diff --git a/conf/plugins/imc-attestation.opt b/conf/plugins/imc-attestation.opt index 82af6b649..25435ac53 100644 --- a/conf/plugins/imc-attestation.opt +++ b/conf/plugins/imc-attestation.opt @@ -10,6 +10,9 @@ libimcv.plugins.imc-attestation.aik_pubkey = libimcv.plugins.imc-attestation.aik_handle = AIK object handle. +libimcv.plugins.imc-attestation.hash_algorithm = sha384 + Preferred measurement hash algorithm. + libimcv.plugins.imc-attestation.mandatory_dh_groups = yes Enforce mandatory Diffie-Hellman groups. diff --git a/conf/plugins/imv-attestation.opt b/conf/plugins/imv-attestation.opt index f55225023..ca99ef42e 100644 --- a/conf/plugins/imv-attestation.opt +++ b/conf/plugins/imv-attestation.opt @@ -7,7 +7,7 @@ libimcv.plugins.imv-attestation.mandatory_dh_groups = yes libimcv.plugins.imv-attestation.dh_group = ecp256 Preferred Diffie-Hellman group. -libimcv.plugins.imv-attestation.hash_algorithm = sha256 +libimcv.plugins.imv-attestation.hash_algorithm = sha384 Preferred measurement hash algorithm. libimcv.plugins.imv-attestation.min_nonce_len = 0 diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_process.c b/src/libimcv/plugins/imc_attestation/imc_attestation_process.c index 56713bb04..daf5c3b20 100644 --- a/src/libimcv/plugins/imc_attestation/imc_attestation_process.c +++ b/src/libimcv/plugins/imc_attestation/imc_attestation_process.c @@ -57,7 +57,9 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg, chunk_t attr_info; pts_t *pts; pts_error_code_t pts_error; + tpm_tss_t *tpm; pen_type_t attr_type; + char *hash_alg; bool valid_path; pts = attestation_state->get_pts(attestation_state); @@ -85,8 +87,24 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg, tcg_pts_attr_meas_algo_t *attr_cast; pts_meas_algorithms_t offered_algorithms, selected_algorithm; + attr_cast = (tcg_pts_attr_meas_algo_t*)attr; offered_algorithms = attr_cast->get_algorithms(attr_cast); + + /* If a TPM is present choose only algorithms with a PCR bank */ + tpm = pts->get_tpm(pts); + if (tpm) + { + pts_meas_algo_with_pcr(tpm, &supported_algorithms); + } + + /* The algorithms can be restricted by the Attestation IMC */ + hash_alg = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.hash_algorithm", "sha384", lib->ns); + if (!pts_meas_algo_update(hash_alg, &supported_algorithms)) + { + supported_algorithms = PTS_MEAS_ALGO_NONE; + } selected_algorithm = pts_meas_algo_select(supported_algorithms, offered_algorithms); if (selected_algorithm == PTS_MEAS_ALGO_NONE) @@ -146,7 +164,8 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg, /* Send DH Nonce Parameters Response attribute */ attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group, - supported_algorithms, responder_nonce, responder_value); + pts->get_meas_algorithm(pts), responder_nonce, + responder_value); msg->add_attribute(msg, attr); break; } diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c index 51bcdc410..fa7d59fbc 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c @@ -887,7 +887,7 @@ imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id, } hash_alg = lib->settings->get_str(lib->settings, - "%s.plugins.imv-attestation.hash_algorithm", "sha256", lib->ns); + "%s.plugins.imv-attestation.hash_algorithm", "sha2384", lib->ns); dh_group = lib->settings->get_str(lib->settings, "%s.plugins.imv-attestation.dh_group", "ecp256", lib->ns); mandatory_dh_groups = lib->settings->get_bool(lib->settings, diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_build.c b/src/libimcv/plugins/imv_attestation/imv_attestation_build.c index db93ac45f..ec54ce0cf 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_build.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_build.c @@ -68,7 +68,7 @@ bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state, } /* Send DH nonce finish attribute */ - selected_algorithm = pts->get_meas_algorithm(pts); + selected_algorithm = pts->get_dh_hash_algorithm(pts); if (!pts->get_my_public_value(pts, &initiator_value, &initiator_nonce)) { diff --git a/src/libimcv/pts/components/ita/ita_comp_ima.c b/src/libimcv/pts/components/ita/ita_comp_ima.c index a2820b342..703d2e16a 100644 --- a/src/libimcv/pts/components/ita/ita_comp_ima.c +++ b/src/libimcv/pts/components/ita/ita_comp_ima.c @@ -167,16 +167,14 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, uint8_t qualifier, pts_pcr_t *pcrs, uint32_t pcr, chunk_t measurement) { - size_t pcr_len; pts_pcr_transform_t pcr_transform; - pts_meas_algorithms_t hash_algo; + pts_meas_algorithms_t pcr_algo; pts_comp_func_name_t *name; pts_comp_evidence_t *evidence; chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty; - hash_algo = PTS_MEAS_ALGO_SHA1; - pcr_len = HASH_SIZE_SHA1; - pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + pcr_algo = pcrs->get_pcr_algo(pcrs); + pcr_transform = PTS_PCR_TRANSFORM_MATCH; if (this->pcr_info) { @@ -190,7 +188,7 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, } name = this->name->clone(this->name); name->set_qualifier(name, qualifier); - evidence = pts_comp_evidence_create(name, this->depth, pcr, hash_algo, + evidence = pts_comp_evidence_create(name, this->depth, pcr, pcr_algo, pcr_transform, this->creation_time, measurement); if (this->pcr_info) { @@ -362,7 +360,8 @@ METHOD(pts_component_t, measure, status_t, { case IMA_STATE_INIT: this->bios_list = pts_ima_bios_list_create(pts->get_tpm(pts), - IMA_BIOS_MEASUREMENTS); + IMA_BIOS_MEASUREMENTS, + pcrs->get_pcr_algo(pcrs)); if (!this->bios_list) { return FAILED; diff --git a/src/libimcv/pts/pts.c b/src/libimcv/pts/pts.c index 2df30369d..b7f1a0e1f 100644 --- a/src/libimcv/pts/pts.c +++ b/src/libimcv/pts/pts.c @@ -290,16 +290,10 @@ METHOD(pts_t, calculate_secret, bool, return FALSE; } hasher->destroy(hasher); - - /* The DH secret must be destroyed */ chunk_clear(&shared_secret); - /* - * Truncate the hash to 20 bytes to fit the ExternalData - * argument of the TPM Quote command - */ - this->secret.len = min(this->secret.len, 20); DBG3(DBG_PTS, "secret assessment value: %B", &this->secret); + return TRUE; } @@ -698,15 +692,18 @@ METHOD(pts_t, quote, bool, tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig) { chunk_t pcr_value, pcr_computed; + hash_algorithm_t hash_alg; uint32_t pcr, pcr_sel = 0; enumerator_t *enumerator; + hash_alg = pts_meas_algo_to_hash(this->pcrs->get_pcr_algo(this->pcrs)); + /* select PCRs */ DBG2(DBG_PTS, "PCR values hashed into PCR Composite:"); enumerator = this->pcrs->create_enumerator(this->pcrs); while (enumerator->enumerate(enumerator, &pcr)) { - if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, HASH_SHA1)) + if (this->tpm->read_pcr(this->tpm, pcr, &pcr_value, hash_alg)) { pcr_computed = this->pcrs->get(this->pcrs, pcr); DBG2(DBG_PTS, "PCR %2d %#B %s", pcr, &pcr_value, @@ -720,7 +717,7 @@ METHOD(pts_t, quote, bool, enumerator->destroy(enumerator); /* TPM Quote */ - return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, HASH_SHA1, + return this->tpm->quote(this->tpm, this->aik_handle, pcr_sel, hash_alg, this->secret, quote_mode, quote_info, quote_sig); } @@ -846,7 +843,7 @@ METHOD(pts_t, get_pcrs, pts_pcr_t*, { if (!this->pcrs) { - this->pcrs = pts_pcr_create(this->tpm_version); + this->pcrs = pts_pcr_create(this->tpm_version, this->algorithm); } return this->pcrs; } @@ -904,8 +901,8 @@ pts_t *pts_create(bool is_imc) }, .is_imc = is_imc, .proto_caps = PTS_PROTO_CAPS_V, - .algorithm = PTS_MEAS_ALGO_SHA256, - .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256, + .algorithm = PTS_MEAS_ALGO_SHA384, + .dh_hash_algorithm = PTS_MEAS_ALGO_SHA384, ); if (is_imc) diff --git a/src/libimcv/pts/pts_ima_bios_list.c b/src/libimcv/pts/pts_ima_bios_list.c index 8695ab153..2c798cf0a 100644 --- a/src/libimcv/pts/pts_ima_bios_list.c +++ b/src/libimcv/pts/pts_ima_bios_list.c @@ -196,12 +196,14 @@ METHOD(pts_ima_bios_list_t, destroy, void, /** * See header */ -pts_ima_bios_list_t* pts_ima_bios_list_create(tpm_tss_t *tpm, char *file) +pts_ima_bios_list_t* pts_ima_bios_list_create(tpm_tss_t *tpm, char *file, + pts_meas_algorithms_t algo) { private_pts_ima_bios_list_t *this; uint32_t pcr, ev_type, event_type, event_len, seek_len, count = 1; uint32_t buf_len = 8192; uint8_t event_buf[buf_len]; + hash_algorithm_t hash_alg; chunk_t event; bios_entry_t *entry; struct stat st; @@ -228,6 +230,7 @@ pts_ima_bios_list_t* pts_ima_bios_list_create(tpm_tss_t *tpm, char *file) close(fd); return FALSE; } + hash_alg = pts_meas_algo_to_hash(algo); INIT(this, .public = { @@ -264,7 +267,7 @@ pts_ima_bios_list_t* pts_ima_bios_list_create(tpm_tss_t *tpm, char *file) { break; } - if (!tpm->get_event_digest(tpm, fd, &entry->measurement)) + if (!tpm->get_event_digest(tpm, fd, hash_alg, &entry->measurement)) { break; } diff --git a/src/libimcv/pts/pts_ima_bios_list.h b/src/libimcv/pts/pts_ima_bios_list.h index 701a0876a..619a4ae45 100644 --- a/src/libimcv/pts/pts_ima_bios_list.h +++ b/src/libimcv/pts/pts_ima_bios_list.h @@ -21,6 +21,8 @@ #ifndef PTS_IMA_BIOS_LIST_H_ #define PTS_IMA_BIOS_LIST_H_ +#include "pts_meas_algo.h" + #include #include @@ -70,7 +72,10 @@ struct pts_ima_bios_list_t { * * @param tpm TPM object * @param file Pathname pointing to the BIOS measurements + * @param algo hash measurement algorithm to be used */ -pts_ima_bios_list_t* pts_ima_bios_list_create(tpm_tss_t *tpm, char *file); +pts_ima_bios_list_t* pts_ima_bios_list_create(tpm_tss_t *tpm, char *file, + pts_meas_algorithms_t algo); + #endif /** PTS_IMA_BIOS_LIST_H_ @}*/ diff --git a/src/libimcv/pts/pts_meas_algo.c b/src/libimcv/pts/pts_meas_algo.c index 246c37714..18f788260 100644 --- a/src/libimcv/pts/pts_meas_algo.c +++ b/src/libimcv/pts/pts_meas_algo.c @@ -19,8 +19,11 @@ ENUM_BEGIN(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_NONE, "None"); -ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA384, PTS_MEAS_ALGO_SHA384, +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA512, PTS_MEAS_ALGO_SHA512, PTS_MEAS_ALGO_NONE, + "SHA512"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA384, PTS_MEAS_ALGO_SHA384, + PTS_MEAS_ALGO_SHA512, "SHA384"); ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_SHA384, @@ -64,9 +67,19 @@ bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms) DBG2(DBG_PTS, format1, "optional ", hash_algorithm_names, hash_alg, plugin_name); } + else if (hash_alg == HASH_SHA512) + { + *algorithms |= PTS_MEAS_ALGO_SHA512; + DBG2(DBG_PTS, format1, "optional ", hash_algorithm_names, hash_alg, + plugin_name); + } } enumerator->destroy(enumerator); + if (!(*algorithms & PTS_MEAS_ALGO_SHA512)) + { + DBG1(DBG_PTS, format2, "optional ", hash_algorithm_names, HASH_SHA512); + } if (!(*algorithms & PTS_MEAS_ALGO_SHA384)) { DBG1(DBG_PTS, format2, "optional ", hash_algorithm_names, HASH_SHA384); @@ -76,14 +89,14 @@ bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms) { return TRUE; } - if (!(*algorithms & PTS_MEAS_ALGO_SHA1)) - { - DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA1); - } if (!(*algorithms & PTS_MEAS_ALGO_SHA256)) { DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA256); } + if (!(*algorithms & PTS_MEAS_ALGO_SHA1)) + { + DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA1); + } return FALSE; } @@ -92,33 +105,67 @@ bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms) */ bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms) { - if (strcaseeq(hash_alg, "sha384") || strcaseeq(hash_alg, "sha2_384")) + if (strcaseeq(hash_alg, "sha512") || strcaseeq(hash_alg, "sha2_512")) { /* nothing to update, all algorithms are supported */ return TRUE; } + if (strcaseeq(hash_alg, "sha384") || strcaseeq(hash_alg, "sha2_384")) + { + /* remove SHA512 algorithm */ + *algorithms &= ~PTS_MEAS_ALGO_SHA512; + return TRUE; + } if (strcaseeq(hash_alg, "sha256") || strcaseeq(hash_alg, "sha2_256")) { - /* remove SHA384algorithm */ - *algorithms &= ~PTS_MEAS_ALGO_SHA384; + /* remove SHA512 and SHA384 algorithms */ + *algorithms &= ~(PTS_MEAS_ALGO_SHA512 | PTS_MEAS_ALGO_SHA384); return TRUE; } if (strcaseeq(hash_alg, "sha1")) { - /* remove SHA384 and SHA256 algorithms */ - *algorithms &= ~(PTS_MEAS_ALGO_SHA384 | PTS_MEAS_ALGO_SHA256); + /* remove SHA512, SHA384 and SHA256 algorithms */ + *algorithms &= ~(PTS_MEAS_ALGO_SHA512 | PTS_MEAS_ALGO_SHA384 | + PTS_MEAS_ALGO_SHA256); return TRUE; } DBG1(DBG_PTS, "unknown hash algorithm '%s' configured", hash_alg); return FALSE; } +/** + * Described in header. + */ +void pts_meas_algo_with_pcr(tpm_tss_t *tpm, pts_meas_algorithms_t *algorithms) +{ + pts_meas_algorithms_t algo_set[] = { PTS_MEAS_ALGO_SHA1, + PTS_MEAS_ALGO_SHA256, + PTS_MEAS_ALGO_SHA384, + PTS_MEAS_ALGO_SHA512 + }; + int i; + + for (i = 0; i < countof(algo_set); i++) + { + if (!tpm->has_pcr_bank(tpm, pts_meas_algo_to_hash(algo_set[i]))) + { + /* remove algorithm */ + *algorithms &= ~algo_set[i]; + } + } +} + /** * Described in header. */ pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos, pts_meas_algorithms_t offered_algos) { + if ((supported_algos & PTS_MEAS_ALGO_SHA512) && + (offered_algos & PTS_MEAS_ALGO_SHA512)) + { + return PTS_MEAS_ALGO_SHA512; + } if ((supported_algos & PTS_MEAS_ALGO_SHA384) && (offered_algos & PTS_MEAS_ALGO_SHA384)) { @@ -150,6 +197,8 @@ hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm) return HASH_SHA256; case PTS_MEAS_ALGO_SHA384: return HASH_SHA384; + case PTS_MEAS_ALGO_SHA512: + return HASH_SHA512; default: return HASH_UNKNOWN; } @@ -168,6 +217,8 @@ pts_meas_algorithms_t pts_meas_algo_from_hash(hash_algorithm_t algorithm) return PTS_MEAS_ALGO_SHA256; case HASH_SHA384: return PTS_MEAS_ALGO_SHA384; + case HASH_SHA512: + return PTS_MEAS_ALGO_SHA512; default: return PTS_MEAS_ALGO_NONE; } @@ -186,9 +237,10 @@ size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm) return HASH_SIZE_SHA256; case PTS_MEAS_ALGO_SHA384: return HASH_SIZE_SHA384; + case PTS_MEAS_ALGO_SHA512: + return HASH_SIZE_SHA512; case PTS_MEAS_ALGO_NONE: default: return 0; } } - diff --git a/src/libimcv/pts/pts_meas_algo.h b/src/libimcv/pts/pts_meas_algo.h index 36d0ab1f5..38504be95 100644 --- a/src/libimcv/pts/pts_meas_algo.h +++ b/src/libimcv/pts/pts_meas_algo.h @@ -24,6 +24,7 @@ #include #include +#include typedef enum pts_meas_algorithms_t pts_meas_algorithms_t; @@ -32,6 +33,7 @@ typedef enum pts_meas_algorithms_t pts_meas_algorithms_t; */ enum pts_meas_algorithms_t { PTS_MEAS_ALGO_NONE = 0, + PTS_MEAS_ALGO_SHA512 = (1<<12), PTS_MEAS_ALGO_SHA384 = (1<<13), PTS_MEAS_ALGO_SHA256 = (1<<14), PTS_MEAS_ALGO_SHA1 = (1<<15) @@ -68,6 +70,8 @@ bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms); * sha1 : PTS_MEAS_ALGO_SHA1 * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384 + * sha512: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384 | + PTS_MEAS_ALGO_SHA512 * * The PTS-IMC is expected to select the strongest supported algorithm * @@ -76,6 +80,15 @@ bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms); */ bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms); +/** + * Remove the PTS measurement algorithms not having an assigned PCR bank + * + * @param tpm handle to TPM object + * @param algorithm reduced set of algorithms with assigned PCR banks + * @ + */ +void pts_meas_algo_with_pcr(tpm_tss_t *tpm, pts_meas_algorithms_t *algorithms); + /** * Select the strongest PTS measurement algorithm * among a set of offered PTS measurement algorithms diff --git a/src/libimcv/pts/pts_pcr.c b/src/libimcv/pts/pts_pcr.c index 28593a9b9..68d36282b 100644 --- a/src/libimcv/pts/pts_pcr.c +++ b/src/libimcv/pts/pts_pcr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Andreas Steffen + * Copyright (C) 2012-2020 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -52,6 +52,16 @@ struct private_pts_pcr_t { */ uint8_t pcr_select[PTS_PCR_MAX_NUM / 8]; + /** + * Length in bytes of a PCR register (size of hash used) + */ + size_t pcr_len; + + /** + * Hash algorithm of PCR bank + */ + pts_meas_algorithms_t pcr_algo; + /** * Hasher used to extend shadow PCRs */ @@ -59,6 +69,12 @@ struct private_pts_pcr_t { }; +METHOD(pts_pcr_t, get_pcr_algo, pts_meas_algorithms_t, + private_pts_pcr_t *this) +{ + return this->pcr_algo; +} + METHOD(pts_pcr_t, get_count, uint32_t, private_pts_pcr_t *this) { @@ -162,14 +178,14 @@ METHOD(pts_pcr_t, get, chunk_t, METHOD(pts_pcr_t, set, bool, private_pts_pcr_t *this, uint32_t pcr, chunk_t value) { - if (value.len != PTS_PCR_LEN) + if (value.len != this->pcr_len) { DBG1(DBG_PTS, "PCR %2u: value does not fit", pcr); return FALSE; } if (select_pcr(this, pcr)) { - memcpy(this->pcrs[pcr].ptr, value.ptr, PTS_PCR_LEN); + memcpy(this->pcrs[pcr].ptr, value.ptr, this->pcr_len); return TRUE; } return FALSE; @@ -178,7 +194,7 @@ METHOD(pts_pcr_t, set, bool, METHOD(pts_pcr_t, extend, chunk_t, private_pts_pcr_t *this, uint32_t pcr, chunk_t measurement) { - if (measurement.len != PTS_PCR_LEN) + if (measurement.len != this->pcr_len) { DBG1(DBG_PTS, "PCR %2u: measurement does not fit", pcr); return chunk_empty; @@ -206,7 +222,7 @@ METHOD(pts_pcr_t, get_composite, tpm_tss_pcr_composite_t*, u_char *pos; selection_size = get_selection_size(this); - pcr_field_size = this->pcr_count * PTS_PCR_LEN; + pcr_field_size = this->pcr_count * this->pcr_len; INIT(pcr_composite, .pcr_select = chunk_alloc(selection_size), @@ -219,8 +235,8 @@ METHOD(pts_pcr_t, get_composite, tpm_tss_pcr_composite_t*, enumerator = create_enumerator(this); while (enumerator->enumerate(enumerator, &pcr)) { - memcpy(pos, this->pcrs[pcr].ptr, PTS_PCR_LEN); - pos += PTS_PCR_LEN; + memcpy(pos, this->pcrs[pcr].ptr, this->pcr_len); + pos += this->pcr_len; } enumerator->destroy(enumerator); @@ -243,22 +259,25 @@ METHOD(pts_pcr_t, destroy, void, /** * See header */ -pts_pcr_t *pts_pcr_create(tpm_version_t tpm_version) +pts_pcr_t *pts_pcr_create(tpm_version_t tpm_version, pts_meas_algorithms_t algo) { private_pts_pcr_t *this; + hash_algorithm_t hash_alg; hasher_t *hasher; uint32_t i; - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + hash_alg = pts_meas_algo_to_hash(algo); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); if (!hasher) { DBG1(DBG_PTS, "%N hasher could not be created", - hash_algorithm_short_names, HASH_SHA1); + hash_algorithm_short_names, hash_alg); return NULL; } INIT(this, .public = { + .get_pcr_algo = _get_pcr_algo, .get_count = _get_count, .select_pcr = _select_pcr, .get_selection_size = _get_selection_size, @@ -269,13 +288,15 @@ pts_pcr_t *pts_pcr_create(tpm_version_t tpm_version) .get_composite = _get_composite, .destroy = _destroy, }, + .pcr_algo = algo, + .pcr_len = pts_meas_algo_hash_size(algo), .hasher = hasher, ); for (i = 0; i < PTS_PCR_MAX_NUM; i++) { - this->pcrs[i] = chunk_alloc(PTS_PCR_LEN); - memset(this->pcrs[i].ptr, 0x00, PTS_PCR_LEN); + this->pcrs[i] = chunk_alloc(this->pcr_len); + memset(this->pcrs[i].ptr, 0x00, this->pcr_len); } /* Set locality indicator in PCR[0] */ @@ -285,7 +306,7 @@ pts_pcr_t *pts_pcr_create(tpm_version_t tpm_version) DBG2(DBG_PTS, "TPM 2.0 - locality indicator set to %u", (uint32_t)locality); - this->pcrs[0].ptr[PTS_PCR_LEN - 1] = locality; + this->pcrs[0].ptr[this->pcr_len - 1] = locality; } return &this->public; diff --git a/src/libimcv/pts/pts_pcr.h b/src/libimcv/pts/pts_pcr.h index ad3670539..6b399e466 100644 --- a/src/libimcv/pts/pts_pcr.h +++ b/src/libimcv/pts/pts_pcr.h @@ -23,6 +23,8 @@ typedef struct pts_pcr_t pts_pcr_t; +#include "pts_meas_algo.h" + #include #include @@ -33,16 +35,18 @@ typedef struct pts_pcr_t pts_pcr_t; */ #define PTS_PCR_MAX_NUM 24 -/** - * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2 - */ -#define PTS_PCR_LEN 20 - /** * Class implementing a shadow PCR register set */ struct pts_pcr_t { + /** + * Get the hash algorithm used by the PCR bank + * + * @return hash_measurement algorithm + */ + pts_meas_algorithms_t(*get_pcr_algo)(pts_pcr_t *this); + /** * Get the number of selected PCRs * @@ -117,7 +121,8 @@ struct pts_pcr_t { * Creates an pts_pcr_t object * * @param tpm_version TPM version + * @param algo Hash algorithm used by PCR bank */ -pts_pcr_t* pts_pcr_create(tpm_version_t tpm_version); +pts_pcr_t* pts_pcr_create(tpm_version_t tpm_version, pts_meas_algorithms_t algo); #endif /** PTS_PCR_H_ @}*/ diff --git a/src/libtpmtss/tpm_tss.h b/src/libtpmtss/tpm_tss.h index bf8cff3ea..e3dd03334 100644 --- a/src/libtpmtss/tpm_tss.h +++ b/src/libtpmtss/tpm_tss.h @@ -89,6 +89,14 @@ struct tpm_tss_t { enumerator_t *(*supported_signature_schemes)(tpm_tss_t *this, uint32_t handle); + /** + * Check if there is an assigned PCR bank for the given hash algorithm + * + * @param alg hash algorithm + * @return TRUE if a PCR bank for this algorithm exists + */ + bool (*has_pcr_bank)(tpm_tss_t *this, hash_algorithm_t alg); + /** * Retrieve the current value of a PCR register in a given PCR bank * @@ -170,10 +178,12 @@ struct tpm_tss_t { * Get an event digest from a TPM measurement log * * @param fd file descriptor of the measurement log + * @param hash hash algorithm of the digest to be extracted * @param digest allocated chunk_t containing event digest * @return TRUE if event digest was successfully extracted */ - bool (*get_event_digest)(tpm_tss_t *this, int fd, chunk_t *digest); + bool (*get_event_digest)(tpm_tss_t *this, int fd, hash_algorithm_t alg, + chunk_t *digest); /** * Destroy a tpm_tss_t. diff --git a/src/libtpmtss/tpm_tss_trousers.c b/src/libtpmtss/tpm_tss_trousers.c index c84b04167..64764bfa9 100644 --- a/src/libtpmtss/tpm_tss_trousers.c +++ b/src/libtpmtss/tpm_tss_trousers.c @@ -398,6 +398,12 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, return enumerator_create_empty(); } +METHOD(tpm_tss_t, has_pcr_bank, bool, + private_tpm_tss_trousers_t *this, hash_algorithm_t alg) +{ + return alg == HASH_SHA1; +} + 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) @@ -406,6 +412,10 @@ METHOD(tpm_tss_t, read_pcr, bool, uint8_t *value; uint32_t len; + if (alg != HASH_SHA1) + { + return FALSE; + } result = Tspi_TPM_PcrRead(this->hTPM, pcr_num, &len, &value); if (result != TSS_SUCCESS) { @@ -425,6 +435,10 @@ METHOD(tpm_tss_t, extend_pcr, bool, uint32_t pcr_len; uint8_t *pcr_ptr; + if (alg != HASH_SHA1) + { + return FALSE; + } result = Tspi_TPM_PcrExtend(this->hTPM, pcr_num, data.len, data.ptr, NULL, &pcr_len, &pcr_ptr); if (result != TSS_SUCCESS) @@ -458,6 +472,11 @@ METHOD(tpm_tss_t, quote, bool, enumerator_t *enumerator; bool success = FALSE; + if (alg != HASH_SHA1) + { + return 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); @@ -612,8 +631,13 @@ METHOD(tpm_tss_t, get_data, bool, } METHOD(tpm_tss_t, get_event_digest, bool, - private_tpm_tss_trousers_t *this, int fd, chunk_t *digest) + private_tpm_tss_trousers_t *this, int fd, hash_algorithm_t alg, + chunk_t *digest) { + if (alg != HASH_SHA1) + { + return FALSE; + } *digest = chunk_alloc(HASH_SIZE_SHA1); return read(fd, digest->ptr, digest->len) == digest->len; @@ -659,6 +683,7 @@ tpm_tss_t *tpm_tss_trousers_create() .generate_aik = _generate_aik, .get_public = _get_public, .supported_signature_schemes = _supported_signature_schemes, + .has_pcr_bank = _has_pcr_bank, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote = _quote, diff --git a/src/libtpmtss/tpm_tss_tss2_v1.c b/src/libtpmtss/tpm_tss_tss2_v1.c index cbc3118df..fb5a6e93a 100644 --- a/src/libtpmtss/tpm_tss_tss2_v1.c +++ b/src/libtpmtss/tpm_tss_tss2_v1.c @@ -42,6 +42,9 @@ #define LABEL "TPM 2.0 -" +#define PLATFORM_PCR 24 +#define MAX_PCR_BANKS 4 + typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t; /** @@ -64,21 +67,31 @@ struct private_tpm_tss_tss2_t { */ TSS2_SYS_CONTEXT *sys_context; - /** - * Number of supported algorithms - */ - size_t supported_algs_count; - /** * TPM version info */ chunk_t version_info; + /** + * Number of supported algorithms + */ + size_t supported_algs_count; + /** * List of supported algorithms */ TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET]; + /** + * Number of assigned PCR banks + */ + size_t assigned_pcrs_count; + + /** + * List of assigned PCR banks + */ + TPM_ALG_ID assigned_pcrs[MAX_PCR_BANKS]; + /** * Is TPM FIPS 186-4 compliant ? */ @@ -304,7 +317,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) this->mutex->unlock(this->mutex); if (rval != TPM_RC_SUCCESS) { - DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x", + DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ECC_CURVES: 0x%06x", LABEL, rval); return FALSE; } @@ -327,6 +340,40 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) } DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf); + /* get assigned PCR banks */ + this->mutex->lock(this->mutex); + rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_PCRS, + 0, MAX_PCR_BANKS, &more_data, &cap_data, 0); + this->mutex->unlock(this->mutex); + if (rval != TPM_RC_SUCCESS) + { + DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_PCRS: 0x%06x", + LABEL, rval); + return FALSE; + } + + /* Number of assigned PCR banks */ + this->assigned_pcrs_count = cap_data.data.assignedPCR.count; + + /* reset print buffer */ + pos = buf; + len = BUF_LEN; + + /* store and print assigned PCR banks */ + for (i = 0; i < cap_data.data.assignedPCR.count; i++) + { + alg = cap_data.data.assignedPCR.pcrSelections[i].hash; + this->assigned_pcrs[i] = alg; + written = snprintf(pos, len, " %N", tpm_alg_id_names, alg); + if (written < 0 || written >= len) + { + break; + } + pos += written; + len -= written; + } + DBG2(DBG_PTS, "%s PCR banks:%s", LABEL, buf); + return TRUE; } @@ -685,27 +732,44 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, (void*)signature_params_destroy); } +METHOD(tpm_tss_t, has_pcr_bank, bool, + private_tpm_tss_tss2_t *this, hash_algorithm_t alg) +{ + TPM_ALG_ID alg_id; + int i; + + alg_id = hash_alg_to_tpm_alg_id(alg); + + for (i = 0; i < this->assigned_pcrs_count; i++) + { + if (this->assigned_pcrs[i] == alg_id) + { + return TRUE; + } + } + + return FALSE; +} + /** * Configure a PCR Selection assuming a maximum of 24 registers */ static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs, hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel) { - TPM_ALG_ID alg_id; uint32_t pcr; - /* check if hash algorithm is supported by TPM */ - alg_id = hash_alg_to_tpm_alg_id(alg); - if (!is_supported_alg(this, alg_id)) + /* check if there is an assigned PCR bank for this hash algorithm */ + if (!has_pcr_bank(this, alg)) { - DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", + DBG1(DBG_PTS, "%s %N hash algorithm not supported by any PCR bank", LABEL, hash_algorithm_short_names, alg); return FALSE; } /* initialize the PCR Selection structure,*/ pcr_sel->count = 1; - pcr_sel->pcrSelections[0].hash = alg_id; + pcr_sel->pcrSelections[0].hash = hash_alg_to_tpm_alg_id(alg); pcr_sel->pcrSelections[0].sizeofSelect = 3; pcr_sel->pcrSelections[0].pcrSelect[0] = 0; pcr_sel->pcrSelections[0].pcrSelect[1] = 0; @@ -772,7 +836,6 @@ METHOD(tpm_tss_t, extend_pcr, bool, chunk_t data, hash_algorithm_t alg) { uint32_t rval; - TPM_ALG_ID alg_id; TPML_DIGEST_VALUES digest_values; TPMS_AUTH_COMMAND session_data_cmd; TPMS_AUTH_RESPONSE session_data_rsp; @@ -796,17 +859,16 @@ METHOD(tpm_tss_t, extend_pcr, bool, *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0; - /* check if hash algorithm is supported by TPM */ - alg_id = hash_alg_to_tpm_alg_id(alg); - if (!is_supported_alg(this, alg_id)) + /* check if there is an assigned PCR bank for this hash algorithm */ + if (!has_pcr_bank(this, alg)) { - DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", + DBG1(DBG_PTS, "%s %N hash algorithm not supported by any PCR bank", LABEL, hash_algorithm_short_names, alg); return FALSE; } digest_values.count = 1; - digest_values.digests[0].hashAlg = alg_id; + digest_values.digests[0].hashAlg = hash_alg_to_tpm_alg_id(alg); switch (alg) { @@ -1337,9 +1399,63 @@ METHOD(tpm_tss_t, get_data, bool, } METHOD(tpm_tss_t, get_event_digest, bool, - private_tpm_tss_tss2_t *this, int fd, chunk_t *digest) + private_tpm_tss_tss2_t *this, int fd, hash_algorithm_t alg, chunk_t *digest) { - return FALSE; + uint8_t digest_buf[HASH_SIZE_SHA512]; + uint32_t digest_count; + size_t digest_len = 0; + hash_algorithm_t hash_alg; + TPM_ALG_ID alg_id; + + if (read(fd, &digest_count, 4) != 4) + { + return FALSE; + } + while (digest_count--) + { + if (read(fd, &alg_id, 2) != 2) + { + return FALSE; + } + hash_alg = hash_alg_from_tpm_alg_id(alg_id); + + switch (hash_alg) + { + case HASH_SHA1: + digest_len = HASH_SIZE_SHA1; + break; + case HASH_SHA256: + digest_len = HASH_SIZE_SHA256; + break; + case HASH_SHA384: + digest_len = HASH_SIZE_SHA384; + break; + case HASH_SHA512: + digest_len = HASH_SIZE_SHA512; + break; + default: + DBG2(DBG_PTS, "alg_id: 0x%04x", alg_id); + return FALSE; + } + if (hash_alg == alg) + { + *digest = chunk_alloc(digest_len); + if (read(fd, digest->ptr, digest_len) != digest_len) + { + return FALSE; + } + } + else + { + /* read without storing */ + if (read(fd, digest_buf, digest_len) != digest_len) + { + return FALSE; + } + } + } + + return TRUE; } METHOD(tpm_tss_t, destroy, void, @@ -1366,6 +1482,7 @@ tpm_tss_t *tpm_tss_tss2_create() .generate_aik = _generate_aik, .get_public = _get_public, .supported_signature_schemes = _supported_signature_schemes, + .has_pcr_bank = _has_pcr_bank, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote = _quote, diff --git a/src/libtpmtss/tpm_tss_tss2_v2.c b/src/libtpmtss/tpm_tss_tss2_v2.c index 0f4e9ce86..914f953f5 100644 --- a/src/libtpmtss/tpm_tss_tss2_v2.c +++ b/src/libtpmtss/tpm_tss_tss2_v2.c @@ -35,6 +35,7 @@ #define LABEL "TPM 2.0 -" #define PLATFORM_PCR 24 +#define MAX_PCR_BANKS 4 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t; @@ -58,21 +59,31 @@ struct private_tpm_tss_tss2_t { */ TSS2_SYS_CONTEXT *sys_context; - /** - * Number of supported algorithms - */ - size_t supported_algs_count; - /** * TPM version info */ chunk_t version_info; + /** + * Number of supported algorithms + */ + size_t supported_algs_count; + /** * List of supported algorithms */ TPM2_ALG_ID supported_algs[TPM2_PT_ALGORITHM_SET]; + /** + * Number of assigned PCR banks + */ + size_t assigned_pcrs_count; + + /** + * List of assigned PCR banks + */ + TPM2_ALG_ID assigned_pcrs[MAX_PCR_BANKS]; + /** * Is TPM FIPS 186-4 compliant ? */ @@ -314,7 +325,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) this->mutex->unlock(this->mutex); if (rval != TPM2_RC_SUCCESS) { - DBG1(DBG_PTS, "%s GetCapability failed for TPM2_ECC_CURVES: 0x%06x", + DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_ECC_CURVES: 0x%06x", LABEL, rval); return FALSE; } @@ -337,6 +348,40 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) } DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf); + /* get assigned PCR banks */ + this->mutex->lock(this->mutex); + rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_PCRS, + 0, MAX_PCR_BANKS, &more_data, &cap_data, 0); + this->mutex->unlock(this->mutex); + if (rval != TPM2_RC_SUCCESS) + { + DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_PCRS: 0x%06x", + LABEL, rval); + return FALSE; + } + + /* Number of assigned PCR banks */ + this->assigned_pcrs_count = cap_data.data.assignedPCR.count; + + /* reset print buffer */ + pos = buf; + len = BUF_LEN; + + /* store and print assigned PCR banks */ + for (i = 0; i < cap_data.data.assignedPCR.count; i++) + { + alg = cap_data.data.assignedPCR.pcrSelections[i].hash; + this->assigned_pcrs[i] = alg; + written = snprintf(pos, len, " %N", tpm_alg_id_names, alg); + if (written < 0 || written >= len) + { + break; + } + pos += written; + len -= written; + } + DBG2(DBG_PTS, "%s PCR banks:%s", LABEL, buf); + return TRUE; } @@ -649,27 +694,45 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, (void*)signature_params_destroy); } +METHOD(tpm_tss_t, has_pcr_bank, bool, + private_tpm_tss_tss2_t *this, hash_algorithm_t alg) +{ + TPM2_ALG_ID alg_id; + int i; + + alg_id = hash_alg_to_tpm_alg_id(alg); + + for (i = 0; i < this->assigned_pcrs_count; i++) + { + if (this->assigned_pcrs[i] == alg_id) + { + return TRUE; + } + } + + return FALSE; +} + /** * Configure a PCR Selection assuming a maximum of 24 registers */ static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs, hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel) { - TPM2_ALG_ID alg_id; uint32_t pcr; - /* check if hash algorithm is supported by TPM */ - alg_id = hash_alg_to_tpm_alg_id(alg); - if (!is_supported_alg(this, alg_id)) + /* check if there is an assigned PCR bank for this hash algorithm */ + if (!has_pcr_bank(this, alg)) { - DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", + DBG1(DBG_PTS, "%s %N hash algorithm not supported by any PCR bank", LABEL, hash_algorithm_short_names, alg); return FALSE; } /* initialize the PCR Selection structure,*/ pcr_sel->count = 1; - pcr_sel->pcrSelections[0].hash = alg_id; + pcr_sel->pcrSelections[0].hash = hash_alg_to_tpm_alg_id(alg); +; pcr_sel->pcrSelections[0].sizeofSelect = 3; pcr_sel->pcrSelections[0].pcrSelect[0] = 0; pcr_sel->pcrSelections[0].pcrSelect[1] = 0; @@ -736,24 +799,22 @@ METHOD(tpm_tss_t, extend_pcr, bool, chunk_t data, hash_algorithm_t alg) { uint32_t rval; - TPM2_ALG_ID alg_id; TPML_DIGEST_VALUES digest_values; TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } }; TSS2L_SYS_AUTH_RESPONSE auth_rsp; auth_cmd.auths[0].sessionHandle = TPM2_RS_PW; - /* check if hash algorithm is supported by TPM */ - alg_id = hash_alg_to_tpm_alg_id(alg); - if (!is_supported_alg(this, alg_id)) + /* check if there is an assigned PCR bank for this hash algorithm */ + if (!has_pcr_bank(this, alg)) { - DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", + DBG1(DBG_PTS, "%s %N hash algorithm not supported by any PCR bank", LABEL, hash_algorithm_short_names, alg); return FALSE; } digest_values.count = 1; - digest_values.digests[0].hashAlg = alg_id; + digest_values.digests[0].hashAlg = hash_alg_to_tpm_alg_id(alg); switch (alg) { @@ -1237,7 +1298,7 @@ METHOD(tpm_tss_t, get_data, bool, } METHOD(tpm_tss_t, get_event_digest, bool, - private_tpm_tss_tss2_t *this, int fd, chunk_t *digest) + private_tpm_tss_tss2_t *this, int fd, hash_algorithm_t alg, chunk_t *digest) { uint8_t digest_buf[HASH_SIZE_SHA512]; uint32_t digest_count; @@ -1275,7 +1336,7 @@ METHOD(tpm_tss_t, get_event_digest, bool, DBG2(DBG_PTS, "alg_id: 0x%04x", alg_id); return FALSE; } - if (hash_alg == HASH_SHA1) + if (hash_alg == alg) { *digest = chunk_alloc(digest_len); if (read(fd, digest->ptr, digest_len) != digest_len) @@ -1285,7 +1346,7 @@ METHOD(tpm_tss_t, get_event_digest, bool, } else { - /* currently skip non-SHA1 digests */ + /* read without storing */ if (read(fd, digest_buf, digest_len) != digest_len) { return FALSE; @@ -1320,6 +1381,7 @@ tpm_tss_t *tpm_tss_tss2_create() .generate_aik = _generate_aik, .get_public = _get_public, .supported_signature_schemes = _supported_signature_schemes, + .has_pcr_bank = _has_pcr_bank, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote = _quote,