diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-10-31 16:50:20 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-10-31 16:52:00 +0100 |
commit | 2e6a0579cc7026e42d3e459cf6844ade7b2e6dcf (patch) | |
tree | 0059447c0981c6dd1201fa18692742d61a48c758 /src/boot/measure.c | |
parent | 28acd1e6c3726802a1b07da23e037591b69e8cd4 (diff) | |
download | systemd-2e6a0579cc7026e42d3e459cf6844ade7b2e6dcf.tar.gz |
measure: honour phases when signing
Diffstat (limited to 'src/boot/measure.c')
-rw-r--r-- | src/boot/measure.c | 270 |
1 files changed, 146 insertions, 124 deletions
diff --git a/src/boot/measure.c b/src/boot/measure.c index 859810df55..4f16acedf0 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -779,6 +779,10 @@ static int verb_sign(int argc, char *argv[], void *userdata) { if (r < 0) return r; + r = pcr_states_save(pcr_states, n); + if (r < 0) + return r; + r = dlopen_tpm2(); if (r < 0) return r; @@ -787,147 +791,165 @@ static int verb_sign(int argc, char *argv[], void *userdata) { if (r < 0) return r; - for (size_t i = 0; i < n; i++) { - static const TPMT_SYM_DEF symmetric = { - .algorithm = TPM2_ALG_AES, - .keyBits.aes = 128, - .mode.aes = TPM2_ALG_CFB, - }; - PcrState *p = pcr_states + i; - - rc = sym_Esys_StartAuthSession( - c.esys_context, - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - NULL, - TPM2_SE_TRIAL, - &symmetric, - TPM2_ALG_SHA256, - &session_handle); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + STRV_FOREACH(phase, arg_phase) { - /* Generate a single hash value from the PCRs included in our policy. Given that that's - * exactly one, the calculation is trivial. */ - TPM2B_DIGEST intermediate_digest = { - .size = SHA256_DIGEST_SIZE, - }; - assert(sizeof(intermediate_digest.buffer) >= SHA256_DIGEST_SIZE); - sha256_direct(p->value, p->value_size, intermediate_digest.buffer); + r = measure_phase(pcr_states, n, *phase); + if (r < 0) + return r; - int tpmalg = tpm2_pcr_bank_from_string(EVP_MD_name(p->md)); - if (tpmalg < 0) { - log_error_errno(tpmalg, "Unsupported PCR bank"); - goto finish; - } + for (size_t i = 0; i < n; i++) { + static const TPMT_SYM_DEF symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }; + PcrState *p = pcr_states + i; + + rc = sym_Esys_StartAuthSession( + c.esys_context, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + NULL, + TPM2_SE_TRIAL, + &symmetric, + TPM2_ALG_SHA256, + &session_handle); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } - TPML_PCR_SELECTION pcr_selection; - tpm2_pcr_mask_to_selection(1 << TPM_PCR_INDEX_KERNEL_IMAGE, tpmalg, &pcr_selection); - - rc = sym_Esys_PolicyPCR( - c.esys_context, - session_handle, - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - &intermediate_digest, - &pcr_selection); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to push PCR policy into TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + /* Generate a single hash value from the PCRs included in our policy. Given that that's + * exactly one, the calculation is trivial. */ + TPM2B_DIGEST intermediate_digest = { + .size = SHA256_DIGEST_SIZE, + }; + assert(sizeof(intermediate_digest.buffer) >= SHA256_DIGEST_SIZE); + sha256_direct(p->value, p->value_size, intermediate_digest.buffer); + + int tpmalg = tpm2_pcr_bank_from_string(EVP_MD_name(p->md)); + if (tpmalg < 0) { + log_error_errno(tpmalg, "Unsupported PCR bank"); + goto finish; + } - _cleanup_(Esys_Freep) TPM2B_DIGEST *pcr_policy_digest = NULL; - rc = sym_Esys_PolicyGetDigest( - c.esys_context, - session_handle, - ESYS_TR_NONE, - ESYS_TR_NONE, - ESYS_TR_NONE, - &pcr_policy_digest); - if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); - goto finish; - } + TPML_PCR_SELECTION pcr_selection; + tpm2_pcr_mask_to_selection(1 << TPM_PCR_INDEX_KERNEL_IMAGE, tpmalg, &pcr_selection); + + rc = sym_Esys_PolicyPCR( + c.esys_context, + session_handle, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + &intermediate_digest, + &pcr_selection); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to push PCR policy into TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } - session_handle = tpm2_flush_context_verbose(c.esys_context, session_handle); + _cleanup_(Esys_Freep) TPM2B_DIGEST *pcr_policy_digest = NULL; + rc = sym_Esys_PolicyGetDigest( + c.esys_context, + session_handle, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + &pcr_policy_digest); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } - _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL; - mdctx = EVP_MD_CTX_new(); - if (!mdctx) { - r = log_oom(); - goto finish; - } + session_handle = tpm2_flush_context_verbose(c.esys_context, session_handle); - if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to initialize signature context."); - goto finish; - } + _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL; + mdctx = EVP_MD_CTX_new(); + if (!mdctx) { + r = log_oom(); + goto finish; + } - if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest->buffer, pcr_policy_digest->size) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to sign data."); - goto finish; - } + if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to initialize signature context."); + goto finish; + } - size_t ss; - if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to finalize signature"); - goto finish; - } + if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest->buffer, pcr_policy_digest->size) != 1) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to sign data."); + goto finish; + } - _cleanup_free_ void *sig = malloc(ss); - if (!ss) { - r = log_oom(); - goto finish; - } + size_t ss; + if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to finalize signature"); + goto finish; + } - if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to acquire signature data"); - goto finish; - } + _cleanup_free_ void *sig = malloc(ss); + if (!ss) { + r = log_oom(); + goto finish; + } - _cleanup_free_ void *pubkey_fp = NULL; - size_t pubkey_fp_size = 0; - r = pubkey_fingerprint(pubkey, EVP_sha256(), &pubkey_fp, &pubkey_fp_size); - if (r < 0) - goto finish; + if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to acquire signature data"); + goto finish; + } - _cleanup_(json_variant_unrefp) JsonVariant *bv = NULL, *a = NULL; + _cleanup_free_ void *pubkey_fp = NULL; + size_t pubkey_fp_size = 0; + r = pubkey_fingerprint(pubkey, EVP_sha256(), &pubkey_fp, &pubkey_fp_size); + if (r < 0) + goto finish; - r = tpm2_make_pcr_json_array(UINT64_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE, &a); - if (r < 0) { - log_error_errno(r, "Failed to build JSON PCR mask array: %m"); - goto finish; - } + _cleanup_(json_variant_unrefp) JsonVariant *a = NULL; + r = tpm2_make_pcr_json_array(UINT64_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE, &a); + if (r < 0) { + log_error_errno(r, "Failed to build JSON PCR mask array: %m"); + goto finish; + } - r = json_build(&bv, JSON_BUILD_ARRAY( - JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("pcrs", JSON_BUILD_VARIANT(a)), /* PCR mask */ - JSON_BUILD_PAIR("pkfp", JSON_BUILD_HEX(pubkey_fp, pubkey_fp_size)), /* SHA256 fingerprint of public key (DER) used for the signature */ - JSON_BUILD_PAIR("pol", JSON_BUILD_HEX(pcr_policy_digest->buffer, pcr_policy_digest->size)), /* TPM2 policy hash that is signed */ - JSON_BUILD_PAIR("sig", JSON_BUILD_BASE64(sig, ss))))); /* signature data */ - if (r < 0) { - log_error_errno(r, "Failed to build JSON object: %m"); - goto finish; - } + _cleanup_(json_variant_unrefp) JsonVariant *bv = NULL; + r = json_build(&bv, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("pcrs", JSON_BUILD_VARIANT(a)), /* PCR mask */ + JSON_BUILD_PAIR("pkfp", JSON_BUILD_HEX(pubkey_fp, pubkey_fp_size)), /* SHA256 fingerprint of public key (DER) used for the signature */ + JSON_BUILD_PAIR("pol", JSON_BUILD_HEX(pcr_policy_digest->buffer, pcr_policy_digest->size)), /* TPM2 policy hash that is signed */ + JSON_BUILD_PAIR("sig", JSON_BUILD_BASE64(sig, ss)))); /* signature data */ + if (r < 0) { + log_error_errno(r, "Failed to build JSON object: %m"); + goto finish; + } + + _cleanup_(json_variant_unrefp) JsonVariant *av = NULL; + av = json_variant_ref(json_variant_by_key(v, p->bank)); - r = json_variant_set_field(&v, p->bank, bv); - if (r < 0) { - log_error_errno(r, "Failed to add JSON field: %m"); - goto finish; + r = json_variant_append_array(&av, bv); + if (r < 0) { + log_error_errno(r, "Failed to append JSON object: %m"); + goto finish; + } + + r = json_variant_set_field(&v, p->bank, av); + if (r < 0) { + log_error_errno(r, "Failed to add JSON field: %m"); + goto finish; + } } + + /* Return to the original kernel measurement for the next phase calculation */ + pcr_states_restore(pcr_states, n); } if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) |