From: Lennart Poettering Date: Fri, 14 Oct 2022 12:38:35 +0000 (+0200) Subject: tpm2-util: optionally do HMAC in tpm2_extend_bytes() in case we process sensitive... X-Git-Tag: v253-rc1~93^2~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9885c8745d313588350325e8e2110887bf78c442;p=thirdparty%2Fsystemd.git tpm2-util: optionally do HMAC in tpm2_extend_bytes() in case we process sensitive data When measuring data into a PCR we are supposed to hash the data on the CPU and then pass the hash value over the wire to the TPM2. That's all good as long as the data we intend to measure is not sensitive. Let's be extra careful though if we want to measure sensitive data, for example the root file system volume key. Instead of just hashing that and passing it over the wire to the TPM2, let's do a HMAC signature instead. It's also a hash operation, but should protect our secret reasonably well and not leak direct information about it to wiretappers. --- diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c index a4aa162801d..6d055e3499d 100644 --- a/src/boot/pcrphase.c +++ b/src/boot/pcrphase.c @@ -220,7 +220,7 @@ static int run(int argc, char *argv[]) { log_debug("Measuring '%s' into PCR index %u, banks %s.", word, TPM_PCR_INDEX_KERNEL_IMAGE, joined); - r = tpm2_extend_bytes(c.esys_context, arg_banks, TPM_PCR_INDEX_KERNEL_IMAGE, word, length); /* → PCR 11 */ + r = tpm2_extend_bytes(c.esys_context, arg_banks, TPM_PCR_INDEX_KERNEL_IMAGE, word, length, NULL, 0); /* → PCR 11 */ if (r < 0) return r; diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 36023c6de25..1b0adab3974 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -1925,14 +1925,22 @@ int tpm2_extend_bytes( char **banks, unsigned pcr_index, const void *data, - size_t sz) { + size_t data_size, + const void *secret, + size_t secret_size) { #if HAVE_OPENSSL TPML_DIGEST_VALUES values = {}; TSS2_RC rc; assert(c); - assert(data || sz == 0); + assert(data || data_size == 0); + assert(secret || secret_size == 0); + + if (data_size == SIZE_MAX) + data_size = strlen(data); + if (secret_size == SIZE_MAX) + secret_size = strlen(secret); if (pcr_index >= TPM2_PCRS_MAX) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Can't measure into unsupported PCR %u, refusing.", pcr_index); @@ -1958,8 +1966,17 @@ int tpm2_extend_bytes( values.digests[values.count].hashAlg = id; - if (EVP_Digest(data, sz, (unsigned char*) &values.digests[values.count].digest, NULL, implementation, NULL) != 1) - return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash word."); + /* So here's a twist: sometimes we want to measure secrets (e.g. root file system volume + * key), but we'd rather not leak a literal hash of the secret to the TPM (given that the + * wire is unprotected, and some other subsystem might use the simple, literal hash of the + * secret for other purposes, maybe because it needs a shorter secret derived from it for + * some unrelated purpose, who knows). Hence we instead measure an HMAC signature of a + * private non-secret string instead. */ + if (secret_size > 0) { + if (!HMAC(implementation, secret, secret_size, data, data_size, (unsigned char*) &values.digests[values.count].digest, NULL)) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to calculate HMAC of data to measure."); + } else if (EVP_Digest(data, data_size, (unsigned char*) &values.digests[values.count].digest, NULL, implementation, NULL) != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash data to measure."); values.count++; } diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 4cab52a9492..96e6c31b0a4 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -70,7 +70,7 @@ static inline void Esys_Freep(void *p) { int tpm2_get_good_pcr_banks(ESYS_CONTEXT *c, uint32_t pcr_mask, TPMI_ALG_HASH **ret_banks); int tpm2_get_good_pcr_banks_strv(ESYS_CONTEXT *c, uint32_t pcr_mask, char ***ret); -int tpm2_extend_bytes(ESYS_CONTEXT *c, char **banks, unsigned pcr_index, const void *data, size_t sz); +int tpm2_extend_bytes(ESYS_CONTEXT *c, char **banks, unsigned pcr_index, const void *data, size_t data_size, const void *secret, size_t secret_size); #else struct tpm2_context;