]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
measure: honour phases when signing 25202/head
authorLennart Poettering <lennart@poettering.net>
Mon, 31 Oct 2022 15:50:20 +0000 (16:50 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 31 Oct 2022 15:52:00 +0000 (16:52 +0100)
src/boot/measure.c

index 859810df55eda694ed33e007d4de263574fa6099..4f16acedf063ef4fefb487b99a33efcefc0a2b45 100644 (file)
@@ -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))