measure: honour phases when signing

This commit is contained in:
Lennart Poettering
2022-10-31 16:52:00 +01:00
parent 28acd1e6c3
commit 2e6a0579cc
+157 -135
View 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;
STRV_FOREACH(phase, arg_phase) {
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;
}
/* 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;
}
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;
}
_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;
}
session_handle = tpm2_flush_context_verbose(c.esys_context, session_handle);
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL;
mdctx = EVP_MD_CTX_new();
if (!mdctx) {
r = log_oom();
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;
}
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;
}
size_t ss;
if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) {
r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to finalize signature");
goto finish;
}
_cleanup_free_ void *sig = malloc(ss);
if (!ss) {
r = log_oom();
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 *pubkey_fp = NULL;
size_t pubkey_fp_size = 0;
r = pubkey_fingerprint(pubkey, EVP_sha256(), &pubkey_fp, &pubkey_fp_size);
r = measure_phase(pcr_states, n, *phase);
if (r < 0)
goto finish;
return r;
_cleanup_(json_variant_unrefp) JsonVariant *bv = NULL, *a = NULL;
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;
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;
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;
}
/* 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;
}
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;
}
_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;
}
session_handle = tpm2_flush_context_verbose(c.esys_context, session_handle);
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL;
mdctx = EVP_MD_CTX_new();
if (!mdctx) {
r = log_oom();
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;
}
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;
}
size_t ss;
if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) {
r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to finalize signature");
goto finish;
}
_cleanup_free_ void *sig = malloc(ss);
if (!ss) {
r = log_oom();
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 *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;
_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;
}
_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_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;
}
}
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;
}
r = json_variant_set_field(&v, p->bank, bv);
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))