systemd/0513-tpm2-move-openssl-requ...

205 lines
7.7 KiB
Diff

From 42b51de62cf4f4bbb92ef63deaa4cd9181f21beb Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@ieee.org>
Date: Thu, 8 Dec 2022 16:57:47 -0500
Subject: [PATCH] tpm2: move openssl-required ifdef code out of policy-building
function
(cherry picked from commit 958982415808eeec956e79c4f7ca030af5af1b71)
Related: RHEL-16182
---
src/shared/tpm2-util.c | 98 +++++++++++++++++++++++++-----------------
1 file changed, 58 insertions(+), 40 deletions(-)
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 722ae3ca9c..ea04d0a892 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -1262,21 +1262,38 @@ static int tpm2_make_encryption_session(
return 0;
}
+static int openssl_pubkey_to_tpm2_pubkey(
+ const void *pubkey,
+ size_t pubkey_size,
+ TPM2B_PUBLIC *output,
+ void **ret_fp,
+ size_t *ret_fp_size) {
+
#if HAVE_OPENSSL
-static int openssl_pubkey_to_tpm2_pubkey(EVP_PKEY *input, TPM2B_PUBLIC *output) {
#if OPENSSL_VERSION_MAJOR >= 3
_cleanup_(BN_freep) BIGNUM *n = NULL, *e = NULL;
#else
const BIGNUM *n = NULL, *e = NULL;
const RSA *rsa = NULL;
#endif
- int n_bytes, e_bytes;
+ int r, n_bytes, e_bytes;
- assert(input);
+ assert(pubkey);
+ assert(pubkey_size > 0);
assert(output);
/* Converts an OpenSSL public key to a structure that the TPM chip can process. */
+ _cleanup_fclose_ FILE *f = NULL;
+ f = fmemopen((void*) pubkey, pubkey_size, "r");
+ if (!f)
+ return log_oom();
+
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *input = NULL;
+ input = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+ if (!input)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse PEM public key.");
+
if (EVP_PKEY_base_id(input) != EVP_PKEY_RSA)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Provided public key is not an RSA key.");
@@ -1343,22 +1360,38 @@ static int openssl_pubkey_to_tpm2_pubkey(EVP_PKEY *input, TPM2B_PUBLIC *output)
if (BN_bn2bin(e, (unsigned char*) &output->publicArea.parameters.rsaDetail.exponent) <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to convert RSA exponent.");
+ if (ret_fp) {
+ _cleanup_free_ void *fp = NULL;
+ size_t fp_size;
+
+ assert(ret_fp_size);
+
+ r = pubkey_fingerprint(input, EVP_sha256(), &fp, &fp_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to calculate public key fingerprint: %m");
+
+ *ret_fp = TAKE_PTR(fp);
+ *ret_fp_size = fp_size;
+ }
+
return 0;
+#else /* HAVE_OPENSSL */
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
+#endif
}
static int find_signature(
JsonVariant *v,
- uint16_t pcr_bank,
- uint32_t pcr_mask,
- EVP_PKEY *pk,
+ const TPML_PCR_SELECTION *pcr_selection,
+ const void *fp,
+ size_t fp_size,
const void *policy,
size_t policy_size,
void *ret_signature,
size_t *ret_signature_size) {
- _cleanup_free_ void *fp = NULL;
+#if HAVE_OPENSSL
JsonVariant *b, *i;
- size_t fp_size;
const char *k;
int r;
@@ -1368,6 +1401,12 @@ static int find_signature(
if (!json_variant_is_object(v))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Signature is not a JSON object.");
+ uint16_t pcr_bank = pcr_selection->pcrSelections[0].hash;
+ uint32_t pcr_mask;
+ r = tpm2_tpml_pcr_selection_to_mask(pcr_selection, pcr_bank, &pcr_mask);
+ if (r < 0)
+ return r;
+
k = tpm2_hash_alg_to_string(pcr_bank);
if (!k)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Don't know PCR bank %" PRIu16, pcr_bank);
@@ -1411,12 +1450,6 @@ static int find_signature(
if (r < 0)
return log_error_errno(r, "Failed to decode fingerprint in JSON data: %m");
- if (!fp) {
- r = pubkey_fingerprint(pk, EVP_sha256(), &fp, &fp_size);
- if (r < 0)
- return log_error_errno(r, "Failed to calculate public key fingerprint: %m");
- }
-
if (memcmp_nn(fp, fp_size, fpj_data, fpj_size) != 0)
continue; /* Not for this public key */
@@ -1441,8 +1474,10 @@ static int find_signature(
}
return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "Couldn't find signature for this PCR bank, PCR index and public key.");
-}
+#else /* HAVE_OPENSSL */
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
#endif
+}
static int tpm2_make_policy_session(
Tpm2Context *c,
@@ -1504,21 +1539,6 @@ static int tpm2_make_policy_session(
}
}
-#if HAVE_OPENSSL
- _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
- if (pubkey_size > 0) {
- /* If a pubkey is specified, load it to validate it, even if the PCR mask for this is
- * actually zero, and we are thus not going to use it. */
- _cleanup_fclose_ FILE *f = fmemopen((void*) pubkey, pubkey_size, "r");
- if (!f)
- return log_oom();
-
- pk = PEM_read_PUBKEY(f, NULL, NULL, NULL);
- if (!pk)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse PEM public key.");
- }
-#endif
-
_cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
r = tpm2_handle_new(c, &session);
if (r < 0)
@@ -1541,12 +1561,14 @@ static int tpm2_make_policy_session(
"Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
if (pubkey_pcr_mask != 0) {
-#if HAVE_OPENSSL
+ _cleanup_free_ void *fp = NULL;
+ size_t fp_size = 0;
+ TPM2B_PUBLIC pubkey_tpm2;
+
log_debug("Configuring public key based PCR policy.");
- /* First: load public key into the TPM */
- TPM2B_PUBLIC pubkey_tpm2;
- r = openssl_pubkey_to_tpm2_pubkey(pk, &pubkey_tpm2);
+ /* Convert the PEM key to TPM2 format */
+ r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, &fp, &fp_size);
if (r < 0)
return r;
@@ -1614,9 +1636,8 @@ static int tpm2_make_policy_session(
r = find_signature(
signature_json,
- pcr_bank,
- pubkey_pcr_mask,
- pk,
+ &pcr_selection,
+ fp, fp_size,
approved_policy->buffer,
approved_policy->size,
&signature_raw,
@@ -1680,9 +1701,6 @@ static int tpm2_make_policy_session(
if (rc != TSS2_RC_SUCCESS)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc));
-#else
- return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
-#endif
}
if (hash_pcr_mask != 0) {