summaryrefslogtreecommitdiff
path: root/src/boot/measure.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-10-31 16:50:20 +0100
committerLennart Poettering <lennart@poettering.net>2022-10-31 16:52:00 +0100
commit2e6a0579cc7026e42d3e459cf6844ade7b2e6dcf (patch)
tree0059447c0981c6dd1201fa18692742d61a48c758 /src/boot/measure.c
parent28acd1e6c3726802a1b07da23e037591b69e8cd4 (diff)
downloadsystemd-2e6a0579cc7026e42d3e459cf6844ade7b2e6dcf.tar.gz
measure: honour phases when signing
Diffstat (limited to 'src/boot/measure.c')
-rw-r--r--src/boot/measure.c270
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))