Implemented Quote Digest constructing function for IMV
Implemented Signature verification function to check TPM Quote Signature Implemented Handling of Simple Evidence Final attribute Fixed bug within tpm_quote function
This commit is contained in:
parent
7037b55ff1
commit
a8be826be4
|
@ -321,8 +321,8 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
/* TODO: Implement BIOS measurement */
|
/* TODO: Implement BIOS measurement */
|
||||||
DBG1(DBG_IMC, "experimental implementation:"
|
DBG1(DBG_IMC, "experimental implementation:"
|
||||||
" Extend TPM with etc/tnc_config file");
|
" Extend TPM with etc/tnc_config file");
|
||||||
|
params.pcr_info_included = TRUE;
|
||||||
params.flags = PTS_SIMPLE_COMP_EVID_FLAG_PCR | PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID;
|
params.flags = PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID;
|
||||||
params.depth = 0;
|
params.depth = 0;
|
||||||
params.vendor_id = PEN_TCG;
|
params.vendor_id = PEN_TCG;
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
params.extended_pcr = EXTEND_PCR;
|
params.extended_pcr = EXTEND_PCR;
|
||||||
params.hash_algorithm = pts->get_meas_algorithm(pts);
|
params.hash_algorithm = pts->get_meas_algorithm(pts);
|
||||||
|
|
||||||
if (!(params.flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR))
|
if (!params.pcr_info_included)
|
||||||
{
|
{
|
||||||
params.transformation = PTS_PCR_TRANSFORM_NO;
|
params.transformation = PTS_PCR_TRANSFORM_NO;
|
||||||
}
|
}
|
||||||
|
@ -464,11 +464,11 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
DESTROY_IF(evidences);
|
DESTROY_IF(evidences);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send Simple Evidence Final attribute */
|
/* Send Simple Evidence Final attribute */
|
||||||
flags = PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO;
|
flags = PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO;
|
||||||
|
|
||||||
attr = tcg_pts_attr_simple_evid_final_create(flags, 0,
|
attr = tcg_pts_attr_simple_evid_final_create(FALSE, flags, 0,
|
||||||
pcr_composite, quote_signature, chunk_empty);
|
pcr_composite, quote_signature, chunk_empty);
|
||||||
attr_list->insert_last(attr_list, attr);
|
attr_list->insert_last(attr_list, attr);
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
case TCG_PTS_SIMPLE_COMP_EVID:
|
case TCG_PTS_SIMPLE_COMP_EVID:
|
||||||
{
|
{
|
||||||
tcg_pts_attr_simple_comp_evid_t *attr_cast;
|
tcg_pts_attr_simple_comp_evid_t *attr_cast;
|
||||||
|
bool pcr_info_inclided;
|
||||||
pts_attr_simple_comp_evid_flag_t flags;
|
pts_attr_simple_comp_evid_flag_t flags;
|
||||||
u_int32_t depth, comp_vendor_id, extended_pcr;
|
u_int32_t depth, comp_vendor_id, extended_pcr;
|
||||||
u_int8_t family, measurement_type;
|
u_int8_t family, measurement_type;
|
||||||
|
@ -188,7 +189,8 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
|
|
||||||
attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
|
attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
|
||||||
attr_info = attr->get_value(attr);
|
attr_info = attr->get_value(attr);
|
||||||
|
|
||||||
|
pcr_info_inclided = attr_cast->is_pcr_info_included(attr_cast);
|
||||||
flags = attr_cast->get_flags(attr_cast);
|
flags = attr_cast->get_flags(attr_cast);
|
||||||
depth = attr_cast->get_sub_component_depth(attr_cast);
|
depth = attr_cast->get_sub_component_depth(attr_cast);
|
||||||
/* TODO: Implement checking of components with its sub-components */
|
/* TODO: Implement checking of components with its sub-components */
|
||||||
|
@ -241,14 +243,14 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
measurement_time = attr_cast->get_measurement_time(attr_cast);
|
measurement_time = attr_cast->get_measurement_time(attr_cast);
|
||||||
|
|
||||||
/* Call getters of optional fields when corresponding flag is set */
|
/* Call getters of optional fields when corresponding flag is set */
|
||||||
if (flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR)
|
if (pcr_info_inclided)
|
||||||
{
|
{
|
||||||
extended_pcr = attr_cast->get_extended_pcr(attr_cast);
|
extended_pcr = attr_cast->get_extended_pcr(attr_cast);
|
||||||
pcr_before = attr_cast->get_pcr_before_value(attr_cast);
|
pcr_before = attr_cast->get_pcr_before_value(attr_cast);
|
||||||
pcr_after = attr_cast->get_pcr_after_value(attr_cast);
|
pcr_after = attr_cast->get_pcr_after_value(attr_cast);
|
||||||
measurement = attr_cast->get_comp_measurement(attr_cast);
|
measurement = attr_cast->get_comp_measurement(attr_cast);
|
||||||
}
|
}
|
||||||
if (!(flags & PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID))
|
if (flags != PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID)
|
||||||
{
|
{
|
||||||
policy_uri = attr_cast->get_policy_uri(attr_cast);
|
policy_uri = attr_cast->get_policy_uri(attr_cast);
|
||||||
}
|
}
|
||||||
|
@ -262,27 +264,62 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||||
{
|
{
|
||||||
tcg_pts_attr_simple_evid_final_t *attr_cast;
|
tcg_pts_attr_simple_evid_final_t *attr_cast;
|
||||||
pts_simple_evid_final_flag_t flags;
|
pts_simple_evid_final_flag_t flags;
|
||||||
chunk_t pcr_comp = chunk_empty;
|
chunk_t pcr_comp;
|
||||||
chunk_t tpm_quote_sign = chunk_empty;
|
chunk_t tpm_quote_sign;
|
||||||
chunk_t evid_sign = chunk_empty;
|
chunk_t evid_sign;
|
||||||
|
bool evid_signature_included;
|
||||||
|
|
||||||
/** TODO: Ignoring Composite Hash Algorithm field
|
/** TODO: Ignoring Composite Hash Algorithm field
|
||||||
* No flag defined which indicates the precense of it
|
* No flag defined which indicates the precense of it
|
||||||
*/
|
*/
|
||||||
attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
|
attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
|
||||||
|
evid_signature_included = attr_cast->is_evid_sign_included(attr_cast);
|
||||||
flags = attr_cast->get_flags(attr_cast);
|
flags = attr_cast->get_flags(attr_cast);
|
||||||
|
|
||||||
if ((flags >> 6) & PTS_SIMPLE_EVID_FINAL_FLAG_NO)
|
if ((flags == PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2) ||
|
||||||
|
(flags == PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2_CAP_VER))
|
||||||
{
|
{
|
||||||
|
DBG1(DBG_IMV, "This version of Attestation IMV can not handle"
|
||||||
|
" TPM Quote Info2 structure");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flags == PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO)
|
||||||
|
{
|
||||||
|
chunk_t digest;
|
||||||
pcr_comp = attr_cast->get_pcr_comp(attr_cast);
|
pcr_comp = attr_cast->get_pcr_comp(attr_cast);
|
||||||
tpm_quote_sign = attr_cast->get_tpm_quote_sign(attr_cast);
|
tpm_quote_sign = attr_cast->get_tpm_quote_sign(attr_cast);
|
||||||
|
|
||||||
/** TODO: Construct PCR Composite */
|
if (!pts->get_quote_digest(pts, &digest))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IMV, "unable to contruct TPM Quote Digest");
|
||||||
|
chunk_clear(&digest);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!pts->verify_quote_signature(pts, digest, tpm_quote_sign))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IMV, "signature verification failed");
|
||||||
|
chunk_clear(&digest);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG2(DBG_IMV, "signature verification succeeded for TPM Quote Info");
|
||||||
|
|
||||||
|
if (!chunk_equals(digest, pcr_comp))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IMV, "calculated TPM Quote Info differs from received");
|
||||||
|
DBG1(DBG_IMV, "calculated: %B", &digest);
|
||||||
|
DBG1(DBG_IMV, "received: %B", &pcr_comp);
|
||||||
|
chunk_clear(&digest);
|
||||||
|
}
|
||||||
|
chunk_clear(&digest);
|
||||||
}
|
}
|
||||||
if (flags & PTS_SIMPLE_EVID_FINAL_FLAG_EVID)
|
|
||||||
|
if (evid_signature_included)
|
||||||
{
|
{
|
||||||
/** TODO: What to do with Evidence Signature */
|
/** TODO: What to do with Evidence Signature */
|
||||||
evid_sign = attr_cast->get_evid_sign(attr_cast);
|
evid_sign = attr_cast->get_evid_sign(attr_cast);
|
||||||
|
DBG1(DBG_IMV, "This version of Attestation IMV can not handle"
|
||||||
|
" Optional Evidence Signature field");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <crypto/hashers/hasher.h>
|
#include <crypto/hashers/hasher.h>
|
||||||
|
#include <bio/bio_writer.h>
|
||||||
|
#include <bio/bio_reader.h>
|
||||||
|
/* for isdigit()*/
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <trousers/tss.h>
|
#include <trousers/tss.h>
|
||||||
#include <trousers/trousers.h>
|
#include <trousers/trousers.h>
|
||||||
|
@ -25,10 +29,6 @@
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <openssl/asn1t.h>
|
|
||||||
#include <openssl/x509.h>
|
|
||||||
#include <openssl/rsa.h>
|
|
||||||
|
|
||||||
#define PTS_BUF_SIZE 4096
|
#define PTS_BUF_SIZE 4096
|
||||||
|
|
||||||
typedef struct private_pts_t private_pts_t;
|
typedef struct private_pts_t private_pts_t;
|
||||||
|
@ -822,10 +822,9 @@ METHOD(pts_t, quote_tpm, bool,
|
||||||
BYTE secret[] = TSS_WELL_KNOWN_SECRET;
|
BYTE secret[] = TSS_WELL_KNOWN_SECRET;
|
||||||
TSS_HPCRS hPcrComposite;
|
TSS_HPCRS hPcrComposite;
|
||||||
TSS_VALIDATION valData;
|
TSS_VALIDATION valData;
|
||||||
TPM_QUOTE_INFO *quoteInfo;
|
|
||||||
u_int32_t i;
|
u_int32_t i;
|
||||||
TSS_RESULT result;
|
TSS_RESULT result;
|
||||||
chunk_t pcr_composite_without_nonce;
|
chunk_t pcr_comp, quote_sign;
|
||||||
|
|
||||||
result = Tspi_Context_Create(&hContext);
|
result = Tspi_Context_Create(&hContext);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
|
@ -897,6 +896,7 @@ METHOD(pts_t, quote_tpm, bool,
|
||||||
valData.ulExternalDataLength = this->secret.len;
|
valData.ulExternalDataLength = this->secret.len;
|
||||||
valData.rgbExternalData = (BYTE *)this->secret.ptr;
|
valData.rgbExternalData = (BYTE *)this->secret.ptr;
|
||||||
|
|
||||||
|
|
||||||
/* TPM Quote */
|
/* TPM Quote */
|
||||||
result = Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData);
|
result = Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData);
|
||||||
if (result != TSS_SUCCESS)
|
if (result != TSS_SUCCESS)
|
||||||
|
@ -904,8 +904,6 @@ METHOD(pts_t, quote_tpm, bool,
|
||||||
goto err4;
|
goto err4;
|
||||||
}
|
}
|
||||||
|
|
||||||
quoteInfo = (TPM_QUOTE_INFO *)valData.rgbData;
|
|
||||||
|
|
||||||
/* Display quote info */
|
/* Display quote info */
|
||||||
DBG3(DBG_PTS, "version:");
|
DBG3(DBG_PTS, "version:");
|
||||||
for(i = 0 ; i < 4 ; i++)
|
for(i = 0 ; i < 4 ; i++)
|
||||||
|
@ -929,17 +927,22 @@ METHOD(pts_t, quote_tpm, bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set output chunks */
|
/* Set output chunks */
|
||||||
pcr_composite_without_nonce = chunk_alloc(
|
pcr_comp = chunk_alloc(valData.ulDataLength - ASSESSMENT_SECRET_LEN);
|
||||||
valData.ulDataLength - ASSESSMENT_SECRET_LEN);
|
memcpy(pcr_comp.ptr, valData.rgbData,
|
||||||
memcpy(pcr_composite_without_nonce.ptr, valData.rgbData,
|
valData.ulDataLength - ASSESSMENT_SECRET_LEN);
|
||||||
valData.ulDataLength - ASSESSMENT_SECRET_LEN);
|
*pcr_composite = pcr_comp;
|
||||||
*pcr_composite = pcr_composite_without_nonce;
|
|
||||||
*pcr_composite = chunk_clone(*pcr_composite);
|
*pcr_composite = chunk_clone(*pcr_composite);
|
||||||
free(pcr_composite_without_nonce.ptr);
|
DBG3(DBG_PTS, "PCR comp: %B",pcr_composite);
|
||||||
|
|
||||||
*quote_signature = chunk_from_thing(valData.rgbValidationData);
|
quote_sign = chunk_alloc(valData.ulValidationDataLength);
|
||||||
|
memcpy(quote_sign.ptr, valData.rgbValidationData,
|
||||||
|
valData.ulValidationDataLength);
|
||||||
|
*quote_signature = quote_sign;
|
||||||
*quote_signature = chunk_clone(*quote_signature);
|
*quote_signature = chunk_clone(*quote_signature);
|
||||||
|
DBG3(DBG_PTS, "Quote sign: %B",quote_signature);
|
||||||
|
|
||||||
|
chunk_clear(&pcr_comp);
|
||||||
|
chunk_clear("e_sign);
|
||||||
Tspi_Context_FreeMemory(hContext, NULL);
|
Tspi_Context_FreeMemory(hContext, NULL);
|
||||||
Tspi_Context_CloseObject(hContext, hPcrComposite);
|
Tspi_Context_CloseObject(hContext, hPcrComposite);
|
||||||
Tspi_Context_CloseObject(hContext, hAIK);
|
Tspi_Context_CloseObject(hContext, hAIK);
|
||||||
|
@ -964,6 +967,254 @@ METHOD(pts_t, quote_tpm, bool,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert from string to byte array (configured PCR values)
|
||||||
|
*/
|
||||||
|
static u_int8_t* pcr_string_to_bytearray(char *str_value)
|
||||||
|
{
|
||||||
|
u_int32_t i;
|
||||||
|
u_int8_t *ret;
|
||||||
|
|
||||||
|
if (strlen(str_value) != PCR_LEN * 2)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "expected PCR value with %d characters, current:%B",
|
||||||
|
PCR_LEN * 2, &str_value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = malloc(PCR_LEN);
|
||||||
|
for (i = 0; i < strlen(str_value)/2; i++)
|
||||||
|
{
|
||||||
|
char c1, c2;
|
||||||
|
u_int8_t d1, d2;
|
||||||
|
|
||||||
|
c1 = str_value[i*2];
|
||||||
|
c2 = str_value[i*2 + 1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert characters to u_int8_t
|
||||||
|
* code taken from http://www.codeguru.com/forum/showthread.php?t=316299
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (isdigit(c1))
|
||||||
|
{
|
||||||
|
d1 = c1 - '0';
|
||||||
|
}
|
||||||
|
else if (c1 >= 'A' && c1 <= 'F')
|
||||||
|
{
|
||||||
|
d1 = c1 - 'A' + 10;
|
||||||
|
}
|
||||||
|
else if (c1 >= 'a' && c1 <= 'f')
|
||||||
|
{
|
||||||
|
d1 = c1 - 'a' + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isdigit(c2))
|
||||||
|
{
|
||||||
|
d2 = c2 - '0';
|
||||||
|
}
|
||||||
|
else if (c2 >= 'A' && c2 <= 'F')
|
||||||
|
{
|
||||||
|
d2 = c2 - 'A' + 10;
|
||||||
|
}
|
||||||
|
else if (c2 >= 'a' && c2 <= 'f')
|
||||||
|
{
|
||||||
|
d2 = c2 - 'a' + 10;
|
||||||
|
}
|
||||||
|
/* save value of two characters in one byte */
|
||||||
|
ret[i] = d1*16 + d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build PCR Entries from the configuration
|
||||||
|
*/
|
||||||
|
static bool load_pcr_entries(linked_list_t **output)
|
||||||
|
{
|
||||||
|
linked_list_t *entries;
|
||||||
|
int i, len;
|
||||||
|
|
||||||
|
entries = linked_list_create();
|
||||||
|
for(i = 0; i < MAX_NUM_PCR; i++)
|
||||||
|
{
|
||||||
|
char *string_pcr_value;
|
||||||
|
pcr_entry_t *entry;
|
||||||
|
len = snprintf(NULL, 0, "%s%d", "libimcv.plugins.imv-attestation.pcr", i);
|
||||||
|
|
||||||
|
char var[len + 1];
|
||||||
|
len = snprintf(var, len + 1, "%s%d", "libimcv.plugins.imv-attestation.pcr", i);
|
||||||
|
string_pcr_value = lib->settings->get_str(lib->settings, var, NULL);
|
||||||
|
|
||||||
|
if (string_pcr_value)
|
||||||
|
{
|
||||||
|
u_int8_t *pcr_value;
|
||||||
|
|
||||||
|
entry = malloc_thing(pcr_entry_t);
|
||||||
|
entry->pcr_number = i;
|
||||||
|
|
||||||
|
pcr_value = pcr_string_to_bytearray(string_pcr_value);
|
||||||
|
entry->pcr_value = chunk_from_thing(pcr_value);
|
||||||
|
entries->insert_last(entries, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries->get_count(entries))
|
||||||
|
{
|
||||||
|
*output = entries;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG1(DBG_PTS, "pcr value(s) not available");
|
||||||
|
DESTROY_IF(entries);
|
||||||
|
*output = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. build a TCPA_PCR_COMPOSITE structure which contains (pcrCompositeBuf)
|
||||||
|
* TCPA_PCR_SELECTION structure (bitmask length network order + length bytes bitmask)
|
||||||
|
* UINT32 (network order) gives the number of bytes following (pcr entries * 20)
|
||||||
|
* TCPA_PCRVALUE[] with the pcr values
|
||||||
|
*
|
||||||
|
* The first two bytes of the message represent the length
|
||||||
|
* of the bitmask that follows. The bitmask represents the
|
||||||
|
* requested PCRs to be quoted.
|
||||||
|
*
|
||||||
|
* TPM Main-Part 2 TPM Structures_v1.2 8.1
|
||||||
|
* The bitmask is in big endian order"
|
||||||
|
*
|
||||||
|
* BYTE 1 BYTE 2 ...
|
||||||
|
* Bit: 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 ...
|
||||||
|
* Pcr: 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 ...
|
||||||
|
*
|
||||||
|
* 2. SHA1(pcrCompositeBuf)
|
||||||
|
*
|
||||||
|
* 3. build a TCPA_QUOTE_INFO structure which contains
|
||||||
|
* 4 bytes of version
|
||||||
|
* 4 bytes 'Q' 'U' 'O' 'T'
|
||||||
|
* 20 byte SHA1 of TCPA_PCR_COMPOSITE
|
||||||
|
* 20 byte nonce
|
||||||
|
*
|
||||||
|
* 4. SHA1(TCPA_QUOTE_INFO) gives quoteDigest
|
||||||
|
*/
|
||||||
|
static chunk_t calculate_quote_digest(private_pts_t *this, linked_list_t *pcr_entries)
|
||||||
|
{
|
||||||
|
enumerator_t *e;
|
||||||
|
pcr_entry_t *pcr_entry;
|
||||||
|
chunk_t digest, pcr_composite, hash_pcr_composite;
|
||||||
|
u_int32_t pcr_composite_len;
|
||||||
|
bio_writer_t *writer;
|
||||||
|
u_int8_t mask_bytes[MAX_NUM_PCR / 8], i;
|
||||||
|
hasher_t *hasher;
|
||||||
|
|
||||||
|
pcr_composite_len = 2 + (MAX_NUM_PCR / 8) + 4 +
|
||||||
|
pcr_entries->get_count(pcr_entries) * PCR_LEN;
|
||||||
|
|
||||||
|
writer = bio_writer_create(pcr_composite_len);
|
||||||
|
/* Lenght of the bist mask field */
|
||||||
|
writer->write_uint16(writer, (MAX_NUM_PCR / 8));
|
||||||
|
/* Bit mask indicating selected PCRs */
|
||||||
|
e = pcr_entries->create_enumerator(pcr_entries);
|
||||||
|
while (e->enumerate(e, &pcr_entry))
|
||||||
|
{
|
||||||
|
u_int32_t index = pcr_entry->pcr_number;
|
||||||
|
mask_bytes[index / 8] |= (1 << (index % 8));
|
||||||
|
}
|
||||||
|
e->destroy(e);
|
||||||
|
for (i = 0; i< (MAX_NUM_PCR / 8) ; i++)
|
||||||
|
{
|
||||||
|
writer->write_uint8(writer, mask_bytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lenght of the pcr entries */
|
||||||
|
writer->write_uint32(writer, pcr_entries->get_count(pcr_entries) * PCR_LEN);
|
||||||
|
/* Actual PCR values */
|
||||||
|
e = pcr_entries->create_enumerator(pcr_entries);
|
||||||
|
while (e->enumerate(e, &pcr_entry))
|
||||||
|
{
|
||||||
|
writer->write_data(writer, pcr_entry->pcr_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pcr_composite = chunk_clone(writer->get_buf(writer));
|
||||||
|
writer->destroy(writer);
|
||||||
|
|
||||||
|
writer = bio_writer_create(TPM_QUOTE_INFO_LEN);
|
||||||
|
/* Version number */
|
||||||
|
writer->write_uint8(writer, 1);
|
||||||
|
writer->write_uint8(writer, 1);
|
||||||
|
writer->write_uint8(writer, 0);
|
||||||
|
writer->write_uint8(writer, 0);
|
||||||
|
|
||||||
|
/* Magic QUOT value, depends on TPM Ordinal */
|
||||||
|
writer->write_uint8(writer, 'Q');
|
||||||
|
writer->write_uint8(writer, 'U');
|
||||||
|
writer->write_uint8(writer, 'O');
|
||||||
|
writer->write_uint8(writer, 'T');
|
||||||
|
|
||||||
|
/* SHA1 hash of PCR Composite Structure */
|
||||||
|
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||||
|
hasher->allocate_hash(hasher, pcr_composite, &hash_pcr_composite);
|
||||||
|
writer->write_data(writer, hash_pcr_composite);
|
||||||
|
|
||||||
|
/* Secret assessment value 20 bytes (nonce) */
|
||||||
|
writer->write_data(writer, this->secret);
|
||||||
|
|
||||||
|
/* TPM Quote Info expected from IMC */
|
||||||
|
digest = chunk_clone(writer->get_buf(writer));
|
||||||
|
|
||||||
|
e->destroy(e);
|
||||||
|
writer->destroy(writer);
|
||||||
|
hasher->destroy(hasher);
|
||||||
|
chunk_clear(&pcr_composite);
|
||||||
|
chunk_clear(&hash_pcr_composite);
|
||||||
|
pcr_entries->destroy(pcr_entries);
|
||||||
|
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(pts_t, get_quote_digest, bool,
|
||||||
|
private_pts_t *this, chunk_t *digest)
|
||||||
|
{
|
||||||
|
linked_list_t *entries;
|
||||||
|
|
||||||
|
if (!load_pcr_entries(&entries))
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "failed to load PCR entries");
|
||||||
|
//DESTROY_IF(entries);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*digest = calculate_quote_digest(this, entries);
|
||||||
|
//DESTROY_IF(entries);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(pts_t, verify_quote_signature, bool,
|
||||||
|
private_pts_t *this, chunk_t data, chunk_t signature)
|
||||||
|
{
|
||||||
|
public_key_t *aik_pub_key;
|
||||||
|
|
||||||
|
aik_pub_key = this->aik->get_public_key(this->aik);
|
||||||
|
|
||||||
|
if (!aik_pub_key)
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "failed to get public key from AIK certificate");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1, data, signature))
|
||||||
|
{
|
||||||
|
DBG1(DBG_PTS, "signature verification failed for TPM Quote Info");
|
||||||
|
aik_pub_key->destroy(aik_pub_key);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
aik_pub_key->destroy(aik_pub_key);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(pts_t, destroy, void,
|
METHOD(pts_t, destroy, void,
|
||||||
private_pts_t *this)
|
private_pts_t *this)
|
||||||
{
|
{
|
||||||
|
@ -971,6 +1222,7 @@ METHOD(pts_t, destroy, void,
|
||||||
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->platform_info);
|
free(this->platform_info);
|
||||||
free(this->aik_blob.ptr);
|
free(this->aik_blob.ptr);
|
||||||
free(this->tpm_version_info.ptr);
|
free(this->tpm_version_info.ptr);
|
||||||
|
@ -1157,6 +1409,8 @@ pts_t *pts_create(bool is_imc)
|
||||||
.read_pcr = _read_pcr,
|
.read_pcr = _read_pcr,
|
||||||
.extend_pcr = _extend_pcr,
|
.extend_pcr = _extend_pcr,
|
||||||
.quote_tpm = _quote_tpm,
|
.quote_tpm = _quote_tpm,
|
||||||
|
.get_quote_digest = _get_quote_digest,
|
||||||
|
.verify_quote_signature = _verify_quote_signature,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.is_imc = is_imc,
|
.is_imc = is_imc,
|
||||||
|
@ -1184,4 +1438,3 @@ pts_t *pts_create(bool is_imc)
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define PTS_H_
|
#define PTS_H_
|
||||||
|
|
||||||
typedef struct pts_t pts_t;
|
typedef struct pts_t pts_t;
|
||||||
|
typedef struct pcr_entry_t pcr_entry_t;
|
||||||
|
|
||||||
#include "pts_error.h"
|
#include "pts_error.h"
|
||||||
#include "pts_proto_caps.h"
|
#include "pts_proto_caps.h"
|
||||||
|
@ -54,6 +55,19 @@ typedef struct pts_t pts_t;
|
||||||
*/
|
*/
|
||||||
#define PCR_LEN 20
|
#define PCR_LEN 20
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lenght of the TPM_QUOTE_INFO structure, TPM Spec 1.2
|
||||||
|
*/
|
||||||
|
#define TPM_QUOTE_INFO_LEN 48
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PCR Entry structure which contains PCR number and current value
|
||||||
|
*/
|
||||||
|
struct pcr_entry_t {
|
||||||
|
u_int32_t pcr_number;
|
||||||
|
chunk_t pcr_value;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class implementing the TCG Platform Trust Service (PTS)
|
* Class implementing the TCG Platform Trust Service (PTS)
|
||||||
*
|
*
|
||||||
|
@ -254,6 +268,23 @@ struct pts_t {
|
||||||
bool (*quote_tpm)(pts_t *this, u_int32_t *pcrs, u_int32_t num_of_pcrs,
|
bool (*quote_tpm)(pts_t *this, u_int32_t *pcrs, u_int32_t num_of_pcrs,
|
||||||
chunk_t *pcr_composite, chunk_t *quote_signature);
|
chunk_t *pcr_composite, chunk_t *quote_signature);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs and returns PCR Quote Digest structure expected from IMC
|
||||||
|
*
|
||||||
|
* @param digest Output variable to store quote digest
|
||||||
|
* @return FALSE in case of any error, TRUE otherwise
|
||||||
|
*/
|
||||||
|
bool (*get_quote_digest)(pts_t *this, chunk_t *digest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs and returns PCR Quote Digest structure expected from IMC
|
||||||
|
*
|
||||||
|
* @param data Calculated TPM Quote Digest
|
||||||
|
* @param signature TPM Quote Signature received from IMC
|
||||||
|
* @return FALSE in case signature is not verified, TRUE otherwise
|
||||||
|
*/
|
||||||
|
bool (*verify_quote_signature)(pts_t *this, chunk_t data, chunk_t signature);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys a pts_t object.
|
* Destroys a pts_t object.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue