libimcv: migrate pts to tpm_tss
This commit is contained in:
@@ -16,6 +16,9 @@ libimcv.plugins.imc-attestation.nonce_len = 20
|
|||||||
libimcv.plugins.imc-attestation.use_quote2 = yes
|
libimcv.plugins.imc-attestation.use_quote2 = yes
|
||||||
Use Quote2 AIK signature instead of Quote signature.
|
Use Quote2 AIK signature instead of Quote signature.
|
||||||
|
|
||||||
|
libimcv.plugins.imc-attestation.use_version_info = no
|
||||||
|
Version Info is included in Quote2 signature.
|
||||||
|
|
||||||
libimcv.plugins.imc-attestation.pcr_info = no
|
libimcv.plugins.imc-attestation.pcr_info = no
|
||||||
Whether to send pcr_before and pcr_after info.
|
Whether to send pcr_before and pcr_after info.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1624,7 +1624,7 @@ AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue)
|
|||||||
AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
|
AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue)
|
||||||
AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
|
AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue)
|
||||||
AM_CONDITIONAL(USE_LIBPTTLS, test x$tnc_tnccs = xtrue)
|
AM_CONDITIONAL(USE_LIBPTTLS, test x$tnc_tnccs = xtrue)
|
||||||
AM_CONDITIONAL(USE_LIBTPMTSS, test x$tss_trousers = xtrue -o x$tss_tss2 = xtrue -o x$aikgen = xtrue -o x$aikpub2 = xtrue )
|
AM_CONDITIONAL(USE_LIBTPMTSS, test x$tss_trousers = xtrue -o x$tss_tss2 = xtrue -o x$aikgen = xtrue -o x$aikpub2 = xtrue -o x$imcv = xtrue)
|
||||||
AM_CONDITIONAL(USE_FILE_CONFIG, test x$stroke = xtrue)
|
AM_CONDITIONAL(USE_FILE_CONFIG, test x$stroke = xtrue)
|
||||||
AM_CONDITIONAL(USE_IPSEC_SCRIPT, test x$stroke = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue)
|
AM_CONDITIONAL(USE_IPSEC_SCRIPT, test x$stroke = xtrue -o x$scepclient = xtrue -o x$conftest = xtrue)
|
||||||
AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap)
|
AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
-I$(top_srcdir)/src/libstrongswan \
|
-I$(top_srcdir)/src/libstrongswan \
|
||||||
-I$(top_srcdir)/src/libtncif \
|
-I$(top_srcdir)/src/libtncif \
|
||||||
|
-I$(top_srcdir)/src/libtpmtss \
|
||||||
-DIPSEC_SCRIPT=\"${ipsec_script}\"
|
-DIPSEC_SCRIPT=\"${ipsec_script}\"
|
||||||
|
|
||||||
ipseclib_LTLIBRARIES = libimcv.la
|
ipseclib_LTLIBRARIES = libimcv.la
|
||||||
@@ -10,11 +11,8 @@ libimcv_la_LDFLAGS = \
|
|||||||
|
|
||||||
libimcv_la_LIBADD = \
|
libimcv_la_LIBADD = \
|
||||||
$(top_builddir)/src/libstrongswan/libstrongswan.la \
|
$(top_builddir)/src/libstrongswan/libstrongswan.la \
|
||||||
$(top_builddir)/src/libtncif/libtncif.la
|
$(top_builddir)/src/libtncif/libtncif.la \
|
||||||
|
$(top_builddir)/src/libtpmtss/libtpmtss.la
|
||||||
if USE_TROUSERS
|
|
||||||
libimcv_la_LIBADD += -ltspi
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_WINDOWS
|
if USE_WINDOWS
|
||||||
libimcv_la_LIBADD += -lws2_32
|
libimcv_la_LIBADD += -lws2_32
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
|
* Copyright (C) 2011-2012 Sansar Choinyambuu
|
||||||
|
* Copyright (C) 2011-2016 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -424,7 +425,7 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
|
|||||||
pts_meas_algorithms_t comp_hash_algorithm;
|
pts_meas_algorithms_t comp_hash_algorithm;
|
||||||
pts_comp_evidence_t *evid;
|
pts_comp_evidence_t *evid;
|
||||||
chunk_t pcr_composite, quote_sig;
|
chunk_t pcr_composite, quote_sig;
|
||||||
bool use_quote2;
|
bool use_quote2, use_version_info;
|
||||||
|
|
||||||
/* Send cached Component Evidence entries */
|
/* Send cached Component Evidence entries */
|
||||||
while (attestation_state->next_evidence(attestation_state, &evid))
|
while (attestation_state->next_evidence(attestation_state, &evid))
|
||||||
@@ -434,16 +435,22 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
use_quote2 = lib->settings->get_bool(lib->settings,
|
use_quote2 = lib->settings->get_bool(lib->settings,
|
||||||
"%s.plugins.imc-attestation.use_quote2", TRUE,
|
"%s.plugins.imc-attestation.use_quote2",
|
||||||
lib->ns);
|
TRUE, lib->ns);
|
||||||
if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, "e_sig))
|
use_version_info = lib->settings->get_bool(lib->settings,
|
||||||
|
"%s.plugins.imc-attestation.use_version_info",
|
||||||
|
FALSE, lib->ns);
|
||||||
|
if (!pts->quote_tpm(pts, use_quote2, use_version_info,
|
||||||
|
&pcr_composite, "e_sig))
|
||||||
{
|
{
|
||||||
DBG1(DBG_IMC, "error occurred during TPM quote operation");
|
DBG1(DBG_IMC, "error occurred during TPM quote operation");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send Simple Evidence Final attribute */
|
/* Send Simple Evidence Final attribute */
|
||||||
flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
|
flags = use_quote2 ? (use_version_info ?
|
||||||
|
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER :
|
||||||
|
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2) :
|
||||||
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
|
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
|
||||||
comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
|
comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
|
||||||
|
|
||||||
|
|||||||
@@ -217,7 +217,12 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
|
|||||||
DBG1(DBG_IMV, "received TCG-PTS error '%N'",
|
DBG1(DBG_IMV, "received TCG-PTS error '%N'",
|
||||||
pts_error_code_names, error_code.type);
|
pts_error_code_names, error_code.type);
|
||||||
DBG1(DBG_IMV, "error information: %B", &msg_info);
|
DBG1(DBG_IMV, "error information: %B", &msg_info);
|
||||||
fatal_error = TRUE;
|
|
||||||
|
/* TPM 2.0 doesn't return TPM Version Information */
|
||||||
|
if (error_code.type != TCG_PTS_TPM_VERS_NOT_SUPPORTED)
|
||||||
|
{
|
||||||
|
fatal_error = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ METHOD(pts_component_t, measure, status_t,
|
|||||||
extended_pcr = PCR_DEBUG;
|
extended_pcr = PCR_DEBUG;
|
||||||
time(&measurement_time);
|
time(&measurement_time);
|
||||||
|
|
||||||
if (!pts->read_pcr(pts, extended_pcr, &pcr_after))
|
if (!pts->read_pcr(pts, extended_pcr, &pcr_after, HASH_SHA1))
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr);
|
DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
|
|||||||
+147
-449
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2012 Sansar Choinyambuu
|
* Copyright (C) 2011-2012 Sansar Choinyambuu
|
||||||
* Copyright (C) 2012-2014 Andreas Steffen
|
* Copyright (C) 2012-2016 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -21,21 +21,8 @@
|
|||||||
#include <bio/bio_writer.h>
|
#include <bio/bio_writer.h>
|
||||||
#include <bio/bio_reader.h>
|
#include <bio/bio_reader.h>
|
||||||
|
|
||||||
#ifdef TSS_TROUSERS
|
#include <tpm_tss.h>
|
||||||
#ifdef _BASETSD_H_
|
#include <tpm_tss_trousers.h>
|
||||||
/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */
|
|
||||||
# define _BASETSD_H
|
|
||||||
#endif
|
|
||||||
#include <trousers/tss.h>
|
|
||||||
#include <trousers/trousers.h>
|
|
||||||
#else
|
|
||||||
#ifndef TPM_TAG_QUOTE_INFO2
|
|
||||||
#define TPM_TAG_QUOTE_INFO2 0x0036
|
|
||||||
#endif
|
|
||||||
#ifndef TPM_LOC_ZERO
|
|
||||||
#define TPM_LOC_ZERO 0x01
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -43,6 +30,13 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifndef TPM_TAG_QUOTE_INFO2
|
||||||
|
#define TPM_TAG_QUOTE_INFO2 0x0036
|
||||||
|
#endif
|
||||||
|
#ifndef TPM_LOC_ZERO
|
||||||
|
#define TPM_LOC_ZERO 0x01
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct private_pts_t private_pts_t;
|
typedef struct private_pts_t private_pts_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,9 +96,9 @@ struct private_pts_t {
|
|||||||
bool is_imc;
|
bool is_imc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do we have an activated TPM
|
* Active TPM
|
||||||
*/
|
*/
|
||||||
bool has_tpm;
|
tpm_tss_t *tpm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains a TPM_CAP_VERSION_INFO struct
|
* Contains a TPM_CAP_VERSION_INFO struct
|
||||||
@@ -112,14 +106,14 @@ struct private_pts_t {
|
|||||||
chunk_t tpm_version_info;
|
chunk_t tpm_version_info;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains TSS Blob structure for AIK
|
* AIK object handle
|
||||||
*/
|
*/
|
||||||
chunk_t aik_blob;
|
uint32_t aik_handle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains a Attestation Identity Key or Certificate
|
* Contains an Attestation Identity Key Certificate
|
||||||
*/
|
*/
|
||||||
certificate_t *aik;
|
certificate_t *aik_cert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primary key referening AIK in database
|
* Primary key referening AIK in database
|
||||||
@@ -191,7 +185,6 @@ METHOD(pts_t, set_dh_hash_algorithm, void,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
METHOD(pts_t, create_dh_nonce, bool,
|
METHOD(pts_t, create_dh_nonce, bool,
|
||||||
private_pts_t *this, pts_dh_group_t group, int nonce_len)
|
private_pts_t *this, pts_dh_group_t group, int nonce_len)
|
||||||
{
|
{
|
||||||
@@ -306,41 +299,6 @@ METHOD(pts_t, calculate_secret, bool,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TSS_TROUSERS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print TPM 1.2 Version Info
|
|
||||||
*/
|
|
||||||
static void print_tpm_version_info(private_pts_t *this)
|
|
||||||
{
|
|
||||||
TPM_CAP_VERSION_INFO *info;
|
|
||||||
|
|
||||||
info = (TPM_CAP_VERSION_INFO*)this->tpm_version_info.ptr;
|
|
||||||
|
|
||||||
if (this->tpm_version_info.len >=
|
|
||||||
sizeof(*info) - sizeof(info->vendorSpecific))
|
|
||||||
{
|
|
||||||
DBG2(DBG_PTS, "TPM Version Info: Chip Version: %u.%u.%u.%u, "
|
|
||||||
"Spec Level: %u, Errata Rev: %u, Vendor ID: %.4s",
|
|
||||||
info->version.major, info->version.minor,
|
|
||||||
info->version.revMajor, info->version.revMinor,
|
|
||||||
untoh16(&info->specLevel), info->errataRev, info->tpmVendorID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "could not parse tpm version info");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static void print_tpm_version_info(private_pts_t *this)
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "unknown TPM version: no TSS implementation available");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* TSS_TROUSERS */
|
|
||||||
|
|
||||||
METHOD(pts_t, get_platform_id, int,
|
METHOD(pts_t, get_platform_id, int,
|
||||||
private_pts_t *this)
|
private_pts_t *this)
|
||||||
{
|
{
|
||||||
@@ -356,104 +314,135 @@ METHOD(pts_t, set_platform_id, void,
|
|||||||
METHOD(pts_t, get_tpm_version_info, bool,
|
METHOD(pts_t, get_tpm_version_info, bool,
|
||||||
private_pts_t *this, chunk_t *info)
|
private_pts_t *this, chunk_t *info)
|
||||||
{
|
{
|
||||||
if (!this->has_tpm)
|
*info = this->tpm ? this->tpm->get_version_info(this->tpm) :
|
||||||
{
|
this->tpm_version_info;
|
||||||
return FALSE;
|
return info->len > 0;
|
||||||
}
|
|
||||||
*info = this->tpm_version_info;
|
|
||||||
print_tpm_version_info(this);
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(pts_t, set_tpm_version_info, void,
|
METHOD(pts_t, set_tpm_version_info, void,
|
||||||
private_pts_t *this, chunk_t info)
|
private_pts_t *this, chunk_t info)
|
||||||
{
|
{
|
||||||
this->tpm_version_info = chunk_clone(info);
|
this->tpm_version_info = chunk_clone(info);
|
||||||
print_tpm_version_info(this);
|
/* print_tpm_version_info(this); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute)
|
* Load an AIK handle and an optional AIK certificate and
|
||||||
*/
|
* in the case of a TPM 1.2 an AIK private key blob plus matching public key,
|
||||||
static void load_aik_blob(private_pts_t *this)
|
|
||||||
{
|
|
||||||
char *path;
|
|
||||||
chunk_t *map;
|
|
||||||
|
|
||||||
path = lib->settings->get_str(lib->settings,
|
|
||||||
"%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
|
|
||||||
if (path)
|
|
||||||
{
|
|
||||||
map = chunk_map(path, FALSE);
|
|
||||||
if (map)
|
|
||||||
{
|
|
||||||
DBG2(DBG_PTS, "loaded AIK Blob from '%s'", path);
|
|
||||||
DBG3(DBG_PTS, "AIK Blob: %B", map);
|
|
||||||
this->aik_blob = chunk_clone(*map);
|
|
||||||
chunk_unmap(map);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
|
|
||||||
path, strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "AIK Blob is not available");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load an AIK certificate or public key
|
|
||||||
* the certificate having precedence over the public key if both are present
|
* the certificate having precedence over the public key if both are present
|
||||||
*/
|
*/
|
||||||
static void load_aik(private_pts_t *this)
|
static void load_aik(private_pts_t *this)
|
||||||
{
|
{
|
||||||
char *cert_path, *key_path;
|
char *handle_str, *cert_path, *key_path, *blob_path;
|
||||||
|
chunk_t aik_pubkey = chunk_empty;
|
||||||
|
|
||||||
|
handle_str = lib->settings->get_str(lib->settings,
|
||||||
|
"%s.plugins.imc-attestation.aik_handle", NULL, lib->ns);
|
||||||
cert_path = lib->settings->get_str(lib->settings,
|
cert_path = lib->settings->get_str(lib->settings,
|
||||||
"%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
|
"%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
|
||||||
key_path = lib->settings->get_str(lib->settings,
|
key_path = lib->settings->get_str(lib->settings,
|
||||||
"%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
|
"%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
|
||||||
|
blob_path = lib->settings->get_str(lib->settings,
|
||||||
|
"%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
|
||||||
|
|
||||||
|
if (handle_str)
|
||||||
|
{
|
||||||
|
this->aik_handle = strtoll(handle_str, NULL, 16);
|
||||||
|
}
|
||||||
if (cert_path)
|
if (cert_path)
|
||||||
{
|
{
|
||||||
this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
||||||
CERT_X509, BUILD_FROM_FILE,
|
CERT_X509, BUILD_FROM_FILE,
|
||||||
cert_path, BUILD_END);
|
cert_path, BUILD_END);
|
||||||
if (this->aik)
|
if (this->aik_cert)
|
||||||
{
|
{
|
||||||
DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
|
DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key_path)
|
|
||||||
{
|
|
||||||
this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
|
||||||
CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE,
|
|
||||||
key_path, BUILD_END);
|
|
||||||
if (this->aik)
|
|
||||||
{
|
|
||||||
DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
|
if (this->tpm->get_version(this->tpm) == TPM_VERSION_1_2)
|
||||||
|
{
|
||||||
|
tpm_tss_trousers_t *tpm_12;
|
||||||
|
chunk_t aik_blob = chunk_empty;
|
||||||
|
chunk_t *map;
|
||||||
|
|
||||||
|
/* get AIK private key blob */
|
||||||
|
if (blob_path)
|
||||||
|
{
|
||||||
|
map = chunk_map(blob_path, FALSE);
|
||||||
|
if (map)
|
||||||
|
{
|
||||||
|
DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
|
||||||
|
DBG3(DBG_PTS, "AIK Blob: %B", map);
|
||||||
|
aik_blob = chunk_clone(*map);
|
||||||
|
chunk_unmap(map);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
|
||||||
|
blob_path, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "AIK Blob is not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get AIK public key */
|
||||||
|
if (key_path)
|
||||||
|
{
|
||||||
|
map = chunk_map(key_path, FALSE);
|
||||||
|
if (map)
|
||||||
|
{
|
||||||
|
DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path);
|
||||||
|
aik_pubkey = chunk_clone(*map);
|
||||||
|
chunk_unmap(map);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "unable to map AIK public key file '%s': %s",
|
||||||
|
key_path, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "AIK public key is not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load AIK item into TPM 1.2 object */
|
||||||
|
tpm_12 = (tpm_tss_trousers_t *)this->tpm;
|
||||||
|
tpm_12->load_aik(tpm_12, aik_blob, aik_pubkey, this->aik_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no signed X.509 AIK certificate is available use public key instead */
|
||||||
|
if (!this->aik_cert)
|
||||||
|
{
|
||||||
|
aik_pubkey = this->tpm->get_public(this->tpm, this->aik_handle);
|
||||||
|
if (aik_pubkey.len > 0)
|
||||||
|
{
|
||||||
|
this->aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
||||||
|
CERT_TRUSTED_PUBKEY, BUILD_BLOB,
|
||||||
|
aik_pubkey, BUILD_END);
|
||||||
|
chunk_free(&aik_pubkey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "neither AIK certificate nor public key is available");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(pts_t, get_aik, certificate_t*,
|
METHOD(pts_t, get_aik, certificate_t*,
|
||||||
private_pts_t *this)
|
private_pts_t *this)
|
||||||
{
|
{
|
||||||
return this->aik;
|
return this->aik_cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(pts_t, set_aik, void,
|
METHOD(pts_t, set_aik, void,
|
||||||
private_pts_t *this, certificate_t *aik, int aik_id)
|
private_pts_t *this, certificate_t *aik, int aik_id)
|
||||||
{
|
{
|
||||||
DESTROY_IF(this->aik);
|
DESTROY_IF(this->aik_cert);
|
||||||
this->aik = aik->get_ref(aik);
|
this->aik_cert = aik->get_ref(aik);
|
||||||
this->aik_id = aik_id;
|
this->aik_id = aik_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,290 +600,61 @@ METHOD(pts_t, get_metadata, pts_file_meta_t*,
|
|||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef TSS_TROUSERS
|
|
||||||
|
|
||||||
METHOD(pts_t, read_pcr, bool,
|
METHOD(pts_t, read_pcr, bool,
|
||||||
private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value)
|
private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
hash_algorithm_t alg)
|
||||||
{
|
{
|
||||||
TSS_HCONTEXT hContext;
|
return this->tpm ? this->tpm->read_pcr(this->tpm, pcr_num, pcr_value, alg)
|
||||||
TSS_HTPM hTPM;
|
: FALSE;
|
||||||
TSS_RESULT result;
|
|
||||||
BYTE *buf;
|
|
||||||
UINT32 len;
|
|
||||||
|
|
||||||
bool success = FALSE;
|
|
||||||
|
|
||||||
result = Tspi_Context_Create(&hContext);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = Tspi_Context_Connect(hContext, NULL);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
result = Tspi_Context_GetTpmObject (hContext, &hTPM);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
result = Tspi_TPM_PcrRead(hTPM, pcr_num, &len, &buf);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
*pcr_value = chunk_clone(chunk_create(buf, len));
|
|
||||||
DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value);
|
|
||||||
success = TRUE;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
|
|
||||||
}
|
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
|
||||||
Tspi_Context_Close(hContext);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(pts_t, extend_pcr, bool,
|
METHOD(pts_t, extend_pcr, bool,
|
||||||
private_pts_t *this, uint32_t pcr_num, chunk_t input, chunk_t *output)
|
private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value, chunk_t data,
|
||||||
|
hash_algorithm_t alg)
|
||||||
{
|
{
|
||||||
TSS_HCONTEXT hContext;
|
if (!this->tpm->extend_pcr(this->tpm, pcr_num, pcr_value, data, alg))
|
||||||
TSS_HTPM hTPM;
|
|
||||||
TSS_RESULT result;
|
|
||||||
uint32_t pcr_length;
|
|
||||||
chunk_t pcr_value = chunk_empty;
|
|
||||||
|
|
||||||
result = Tspi_Context_Create(&hContext);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
|
|
||||||
result);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
result = Tspi_Context_Connect(hContext, NULL);
|
DBG3(DBG_PTS, "PCR %d extended with: %#B", pcr_num, &data);
|
||||||
if (result != TSS_SUCCESS)
|
DBG3(DBG_PTS, "PCR %d after extension: %#B", pcr_num, pcr_value);
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
result = Tspi_Context_GetTpmObject (hContext, &hTPM);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcr_value = chunk_alloc(PTS_PCR_LEN);
|
|
||||||
result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PTS_PCR_LEN, input.ptr,
|
|
||||||
NULL, &pcr_length, &pcr_value.ptr);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
*output = pcr_value;
|
|
||||||
*output = chunk_clone(*output);
|
|
||||||
|
|
||||||
DBG3(DBG_PTS, "PCR %d extended with: %B", pcr_num, &input);
|
|
||||||
DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output);
|
|
||||||
|
|
||||||
chunk_clear(&pcr_value);
|
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
|
||||||
Tspi_Context_Close(hContext);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
err:
|
|
||||||
DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
|
|
||||||
|
|
||||||
chunk_clear(&pcr_value);
|
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
|
||||||
Tspi_Context_Close(hContext);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(pts_t, quote_tpm, bool,
|
METHOD(pts_t, quote_tpm, bool,
|
||||||
private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig)
|
private_pts_t *this, bool use_quote2, bool use_version_info,
|
||||||
|
chunk_t *pcr_comp, chunk_t *quote_sig)
|
||||||
{
|
{
|
||||||
TSS_HCONTEXT hContext;
|
chunk_t pcr_value;
|
||||||
TSS_HTPM hTPM;
|
uint32_t pcr, pcr_sel = 0;
|
||||||
TSS_HKEY hAIK;
|
|
||||||
TSS_HKEY hSRK;
|
|
||||||
TSS_HPOLICY srkUsagePolicy;
|
|
||||||
TSS_UUID SRK_UUID = TSS_UUID_SRK;
|
|
||||||
BYTE secret[] = TSS_WELL_KNOWN_SECRET;
|
|
||||||
TSS_HPCRS hPcrComposite;
|
|
||||||
TSS_VALIDATION valData;
|
|
||||||
TSS_RESULT result;
|
|
||||||
chunk_t quote_info;
|
|
||||||
BYTE* versionInfo;
|
|
||||||
uint32_t versionInfoSize, pcr;
|
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
bool success = FALSE;
|
tpm_quote_mode_t quote_mode;
|
||||||
|
|
||||||
result = Tspi_Context_Create(&hContext);
|
/* select PCRs */
|
||||||
if (result != TSS_SUCCESS)
|
DBG2(DBG_PTS, "PCR values hashed into PCR Composite:");
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
|
|
||||||
result);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
result = Tspi_Context_Connect(hContext, NULL);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
result = Tspi_Context_GetTpmObject (hContext, &hTPM);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve SRK from TPM and set the authentication to well known secret*/
|
|
||||||
result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
|
|
||||||
SRK_UUID, &hSRK);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
|
|
||||||
20, secret);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, this->aik_blob.len,
|
|
||||||
this->aik_blob.ptr, &hAIK);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create PCR composite object */
|
|
||||||
result = use_quote2 ?
|
|
||||||
Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
|
|
||||||
TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) :
|
|
||||||
Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
|
|
||||||
TSS_PCRS_STRUCT_DEFAULT, &hPcrComposite);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select PCRs */
|
|
||||||
enumerator = this->pcrs->create_enumerator(this->pcrs);
|
enumerator = this->pcrs->create_enumerator(this->pcrs);
|
||||||
while (enumerator->enumerate(enumerator, &pcr))
|
while (enumerator->enumerate(enumerator, &pcr))
|
||||||
{
|
{
|
||||||
result = use_quote2 ?
|
if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, HASH_SHA1))
|
||||||
Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
|
|
||||||
TSS_PCRS_DIRECTION_RELEASE) :
|
|
||||||
Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
{
|
||||||
break;
|
DBG2(DBG_PTS, "PCR %2d %#B", pcr, &pcr_value);
|
||||||
}
|
chunk_free(&pcr_value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* add PCR to selection list */
|
||||||
|
pcr_sel |= (1 << pcr);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
if (result != TSS_SUCCESS)
|
quote_mode = use_quote2 ? (use_version_info ? TPM_QUOTE2_VERSION_INFO :
|
||||||
{
|
TPM_QUOTE2) : TPM_QUOTE;
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the Validation Data */
|
|
||||||
valData.ulExternalDataLength = this->secret.len;
|
|
||||||
valData.rgbExternalData = (BYTE *)this->secret.ptr;
|
|
||||||
|
|
||||||
|
|
||||||
/* TPM Quote */
|
/* TPM Quote */
|
||||||
result = use_quote2 ?
|
return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, HASH_SHA1,
|
||||||
Tspi_TPM_Quote2(hTPM, hAIK, FALSE, hPcrComposite, &valData,
|
this->secret, quote_mode, pcr_comp, quote_sig);
|
||||||
&versionInfoSize, &versionInfo):
|
|
||||||
Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set output chunks */
|
|
||||||
*pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
|
|
||||||
|
|
||||||
if (use_quote2)
|
|
||||||
{
|
|
||||||
/* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
|
|
||||||
memcpy(pcr_comp->ptr, valData.rgbData + valData.ulDataLength - HASH_SIZE_SHA1,
|
|
||||||
HASH_SIZE_SHA1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* TPM_Composite_Hash is 8-28th bytes of TPM_Quote_Info structure */
|
|
||||||
memcpy(pcr_comp->ptr, valData.rgbData + 8, HASH_SIZE_SHA1);
|
|
||||||
}
|
|
||||||
DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp);
|
|
||||||
|
|
||||||
quote_info = chunk_create(valData.rgbData, valData.ulDataLength);
|
|
||||||
DBG3(DBG_PTS, "TPM Quote Info: %B","e_info);
|
|
||||||
|
|
||||||
*quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
|
|
||||||
valData.ulValidationDataLength));
|
|
||||||
DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig);
|
|
||||||
|
|
||||||
success = TRUE;
|
|
||||||
|
|
||||||
/* Cleanup */
|
|
||||||
err4:
|
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
|
||||||
|
|
||||||
err3:
|
|
||||||
Tspi_Context_CloseObject(hContext, hPcrComposite);
|
|
||||||
|
|
||||||
err2:
|
|
||||||
Tspi_Context_CloseObject(hContext, hAIK);
|
|
||||||
|
|
||||||
err1:
|
|
||||||
Tspi_Context_Close(hContext);
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* TSS_TROUSERS */
|
|
||||||
|
|
||||||
METHOD(pts_t, read_pcr, bool,
|
|
||||||
private_pts_t *this, uint32_t pcr_num, chunk_t *pcr_value)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
METHOD(pts_t, extend_pcr, bool,
|
|
||||||
private_pts_t *this, uint32_t pcr_num, chunk_t input, chunk_t *output)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
METHOD(pts_t, quote_tpm, bool,
|
|
||||||
private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* TSS_TROUSERS */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TPM_QUOTE_INFO structure:
|
* TPM_QUOTE_INFO structure:
|
||||||
* 4 bytes of version
|
* 4 bytes of version
|
||||||
@@ -910,7 +670,7 @@ METHOD(pts_t, quote_tpm, bool,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
METHOD(pts_t, get_quote_info, bool,
|
METHOD(pts_t, get_quote_info, bool,
|
||||||
private_pts_t *this, bool use_quote2, bool use_ver_info,
|
private_pts_t *this, bool use_quote2, bool use_version_info,
|
||||||
pts_meas_algorithms_t comp_hash_algo,
|
pts_meas_algorithms_t comp_hash_algo,
|
||||||
chunk_t *out_pcr_comp, chunk_t *out_quote_info)
|
chunk_t *out_pcr_comp, chunk_t *out_quote_info)
|
||||||
{
|
{
|
||||||
@@ -930,7 +690,7 @@ METHOD(pts_t, get_quote_info, bool,
|
|||||||
"unable to construct TPM Quote Info");
|
"unable to construct TPM Quote Info");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (use_quote2 && use_ver_info && !this->tpm_version_info.ptr)
|
if (use_quote2 && use_version_info && !this->tpm_version_info.ptr)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "TPM Version Information unavailable, ",
|
DBG1(DBG_PTS, "TPM Version Information unavailable, ",
|
||||||
"unable to construct TPM Quote Info2");
|
"unable to construct TPM Quote Info2");
|
||||||
@@ -999,7 +759,7 @@ METHOD(pts_t, get_quote_info, bool,
|
|||||||
/* PCR Composite Hash */
|
/* PCR Composite Hash */
|
||||||
writer->write_data(writer, hash_pcr_comp);
|
writer->write_data(writer, hash_pcr_comp);
|
||||||
|
|
||||||
if (use_ver_info)
|
if (use_version_info)
|
||||||
{
|
{
|
||||||
/* TPM version Info */
|
/* TPM version Info */
|
||||||
writer->write_data(writer, this->tpm_version_info);
|
writer->write_data(writer, this->tpm_version_info);
|
||||||
@@ -1034,24 +794,24 @@ METHOD(pts_t, get_quote_info, bool,
|
|||||||
METHOD(pts_t, verify_quote_signature, bool,
|
METHOD(pts_t, verify_quote_signature, bool,
|
||||||
private_pts_t *this, chunk_t data, chunk_t signature)
|
private_pts_t *this, chunk_t data, chunk_t signature)
|
||||||
{
|
{
|
||||||
public_key_t *aik_pub_key;
|
public_key_t *aik_pubkey;
|
||||||
|
|
||||||
aik_pub_key = this->aik->get_public_key(this->aik);
|
aik_pubkey = this->aik_cert->get_public_key(this->aik_cert);
|
||||||
if (!aik_pub_key)
|
if (!aik_pubkey)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "failed to get public key from AIK certificate");
|
DBG1(DBG_PTS, "failed to get public key from AIK certificate");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1,
|
if (!aik_pubkey->verify(aik_pubkey, SIGN_RSA_EMSA_PKCS1_SHA1,
|
||||||
data, signature))
|
data, signature))
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
|
DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
|
||||||
DESTROY_IF(aik_pub_key);
|
DESTROY_IF(aik_pubkey);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
aik_pub_key->destroy(aik_pub_key);
|
aik_pubkey->destroy(aik_pubkey);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1064,78 +824,17 @@ METHOD(pts_t, get_pcrs, pts_pcr_t*,
|
|||||||
METHOD(pts_t, destroy, void,
|
METHOD(pts_t, destroy, void,
|
||||||
private_pts_t *this)
|
private_pts_t *this)
|
||||||
{
|
{
|
||||||
|
DESTROY_IF(this->tpm);
|
||||||
DESTROY_IF(this->pcrs);
|
DESTROY_IF(this->pcrs);
|
||||||
DESTROY_IF(this->aik);
|
DESTROY_IF(this->aik_cert);
|
||||||
DESTROY_IF(this->dh);
|
DESTROY_IF(this->dh);
|
||||||
free(this->initiator_nonce.ptr);
|
free(this->initiator_nonce.ptr);
|
||||||
free(this->responder_nonce.ptr);
|
free(this->responder_nonce.ptr);
|
||||||
free(this->secret.ptr);
|
free(this->secret.ptr);
|
||||||
free(this->aik_blob.ptr);
|
|
||||||
free(this->tpm_version_info.ptr);
|
free(this->tpm_version_info.ptr);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef TSS_TROUSERS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for a TPM by querying for TPM Version Info
|
|
||||||
*/
|
|
||||||
static bool has_tpm(private_pts_t *this)
|
|
||||||
{
|
|
||||||
TSS_HCONTEXT hContext;
|
|
||||||
TSS_HTPM hTPM;
|
|
||||||
TSS_RESULT result;
|
|
||||||
uint32_t version_info_len;
|
|
||||||
|
|
||||||
result = Tspi_Context_Create(&hContext);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x",
|
|
||||||
result);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
result = Tspi_Context_Connect(hContext, NULL);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
result = Tspi_Context_GetTpmObject (hContext, &hTPM);
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL,
|
|
||||||
&version_info_len,
|
|
||||||
&this->tpm_version_info.ptr);
|
|
||||||
this->tpm_version_info.len = version_info_len;
|
|
||||||
if (result != TSS_SUCCESS)
|
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
this->tpm_version_info = chunk_clone(this->tpm_version_info);
|
|
||||||
|
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
|
||||||
Tspi_Context_Close(hContext);
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
err:
|
|
||||||
DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
|
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
|
||||||
Tspi_Context_Close(hContext);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* TSS_TROUSERS */
|
|
||||||
|
|
||||||
static bool has_tpm(private_pts_t *this)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* TSS_TROUSERS */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
@@ -1189,12 +888,11 @@ pts_t *pts_create(bool is_imc)
|
|||||||
|
|
||||||
if (is_imc)
|
if (is_imc)
|
||||||
{
|
{
|
||||||
if (has_tpm(this))
|
this->tpm = tpm_tss_probe(TPM_VERSION_ANY);
|
||||||
|
if (this->tpm)
|
||||||
{
|
{
|
||||||
this->has_tpm = TRUE;
|
|
||||||
this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
|
this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
|
||||||
load_aik(this);
|
load_aik(this);
|
||||||
load_aik_blob(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+21
-19
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2011 Sansar Choinyambuu
|
* Copyright (C) 2011 Sansar Choinyambuu
|
||||||
* Copyright (C) 2012-2014 Andreas Steffen
|
* Copyright (C) 2012-2016 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -236,39 +236,41 @@ struct pts_t {
|
|||||||
pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir);
|
pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads given PCR value and returns it
|
* Retrieve the current value of a PCR register in a given PCR bank
|
||||||
* Expects owner secret to be WELL_KNOWN_SECRET
|
|
||||||
*
|
*
|
||||||
* @param pcr_num Number of PCR to read
|
* @param pcr_num PCR number
|
||||||
* @param pcr_value Chunk to save pcr read output
|
* @param pcr_value PCR value returned
|
||||||
* @return NULL in case of TSS error, PCR value otherwise
|
* @param alg hash algorithm, selects PCR bank (TPM 2.0 only)
|
||||||
|
* @return TRUE if PCR value retrieval succeeded
|
||||||
*/
|
*/
|
||||||
bool (*read_pcr)(pts_t *this, uint32_t pcr_num, chunk_t *pcr_value);
|
bool (*read_pcr)(pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
hash_algorithm_t alg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends given PCR with given value
|
* Extend a PCR register in a given PCR bank with a hash value
|
||||||
* Expects owner secret to be WELL_KNOWN_SECRET
|
|
||||||
*
|
*
|
||||||
* @param pcr_num Number of PCR to extend
|
* @param pcr_num PCR number
|
||||||
* @param input Value to extend
|
* @param pcr_value extended PCR value returned
|
||||||
* @param output Chunk to save PCR value after extension
|
* @param hash data to be extended into the PCR
|
||||||
* @return FALSE in case of TSS error, TRUE otherwise
|
* @param alg hash algorithm, selects PCR bank (TPM 2.0 only)
|
||||||
|
* @return TRUE if PCR extension succeeded
|
||||||
*/
|
*/
|
||||||
bool (*extend_pcr)(pts_t *this, uint32_t pcr_num, chunk_t input,
|
bool (*extend_pcr)(pts_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
chunk_t *output);
|
chunk_t data, hash_algorithm_t alg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quote over PCR's
|
* Quote over PCR's
|
||||||
* Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK
|
* Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK
|
||||||
*
|
*
|
||||||
* @param use_quote2 Version of the Quote function to be used
|
* @param use_quote2 Version of the Quote function to be used
|
||||||
|
* @param use_version_info Version info is concatenated to TPM_QUOTE_INFO2
|
||||||
* @param pcr_comp Chunk to save PCR composite structure
|
* @param pcr_comp Chunk to save PCR composite structure
|
||||||
* @param quote_sig Chunk to save quote operation output
|
* @param quote_sig Chunk to save quote operation output
|
||||||
* without external data (anti-replay protection)
|
* without external data (anti-replay protection)
|
||||||
* @return FALSE in case of TSS error, TRUE otherwise
|
* @return FALSE in case of TSS error, TRUE otherwise
|
||||||
*/
|
*/
|
||||||
bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp,
|
bool (*quote_tpm)(pts_t *this, bool use_quote2, bool use_version_info,
|
||||||
chunk_t *quote_sig);
|
chunk_t *pcr_comp, chunk_t *quote_sig);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the shadow PCR set
|
* Get the shadow PCR set
|
||||||
@@ -281,13 +283,13 @@ struct pts_t {
|
|||||||
* Constructs and returns TPM Quote Info structure expected from IMC
|
* Constructs and returns TPM Quote Info structure expected from IMC
|
||||||
*
|
*
|
||||||
* @param use_quote2 Version of the TPM_QUOTE_INFO to be constructed
|
* @param use_quote2 Version of the TPM_QUOTE_INFO to be constructed
|
||||||
* @param use_ver_info Version info is concatenated to TPM_QUOTE_INFO2
|
* @param use_version_info Version info is concatenated to TPM_QUOTE_INFO2
|
||||||
* @param comp_hash_algo Composite Hash Algorithm
|
* @param comp_hash_algo Composite Hash Algorithm
|
||||||
* @param pcr_comp Output variable to store PCR Composite
|
* @param pcr_comp Output variable to store PCR Composite
|
||||||
* @param quote_info Output variable to store TPM Quote Info
|
* @param quote_info Output variable to store TPM Quote Info
|
||||||
* @return FALSE in case of any error, TRUE otherwise
|
* @return FALSE in case of any error, TRUE otherwise
|
||||||
*/
|
*/
|
||||||
bool (*get_quote_info)(pts_t *this, bool use_quote2, bool ver_info_included,
|
bool (*get_quote_info)(pts_t *this, bool use_quote2, bool use_version_info,
|
||||||
pts_meas_algorithms_t comp_hash_algo,
|
pts_meas_algorithms_t comp_hash_algo,
|
||||||
chunk_t *pcr_comp, chunk_t *quote_info);
|
chunk_t *pcr_comp, chunk_t *quote_info);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <library.h>
|
#include <library.h>
|
||||||
|
|
||||||
typedef enum tpm_version_t tpm_version_t;
|
typedef enum tpm_version_t tpm_version_t;
|
||||||
|
typedef enum tpm_quote_mode_t tpm_quote_mode_t;
|
||||||
typedef struct tpm_tss_t tpm_tss_t;
|
typedef struct tpm_tss_t tpm_tss_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +36,15 @@ enum tpm_version_t {
|
|||||||
TPM_VERSION_2_0,
|
TPM_VERSION_2_0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TPM Quote Modes
|
||||||
|
*/
|
||||||
|
enum tpm_quote_mode_t {
|
||||||
|
TPM_QUOTE,
|
||||||
|
TPM_QUOTE2,
|
||||||
|
TPM_QUOTE2_VERSION_INFO
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TPM access via TSS public interface
|
* TPM access via TSS public interface
|
||||||
*/
|
*/
|
||||||
@@ -74,6 +84,45 @@ struct tpm_tss_t {
|
|||||||
*/
|
*/
|
||||||
chunk_t (*get_public)(tpm_tss_t *this, uint32_t handle);
|
chunk_t (*get_public)(tpm_tss_t *this, uint32_t handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the current value of a PCR register in a given PCR bank
|
||||||
|
*
|
||||||
|
* @param pcr_num PCR number
|
||||||
|
* @param pcr_value PCR value returned
|
||||||
|
* @param alg hash algorithm, selects PCR bank (TPM 2.0 only)
|
||||||
|
* @return TRUE if PCR value retrieval succeeded
|
||||||
|
*/
|
||||||
|
bool (*read_pcr)(tpm_tss_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
hash_algorithm_t alg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend a PCR register in a given PCR bank with a hash value
|
||||||
|
*
|
||||||
|
* @param pcr_num PCR number
|
||||||
|
* @param pcr_value extended PCR value returned
|
||||||
|
* @param hash data to be extended into the PCR
|
||||||
|
* @param alg hash algorithm, selects PCR bank (TPM 2.0 only)
|
||||||
|
* @return TRUE if PCR extension succeeded
|
||||||
|
*/
|
||||||
|
bool (*extend_pcr)(tpm_tss_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
chunk_t data, hash_algorithm_t alg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do a quote signature over a selection of PCR registers
|
||||||
|
*
|
||||||
|
* @param aik_handle object handle of AIK to be used for quote signature
|
||||||
|
* @param pcr_sel selection of PCR registers
|
||||||
|
* @param alg hash algorithm to be used for quote signature
|
||||||
|
* @param data additional data to be hashed into the quote
|
||||||
|
* @param mode define current and legacy TPM quote modes
|
||||||
|
* @param pcr_comp returns hash of PCR composite
|
||||||
|
* @param sig returns quote signature
|
||||||
|
* @return TRUE if quote signature succeeded
|
||||||
|
*/
|
||||||
|
bool (*quote)(tpm_tss_t *this, uint32_t aik_handle, uint32_t pcr_sel,
|
||||||
|
hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode,
|
||||||
|
chunk_t *pcr_comp, chunk_t *quote_sig);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a tpm_tss_t.
|
* Destroy a tpm_tss_t.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -27,15 +27,24 @@
|
|||||||
|
|
||||||
#ifdef TSS_TROUSERS
|
#ifdef TSS_TROUSERS
|
||||||
|
|
||||||
|
#ifdef _BASETSD_H_
|
||||||
|
/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */
|
||||||
|
# define _BASETSD_H
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <trousers/tss.h>
|
#include <trousers/tss.h>
|
||||||
#include <trousers/trousers.h>
|
#include <trousers/trousers.h>
|
||||||
|
|
||||||
#define LABEL "TPM 1.2 -"
|
#define LABEL "TPM 1.2 -"
|
||||||
|
|
||||||
/* size in bytes of a TSS AIK public key blob */
|
/* size in bytes of a TSS AIK public key blob */
|
||||||
#define AIK_PUBKEY_BLOB_SIZE 284
|
#define AIK_PUBKEY_BLOB_SIZE 284
|
||||||
|
|
||||||
|
/* maximum number of PCR registers */
|
||||||
|
#define PCR_NUM_MAX 24
|
||||||
|
|
||||||
typedef struct private_tpm_tss_trousers_t private_tpm_tss_trousers_t;
|
typedef struct private_tpm_tss_trousers_t private_tpm_tss_trousers_t;
|
||||||
|
typedef struct aik_t aik_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data of an tpm_tss_trousers_t object.
|
* Private data of an tpm_tss_trousers_t object.
|
||||||
@@ -45,20 +54,48 @@ struct private_tpm_tss_trousers_t {
|
|||||||
/**
|
/**
|
||||||
* Public tpm_tss_trousers_t interface.
|
* Public tpm_tss_trousers_t interface.
|
||||||
*/
|
*/
|
||||||
tpm_tss_t public;
|
tpm_tss_trousers_t interface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TSS context
|
* TSS context
|
||||||
*/
|
*/
|
||||||
TSS_HCONTEXT hContext;
|
TSS_HCONTEXT hContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TPM handle
|
||||||
|
*/
|
||||||
|
TSS_HTPM hTPM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TPM version info
|
* TPM version info
|
||||||
*/
|
*/
|
||||||
chunk_t version_info;
|
chunk_t version_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of AIKs retrievable by an object handle
|
||||||
|
*/
|
||||||
|
linked_list_t *aik_list;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct aik_t {
|
||||||
|
/** AIK object handle */
|
||||||
|
uint32_t handle;
|
||||||
|
|
||||||
|
/** AIK private key blob */
|
||||||
|
chunk_t blob;
|
||||||
|
|
||||||
|
/** AIK public key */
|
||||||
|
chunk_t pubkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void free_aik(aik_t *this)
|
||||||
|
{
|
||||||
|
free(this->blob.ptr);
|
||||||
|
free(this->pubkey.ptr);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize TSS context
|
* Initialize TSS context
|
||||||
*
|
*
|
||||||
@@ -86,7 +123,6 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
|
|||||||
uint8_t *version_ptr;
|
uint8_t *version_ptr;
|
||||||
uint32_t version_len;
|
uint32_t version_len;
|
||||||
|
|
||||||
TSS_HTPM hTPM;
|
|
||||||
TSS_RESULT result;
|
TSS_RESULT result;
|
||||||
TPM_CAP_VERSION_INFO *info;
|
TPM_CAP_VERSION_INFO *info;
|
||||||
|
|
||||||
@@ -106,7 +142,7 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Tspi_Context_GetTpmObject (this->hContext, &hTPM);
|
result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "%s could not get TPM object: 0x%x",
|
DBG1(DBG_PTS, "%s could not get TPM object: 0x%x",
|
||||||
@@ -114,8 +150,8 @@ static bool initialize_context(private_tpm_tss_trousers_t *this)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL,
|
result = Tspi_TPM_GetCapability(this->hTPM, TSS_TPMCAP_VERSION_VAL, 0,
|
||||||
&version_len, &version_ptr);
|
NULL, &version_len, &version_ptr);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "%s Tspi_TPM_GetCapability failed: 0x%x",
|
DBG1(DBG_PTS, "%s Tspi_TPM_GetCapability failed: 0x%x",
|
||||||
@@ -168,7 +204,6 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
|||||||
chunk_t aik_exponent;
|
chunk_t aik_exponent;
|
||||||
|
|
||||||
TSS_RESULT result;
|
TSS_RESULT result;
|
||||||
TSS_HTPM hTPM;
|
|
||||||
TSS_HKEY hSRK;
|
TSS_HKEY hSRK;
|
||||||
TSS_HKEY hPCAKey;
|
TSS_HKEY hPCAKey;
|
||||||
TSS_HPOLICY hSrkPolicy;
|
TSS_HPOLICY hSrkPolicy;
|
||||||
@@ -206,14 +241,14 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* get TPM plus TPM policy and set TPM secret */
|
/* get TPM plus TPM policy and set TPM secret */
|
||||||
result = Tspi_Context_GetTpmObject (this->hContext, &hTPM);
|
result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "%s Tspi_Context_GetTpmObject failed: 0x%x",
|
DBG1(DBG_PTS, "%s Tspi_Context_GetTpmObject failed: 0x%x",
|
||||||
LABEL, result);
|
LABEL, result);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
result = Tspi_GetPolicyObject(hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
|
result = Tspi_GetPolicyObject(this->hTPM, TSS_POLICY_USAGE, &hTPMPolicy);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for TPM failed: 0x%x",
|
DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for TPM failed: 0x%x",
|
||||||
@@ -268,7 +303,7 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
|||||||
|
|
||||||
/* generate AIK */
|
/* generate AIK */
|
||||||
DBG1(DBG_LIB, "Generating identity key...");
|
DBG1(DBG_LIB, "Generating identity key...");
|
||||||
result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCAKey, 0, NULL,
|
result = Tspi_TPM_CollateIdentityRequest(this->hTPM, hSRK, hPCAKey, 0, NULL,
|
||||||
hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq);
|
hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
{
|
{
|
||||||
@@ -337,17 +372,240 @@ METHOD(tpm_tss_t, generate_aik, bool,
|
|||||||
METHOD(tpm_tss_t, get_public, chunk_t,
|
METHOD(tpm_tss_t, get_public, chunk_t,
|
||||||
private_tpm_tss_trousers_t *this, uint32_t handle)
|
private_tpm_tss_trousers_t *this, uint32_t handle)
|
||||||
{
|
{
|
||||||
return chunk_empty;
|
enumerator_t *enumerator;
|
||||||
|
chunk_t aik_pubkey = chunk_empty;
|
||||||
|
aik_t *aik;
|
||||||
|
|
||||||
|
enumerator = this->aik_list->create_enumerator(this->aik_list);
|
||||||
|
while (enumerator->enumerate(enumerator, &aik))
|
||||||
|
{
|
||||||
|
if (aik->handle == handle)
|
||||||
|
{
|
||||||
|
aik_pubkey = chunk_clone(aik->pubkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
return aik_pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_t, read_pcr, bool,
|
||||||
|
private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
hash_algorithm_t alg)
|
||||||
|
{
|
||||||
|
TSS_RESULT result;
|
||||||
|
uint8_t *value;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
result = Tspi_TPM_PcrRead(this->hTPM, pcr_num, &len, &value);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_TPM_PcrRead failed: 0x%x", LABEL, result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*pcr_value = chunk_clone(chunk_create(value, len));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_t, extend_pcr, bool,
|
||||||
|
private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
chunk_t data, hash_algorithm_t alg)
|
||||||
|
{
|
||||||
|
TSS_RESULT result;
|
||||||
|
uint32_t pcr_len;
|
||||||
|
uint8_t *pcr_ptr;
|
||||||
|
|
||||||
|
result = Tspi_TPM_PcrExtend(this->hTPM, pcr_num, data.len, data.ptr,
|
||||||
|
NULL, &pcr_len, &pcr_ptr);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_TPM_PcrExtend failed: 0x%x", LABEL, result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*pcr_value = chunk_clone(chunk_create(pcr_ptr, pcr_len));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_t, quote, bool,
|
||||||
|
private_tpm_tss_trousers_t *this, uint32_t aik_handle, uint32_t pcr_sel,
|
||||||
|
hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
|
||||||
|
chunk_t *quote_sig)
|
||||||
|
{
|
||||||
|
TSS_HKEY hAIK;
|
||||||
|
TSS_HKEY hSRK;
|
||||||
|
TSS_HPOLICY srkUsagePolicy;
|
||||||
|
TSS_UUID SRK_UUID = TSS_UUID_SRK;
|
||||||
|
TSS_HPCRS hPcrComposite;
|
||||||
|
TSS_VALIDATION valData;
|
||||||
|
TSS_RESULT result;
|
||||||
|
uint8_t secret[] = TSS_WELL_KNOWN_SECRET;
|
||||||
|
uint8_t *version_info, *comp_hash;
|
||||||
|
uint32_t version_info_size, pcr;
|
||||||
|
aik_t *aik;
|
||||||
|
chunk_t aik_blob = chunk_empty;
|
||||||
|
chunk_t quote_info;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
bool success = FALSE;
|
||||||
|
|
||||||
|
/* Retrieve SRK from TPM and set the authentication to well known secret*/
|
||||||
|
result = Tspi_Context_LoadKeyByUUID(this->hContext, TSS_PS_TYPE_SYSTEM,
|
||||||
|
SRK_UUID, &hSRK);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByUUID for SRK failed: 0x%x",
|
||||||
|
LABEL, result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for SRK failed: 0x%x",
|
||||||
|
LABEL, result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1,
|
||||||
|
20, secret);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_Policy_SetSecret for SRK failed: 0x%x",
|
||||||
|
LABEL, result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve AIK using its handle and load private key into TPM 1.2 */
|
||||||
|
enumerator = this->aik_list->create_enumerator(this->aik_list);
|
||||||
|
while (enumerator->enumerate(enumerator, &aik))
|
||||||
|
{
|
||||||
|
if (aik->handle == aik_handle)
|
||||||
|
{
|
||||||
|
aik_blob = aik->blob;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
if (aik_blob.len == 0)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s AIK private key for handle 0x%80x not found", LABEL);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
result = Tspi_Context_LoadKeyByBlob(this->hContext, hSRK, aik_blob.len,
|
||||||
|
aik_blob.ptr, &hAIK);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByBlob for AIK failed: 0x%x",
|
||||||
|
LABEL, result);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create PCR composite object */
|
||||||
|
result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_PCRS,
|
||||||
|
(mode == TPM_QUOTE) ? TSS_PCRS_STRUCT_INFO :
|
||||||
|
TSS_PCRS_STRUCT_INFO_SHORT,
|
||||||
|
&hPcrComposite);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for pcrComposite failed: "
|
||||||
|
"0x%x", LABEL, result);
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select PCRs */
|
||||||
|
for (pcr = 0; pcr < PCR_NUM_MAX; pcr++)
|
||||||
|
{
|
||||||
|
if (pcr_sel & (1 << pcr))
|
||||||
|
{
|
||||||
|
result = (mode == TPM_QUOTE) ?
|
||||||
|
Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr) :
|
||||||
|
Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
|
||||||
|
TSS_PCRS_DIRECTION_RELEASE);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_PcrComposite_SelectPcrIndex failed: "
|
||||||
|
"0x%x", LABEL, result);
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the Validation Data */
|
||||||
|
valData.ulExternalDataLength = data.len;
|
||||||
|
valData.rgbExternalData = data.ptr;
|
||||||
|
|
||||||
|
/* TPM Quote */
|
||||||
|
result = (mode == TPM_QUOTE) ?
|
||||||
|
Tspi_TPM_Quote (this->hTPM, hAIK, hPcrComposite, &valData) :
|
||||||
|
Tspi_TPM_Quote2(this->hTPM, hAIK, mode == TPM_QUOTE2_VERSION_INFO,
|
||||||
|
hPcrComposite, &valData, &version_info_size,
|
||||||
|
&version_info);
|
||||||
|
if (result != TSS_SUCCESS)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "%s Tspi_TPM_Quote%s failed: 0x%x", LABEL,
|
||||||
|
(mode == TPM_QUOTE) ? "" : "2", result);
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract TPM_Composite_Hash */
|
||||||
|
*pcr_comp = chunk_alloc(HASH_SIZE_SHA1);
|
||||||
|
|
||||||
|
if (mode == TPM_QUOTE)
|
||||||
|
{
|
||||||
|
/* TPM_Composite_Hash starts at byte 8 of TPM_Quote_Info structure */
|
||||||
|
comp_hash = valData.rgbData + 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */
|
||||||
|
comp_hash = valData.rgbData + valData.ulDataLength - version_info_size -
|
||||||
|
HASH_SIZE_SHA1;
|
||||||
|
}
|
||||||
|
memcpy(pcr_comp->ptr, comp_hash, HASH_SIZE_SHA1);
|
||||||
|
DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp);
|
||||||
|
|
||||||
|
quote_info = chunk_create(valData.rgbData, valData.ulDataLength);
|
||||||
|
DBG3(DBG_PTS, "TPM Quote Info: %B","e_info);
|
||||||
|
|
||||||
|
*quote_sig = chunk_clone(chunk_create(valData.rgbValidationData,
|
||||||
|
valData.ulValidationDataLength));
|
||||||
|
DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig);
|
||||||
|
|
||||||
|
success = TRUE;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
Tspi_Context_CloseObject(this->hContext, hPcrComposite);
|
||||||
|
err1:
|
||||||
|
Tspi_Context_CloseObject(this->hContext, hAIK);
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(tpm_tss_t, destroy, void,
|
METHOD(tpm_tss_t, destroy, void,
|
||||||
private_tpm_tss_trousers_t *this)
|
private_tpm_tss_trousers_t *this)
|
||||||
{
|
{
|
||||||
finalize_context(this);
|
finalize_context(this);
|
||||||
|
this->aik_list->destroy_function(this->aik_list, (void*)free_aik);
|
||||||
free(this->version_info.ptr);
|
free(this->version_info.ptr);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_trousers_t, load_aik, void,
|
||||||
|
private_tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey,
|
||||||
|
uint32_t handle)
|
||||||
|
{
|
||||||
|
aik_t *item;
|
||||||
|
|
||||||
|
INIT(item,
|
||||||
|
.handle = handle,
|
||||||
|
.blob = blob,
|
||||||
|
.pubkey = pubkey,
|
||||||
|
);
|
||||||
|
|
||||||
|
this->aik_list->insert_last(this->aik_list, item);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
@@ -357,13 +615,20 @@ tpm_tss_t *tpm_tss_trousers_create()
|
|||||||
bool available;
|
bool available;
|
||||||
|
|
||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.interface = {
|
||||||
.get_version = _get_version,
|
.public = {
|
||||||
.get_version_info = _get_version_info,
|
.get_version = _get_version,
|
||||||
.generate_aik = _generate_aik,
|
.get_version_info = _get_version_info,
|
||||||
.get_public = _get_public,
|
.generate_aik = _generate_aik,
|
||||||
.destroy = _destroy,
|
.get_public = _get_public,
|
||||||
|
.read_pcr = _read_pcr,
|
||||||
|
.quote = _quote,
|
||||||
|
.extend_pcr = _extend_pcr,
|
||||||
|
.destroy = _destroy,
|
||||||
|
},
|
||||||
|
.load_aik = _load_aik,
|
||||||
},
|
},
|
||||||
|
.aik_list = linked_list_create(),
|
||||||
);
|
);
|
||||||
|
|
||||||
available = initialize_context(this);
|
available = initialize_context(this);
|
||||||
@@ -374,7 +639,7 @@ tpm_tss_t *tpm_tss_trousers_create()
|
|||||||
destroy(this);
|
destroy(this);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &this->public;
|
return &this->interface.public;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* TSS_TROUSERS */
|
#else /* TSS_TROUSERS */
|
||||||
|
|||||||
@@ -23,6 +23,27 @@
|
|||||||
|
|
||||||
#include "tpm_tss.h"
|
#include "tpm_tss.h"
|
||||||
|
|
||||||
|
typedef struct tpm_tss_trousers_t tpm_tss_trousers_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TPM 1.2 access via TrouSerS public interface
|
||||||
|
*/
|
||||||
|
struct tpm_tss_trousers_t {
|
||||||
|
|
||||||
|
tpm_tss_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load AIK public and private key pair and save it under an object handle
|
||||||
|
*
|
||||||
|
* @param blob encrypted AIK private key
|
||||||
|
* @param pubkey AIK public key
|
||||||
|
* @param handle object handle under which the AIK key is stored
|
||||||
|
*/
|
||||||
|
void (*load_aik)(tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey,
|
||||||
|
uint32_t handle);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a tpm_tss_trousers instance.
|
* Create a tpm_tss_trousers instance.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -335,6 +335,31 @@ METHOD(tpm_tss_t, get_public, chunk_t,
|
|||||||
return aik_pubkey;
|
return aik_pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_t, read_pcr, bool,
|
||||||
|
private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
hash_algorithm_t alg)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_t, extend_pcr, bool,
|
||||||
|
private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
|
||||||
|
chunk_t data, hash_algorithm_t alg)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(tpm_tss_t, quote, bool,
|
||||||
|
private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
|
||||||
|
hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
|
||||||
|
chunk_t *quote_sig)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(tpm_tss_t, destroy, void,
|
METHOD(tpm_tss_t, destroy, void,
|
||||||
private_tpm_tss_tss2_t *this)
|
private_tpm_tss_tss2_t *this)
|
||||||
{
|
{
|
||||||
@@ -356,6 +381,9 @@ tpm_tss_t *tpm_tss_tss2_create()
|
|||||||
.get_version_info = _get_version_info,
|
.get_version_info = _get_version_info,
|
||||||
.generate_aik = _generate_aik,
|
.generate_aik = _generate_aik,
|
||||||
.get_public = _get_public,
|
.get_public = _get_public,
|
||||||
|
.read_pcr = _read_pcr,
|
||||||
|
.extend_pcr = _extend_pcr,
|
||||||
|
.quote = _quote,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user