You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
673 lines
32 KiB
673 lines
32 KiB
8 months ago
|
From 4276edfa925b9cd2f15685712a58fe68790b8d77 Mon Sep 17 00:00:00 2001
|
||
|
From: Dan Streetman <ddstreet@ieee.org>
|
||
|
Date: Tue, 27 Jun 2023 15:03:08 -0400
|
||
|
Subject: [PATCH] tpm2: add functions to convert TPM2B_PUBLIC to/from openssl
|
||
|
pkey or PEM
|
||
|
|
||
|
Add functions to convert a PEM or pkey to TPM2B_PUBLIC, and functions to
|
||
|
convert TPM2B_PUBLIC to pkey or fingerprint.
|
||
|
|
||
|
Supports both RSA and ECC keys.
|
||
|
|
||
|
Add ECC support to some test-tpm2 tests, and tests to cover the newly added functions.
|
||
|
|
||
|
(cherry picked from commit e3acb4d24c68291376b11bea5787112978e2775f)
|
||
|
|
||
|
Related: RHEL-16182
|
||
|
---
|
||
|
src/shared/tpm2-util.c | 347 ++++++++++++++++++++++++++---------------
|
||
|
src/shared/tpm2-util.h | 9 ++
|
||
|
src/test/meson.build | 5 +-
|
||
|
src/test/test-tpm2.c | 153 ++++++++++++++++--
|
||
|
4 files changed, 373 insertions(+), 141 deletions(-)
|
||
|
|
||
|
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
|
||
|
index fadf3af9d6..b73457843d 100644
|
||
|
--- a/src/shared/tpm2-util.c
|
||
|
+++ b/src/shared/tpm2-util.c
|
||
|
@@ -15,7 +15,6 @@
|
||
|
#include "hmac.h"
|
||
|
#include "lockfile-util.h"
|
||
|
#include "memory-util.h"
|
||
|
-#include "openssl-util.h"
|
||
|
#include "parse-util.h"
|
||
|
#include "random-util.h"
|
||
|
#include "sha256.h"
|
||
|
@@ -2848,124 +2847,6 @@ static int tpm2_make_policy_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
|
||
|
-#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 r, n_bytes, e_bytes;
|
||
|
-
|
||
|
- 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.");
|
||
|
-
|
||
|
-#if OPENSSL_VERSION_MAJOR >= 3
|
||
|
- if (!EVP_PKEY_get_bn_param(input, OSSL_PKEY_PARAM_RSA_N, &n))
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get RSA modulus from public key.");
|
||
|
-#else
|
||
|
- rsa = EVP_PKEY_get0_RSA(input);
|
||
|
- if (!rsa)
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to extract RSA key from public key.");
|
||
|
-
|
||
|
- n = RSA_get0_n(rsa);
|
||
|
- if (!n)
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get RSA modulus from public key.");
|
||
|
-#endif
|
||
|
-
|
||
|
- n_bytes = BN_num_bytes(n);
|
||
|
- assert_se(n_bytes > 0);
|
||
|
- if ((size_t) n_bytes > sizeof_field(TPM2B_PUBLIC, publicArea.unique.rsa.buffer))
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RSA modulus too large for TPM2 public key object.");
|
||
|
-
|
||
|
-#if OPENSSL_VERSION_MAJOR >= 3
|
||
|
- if (!EVP_PKEY_get_bn_param(input, OSSL_PKEY_PARAM_RSA_E, &e))
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get RSA exponent from public key.");
|
||
|
-#else
|
||
|
- e = RSA_get0_e(rsa);
|
||
|
- if (!e)
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get RSA exponent from public key.");
|
||
|
-#endif
|
||
|
-
|
||
|
- e_bytes = BN_num_bytes(e);
|
||
|
- assert_se(e_bytes > 0);
|
||
|
- if ((size_t) e_bytes > sizeof_field(TPM2B_PUBLIC, publicArea.parameters.rsaDetail.exponent))
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RSA exponent too large for TPM2 public key object.");
|
||
|
-
|
||
|
- *output = (TPM2B_PUBLIC) {
|
||
|
- .size = sizeof(TPMT_PUBLIC),
|
||
|
- .publicArea = {
|
||
|
- .type = TPM2_ALG_RSA,
|
||
|
- .nameAlg = TPM2_ALG_SHA256,
|
||
|
- .objectAttributes = TPMA_OBJECT_DECRYPT | TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_USERWITHAUTH,
|
||
|
- .parameters.rsaDetail = {
|
||
|
- .scheme = {
|
||
|
- .scheme = TPM2_ALG_NULL,
|
||
|
- .details.anySig.hashAlg = TPM2_ALG_NULL,
|
||
|
- },
|
||
|
- .symmetric = {
|
||
|
- .algorithm = TPM2_ALG_NULL,
|
||
|
- .mode.sym = TPM2_ALG_NULL,
|
||
|
- },
|
||
|
- .keyBits = n_bytes * 8,
|
||
|
- /* .exponent will be filled in below. */
|
||
|
- },
|
||
|
- .unique = {
|
||
|
- .rsa.size = n_bytes,
|
||
|
- /* .rsa.buffer will be filled in below. */
|
||
|
- },
|
||
|
- },
|
||
|
- };
|
||
|
-
|
||
|
- if (BN_bn2bin(n, output->publicArea.unique.rsa.buffer) <= 0)
|
||
|
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to convert RSA modulus.");
|
||
|
-
|
||
|
- 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,
|
||
|
const TPML_PCR_SELECTION *pcr_selection,
|
||
|
@@ -3575,6 +3456,212 @@ static int tpm2_build_sealing_policy(
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+#if HAVE_OPENSSL
|
||
|
+static int tpm2_ecc_curve_from_openssl_curve_id(int curve_id, TPM2_ECC_CURVE *ret) {
|
||
|
+ assert(ret);
|
||
|
+
|
||
|
+ switch (curve_id) {
|
||
|
+ case NID_X9_62_prime192v1: *ret = TPM2_ECC_NIST_P192; return 0;
|
||
|
+ case NID_secp224r1: *ret = TPM2_ECC_NIST_P192; return 0;
|
||
|
+ case NID_X9_62_prime256v1: *ret = TPM2_ECC_NIST_P256; return 0;
|
||
|
+ case NID_secp384r1: *ret = TPM2_ECC_NIST_P384; return 0;
|
||
|
+ case NID_secp521r1: *ret = TPM2_ECC_NIST_P521; return 0;
|
||
|
+ case NID_sm2: *ret = TPM2_ECC_SM2_P256; return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||
|
+ "Openssl ECC curve id %d not supported.", curve_id);
|
||
|
+}
|
||
|
+
|
||
|
+static int tpm2_ecc_curve_to_openssl_curve_id(TPM2_ECC_CURVE curve, int *ret) {
|
||
|
+ assert(ret);
|
||
|
+
|
||
|
+ switch (curve) {
|
||
|
+ case TPM2_ECC_NIST_P192: *ret = NID_X9_62_prime192v1; return 0;
|
||
|
+ case TPM2_ECC_NIST_P224: *ret = NID_secp224r1; return 0;
|
||
|
+ case TPM2_ECC_NIST_P256: *ret = NID_X9_62_prime256v1; return 0;
|
||
|
+ case TPM2_ECC_NIST_P384: *ret = NID_secp384r1; return 0;
|
||
|
+ case TPM2_ECC_NIST_P521: *ret = NID_secp521r1; return 0;
|
||
|
+ case TPM2_ECC_SM2_P256: *ret = NID_sm2; return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||
|
+ "TPM2 ECC curve %u not supported.", curve);
|
||
|
+}
|
||
|
+
|
||
|
+#define TPM2_RSA_DEFAULT_EXPONENT UINT32_C(0x10001)
|
||
|
+
|
||
|
+int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret) {
|
||
|
+ int r;
|
||
|
+
|
||
|
+ assert(public);
|
||
|
+ assert(ret);
|
||
|
+
|
||
|
+ const TPMT_PUBLIC *p = &public->publicArea;
|
||
|
+ if (p->type == TPM2_ALG_ECC) {
|
||
|
+ int curve_id;
|
||
|
+ r = tpm2_ecc_curve_to_openssl_curve_id(p->parameters.eccDetail.curveID, &curve_id);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
+ const TPMS_ECC_POINT *point = &p->unique.ecc;
|
||
|
+ return ecc_pkey_from_curve_x_y(
|
||
|
+ curve_id,
|
||
|
+ point->x.buffer,
|
||
|
+ point->x.size,
|
||
|
+ point->y.buffer,
|
||
|
+ point->y.size,
|
||
|
+ ret);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (p->type == TPM2_ALG_RSA) {
|
||
|
+ /* TPM specification Part 2 ("Structures") section for TPMS_RSA_PARAMS states "An exponent of
|
||
|
+ * zero indicates that the exponent is the default of 2^16 + 1". */
|
||
|
+ uint32_t exponent = htobe32(p->parameters.rsaDetail.exponent ?: TPM2_RSA_DEFAULT_EXPONENT);
|
||
|
+ return rsa_pkey_from_n_e(
|
||
|
+ p->unique.rsa.buffer,
|
||
|
+ p->unique.rsa.size,
|
||
|
+ &exponent,
|
||
|
+ sizeof(exponent),
|
||
|
+ ret);
|
||
|
+ }
|
||
|
+
|
||
|
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||
|
+ "TPM2 asymmetric algorithm 0x%" PRIx16 " not supported.", p->type);
|
||
|
+}
|
||
|
+
|
||
|
+int tpm2_tpm2b_public_from_openssl_pkey(const EVP_PKEY *pkey, TPM2B_PUBLIC *ret) {
|
||
|
+ int key_id, r;
|
||
|
+
|
||
|
+ assert(pkey);
|
||
|
+ assert(ret);
|
||
|
+
|
||
|
+ TPMT_PUBLIC public = {
|
||
|
+ .nameAlg = TPM2_ALG_SHA256,
|
||
|
+ .objectAttributes = TPMA_OBJECT_DECRYPT | TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_USERWITHAUTH,
|
||
|
+ .parameters.asymDetail = {
|
||
|
+ .symmetric.algorithm = TPM2_ALG_NULL,
|
||
|
+ .scheme.scheme = TPM2_ALG_NULL,
|
||
|
+ },
|
||
|
+ };
|
||
|
+
|
||
|
+#if OPENSSL_VERSION_MAJOR >= 3
|
||
|
+ key_id = EVP_PKEY_get_id(pkey);
|
||
|
+#else
|
||
|
+ key_id = EVP_PKEY_id(pkey);
|
||
|
+#endif
|
||
|
+
|
||
|
+ if (key_id == EVP_PKEY_EC) {
|
||
|
+ public.type = TPM2_ALG_ECC;
|
||
|
+
|
||
|
+ int curve_id;
|
||
|
+ _cleanup_free_ void *x = NULL, *y = NULL;
|
||
|
+ size_t x_size, y_size;
|
||
|
+ r = ecc_pkey_to_curve_x_y(pkey, &curve_id, &x, &x_size, &y, &y_size);
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Could not get ECC key curve/x/y: %m");
|
||
|
+
|
||
|
+ TPM2_ECC_CURVE curve;
|
||
|
+ r = tpm2_ecc_curve_from_openssl_curve_id(curve_id, &curve);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
+ public.parameters.eccDetail.curveID = curve;
|
||
|
+
|
||
|
+ public.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
|
||
|
+
|
||
|
+ r = TPM2B_ECC_PARAMETER_CHECK_SIZE(x_size);
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "ECC key x size %zu too large.", x_size);
|
||
|
+
|
||
|
+ public.unique.ecc.x = TPM2B_ECC_PARAMETER_MAKE(x, x_size);
|
||
|
+
|
||
|
+ r = TPM2B_ECC_PARAMETER_CHECK_SIZE(y_size);
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "ECC key y size %zu too large.", y_size);
|
||
|
+
|
||
|
+ public.unique.ecc.y = TPM2B_ECC_PARAMETER_MAKE(y, y_size);
|
||
|
+ } else if (key_id == EVP_PKEY_RSA) {
|
||
|
+ public.type = TPM2_ALG_RSA;
|
||
|
+
|
||
|
+ _cleanup_free_ void *n = NULL, *e = NULL;
|
||
|
+ size_t n_size, e_size;
|
||
|
+ r = rsa_pkey_to_n_e(pkey, &n, &n_size, &e, &e_size);
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Could not get RSA key n/e: %m");
|
||
|
+
|
||
|
+ r = TPM2B_PUBLIC_KEY_RSA_CHECK_SIZE(n_size);
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "RSA key n size %zu too large.", n_size);
|
||
|
+
|
||
|
+ public.unique.rsa = TPM2B_PUBLIC_KEY_RSA_MAKE(n, n_size);
|
||
|
+ public.parameters.rsaDetail.keyBits = n_size * 8;
|
||
|
+
|
||
|
+ if (sizeof(uint32_t) < e_size)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||
|
+ "RSA key e size %zu too large.", e_size);
|
||
|
+
|
||
|
+ uint32_t exponent = 0;
|
||
|
+ memcpy((void*) &exponent, e, e_size);
|
||
|
+ exponent = be32toh(exponent) >> (32 - e_size * 8);
|
||
|
+ if (exponent == TPM2_RSA_DEFAULT_EXPONENT)
|
||
|
+ exponent = 0;
|
||
|
+ public.parameters.rsaDetail.exponent = exponent;
|
||
|
+ } else
|
||
|
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||
|
+ "EVP_PKEY type %d not supported.", key_id);
|
||
|
+
|
||
|
+ *ret = (TPM2B_PUBLIC) {
|
||
|
+ .size = sizeof(public),
|
||
|
+ .publicArea = public,
|
||
|
+ };
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+int tpm2_tpm2b_public_to_fingerprint(
|
||
|
+ const TPM2B_PUBLIC *public,
|
||
|
+ void **ret_fingerprint,
|
||
|
+ size_t *ret_fingerprint_size) {
|
||
|
+
|
||
|
+#if HAVE_OPENSSL
|
||
|
+ int r;
|
||
|
+
|
||
|
+ assert(public);
|
||
|
+ assert(ret_fingerprint);
|
||
|
+ assert(ret_fingerprint_size);
|
||
|
+
|
||
|
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||
|
+ r = tpm2_tpm2b_public_to_openssl_pkey(public, &pkey);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
+ /* Hardcode fingerprint to SHA256 */
|
||
|
+ return pubkey_fingerprint(pkey, EVP_sha256(), ret_fingerprint, ret_fingerprint_size);
|
||
|
+#else
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret) {
|
||
|
+#if HAVE_OPENSSL
|
||
|
+ int r;
|
||
|
+
|
||
|
+ assert(pem);
|
||
|
+ assert(ret);
|
||
|
+
|
||
|
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||
|
+ r = openssl_pkey_from_pem(pem, pem_size, &pkey);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
+ return tpm2_tpm2b_public_from_openssl_pkey(pkey, ret);
|
||
|
+#else
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
int tpm2_seal(const char *device,
|
||
|
uint32_t hash_pcr_mask,
|
||
|
const void *pubkey,
|
||
|
@@ -3652,12 +3739,11 @@ int tpm2_seal(const char *device,
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
- TPM2B_PUBLIC pubkey_tpm2, *authorize_key = NULL;
|
||
|
+ TPM2B_PUBLIC pubkey_tpm2b;
|
||
|
if (pubkey) {
|
||
|
- r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, NULL, NULL);
|
||
|
+ r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &pubkey_tpm2b);
|
||
|
if (r < 0)
|
||
|
- return r;
|
||
|
- authorize_key = &pubkey_tpm2;
|
||
|
+ return log_error_errno(r, "Could not create TPMT_PUBLIC: %m");
|
||
|
}
|
||
|
|
||
|
TPM2B_DIGEST policy_digest;
|
||
|
@@ -3668,7 +3754,7 @@ int tpm2_seal(const char *device,
|
||
|
r = tpm2_calculate_sealing_policy(
|
||
|
hash_pcr_values,
|
||
|
n_hash_pcr_values,
|
||
|
- authorize_key,
|
||
|
+ pubkey ? &pubkey_tpm2b : NULL,
|
||
|
!!pin,
|
||
|
&policy_digest);
|
||
|
if (r < 0)
|
||
|
@@ -3943,14 +4029,17 @@ int tpm2_unseal(const char *device,
|
||
|
if (r < 0)
|
||
|
return r;
|
||
|
|
||
|
- TPM2B_PUBLIC pubkey_tpm2, *authorize_key = NULL;
|
||
|
+ TPM2B_PUBLIC pubkey_tpm2b;
|
||
|
_cleanup_free_ void *fp = NULL;
|
||
|
size_t fp_size = 0;
|
||
|
if (pubkey) {
|
||
|
- r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, &fp, &fp_size);
|
||
|
+ r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &pubkey_tpm2b);
|
||
|
if (r < 0)
|
||
|
- return r;
|
||
|
- authorize_key = &pubkey_tpm2;
|
||
|
+ return log_error_errno(r, "Could not create TPMT_PUBLIC: %m");
|
||
|
+
|
||
|
+ r = tpm2_tpm2b_public_to_fingerprint(&pubkey_tpm2b, &fp, &fp_size);
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Could not get key fingerprint: %m");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -3987,7 +4076,7 @@ int tpm2_unseal(const char *device,
|
||
|
policy_session,
|
||
|
hash_pcr_mask,
|
||
|
pcr_bank,
|
||
|
- authorize_key,
|
||
|
+ pubkey ? &pubkey_tpm2b : NULL,
|
||
|
fp, fp_size,
|
||
|
pubkey_pcr_mask,
|
||
|
signature,
|
||
|
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
|
||
|
index 2dffcf922d..0938fe35eb 100644
|
||
|
--- a/src/shared/tpm2-util.h
|
||
|
+++ b/src/shared/tpm2-util.h
|
||
|
@@ -7,6 +7,7 @@
|
||
|
#include "io-util.h"
|
||
|
#include "json.h"
|
||
|
#include "macro.h"
|
||
|
+#include "openssl-util.h"
|
||
|
#include "sha256.h"
|
||
|
|
||
|
typedef enum TPM2Flags {
|
||
|
@@ -157,6 +158,14 @@ int tpm2_calculate_policy_pcr(const Tpm2PCRValue *pcr_values, size_t n_pcr_value
|
||
|
int tpm2_seal(const char *device, uint32_t hash_pcr_mask, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
|
||
|
int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);
|
||
|
|
||
|
+#if HAVE_OPENSSL
|
||
|
+int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret);
|
||
|
+int tpm2_tpm2b_public_from_openssl_pkey(const EVP_PKEY *pkey, TPM2B_PUBLIC *ret);
|
||
|
+#endif
|
||
|
+
|
||
|
+int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret);
|
||
|
+int tpm2_tpm2b_public_to_fingerprint(const TPM2B_PUBLIC *public, void **ret_fingerprint, size_t *ret_fingerprint_size);
|
||
|
+
|
||
|
/* The tpm2-tss library has many structs that are simply a combination of an array (or object) and
|
||
|
* size. These macros allow easily initializing or assigning instances of such structs from an existing
|
||
|
* buffer/object and size, while also checking the size for safety with the struct buffer/object size. If the
|
||
|
diff --git a/src/test/meson.build b/src/test/meson.build
|
||
|
index 726f34426c..5430e72ab5 100644
|
||
|
--- a/src/test/meson.build
|
||
|
+++ b/src/test/meson.build
|
||
|
@@ -496,7 +496,8 @@ tests += [
|
||
|
|
||
|
[files('test-sleep.c')],
|
||
|
|
||
|
- [files('test-tpm2.c')],
|
||
|
+ [files('test-tpm2.c'),
|
||
|
+ [], [libopenssl], [], 'HAVE_OPENSSL'],
|
||
|
|
||
|
[files('test-replace-var.c')],
|
||
|
|
||
|
@@ -690,8 +691,6 @@ tests += [
|
||
|
[], [libopenssl], [], 'HAVE_OPENSSL'],
|
||
|
]
|
||
|
|
||
|
-############################################################
|
||
|
-
|
||
|
# define some tests here, because the link_with deps were not defined earlier
|
||
|
|
||
|
tests += [
|
||
|
diff --git a/src/test/test-tpm2.c b/src/test/test-tpm2.c
|
||
|
index 31988ff6f1..a3a2700a8a 100644
|
||
|
--- a/src/test/test-tpm2.c
|
||
|
+++ b/src/test/test-tpm2.c
|
||
|
@@ -701,7 +701,7 @@ TEST(parse_pcr_argument) {
|
||
|
check_parse_pcr_argument_to_mask("debug+24", -EINVAL);
|
||
|
}
|
||
|
|
||
|
-static void tpm2b_public_init(TPM2B_PUBLIC *public) {
|
||
|
+static void tpm2b_public_rsa_init(TPM2B_PUBLIC *public, const char *rsa_n) {
|
||
|
TPMT_PUBLIC tpmt = {
|
||
|
.type = TPM2_ALG_RSA,
|
||
|
.nameAlg = TPM2_ALG_SHA256,
|
||
|
@@ -717,23 +717,149 @@ static void tpm2b_public_init(TPM2B_PUBLIC *public) {
|
||
|
},
|
||
|
};
|
||
|
|
||
|
- DEFINE_HEX_PTR(key, "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727");
|
||
|
+ DEFINE_HEX_PTR(key, rsa_n);
|
||
|
tpmt.unique.rsa = TPM2B_PUBLIC_KEY_RSA_MAKE(key, key_len);
|
||
|
|
||
|
+ public->size = sizeof(tpmt);
|
||
|
public->publicArea = tpmt;
|
||
|
}
|
||
|
|
||
|
+static void tpm2b_public_ecc_init(TPM2B_PUBLIC *public, TPMI_ECC_CURVE curve, const char *x, const char *y) {
|
||
|
+ TPMT_PUBLIC tpmt = {
|
||
|
+ .type = TPM2_ALG_ECC,
|
||
|
+ .nameAlg = TPM2_ALG_SHA256,
|
||
|
+ .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
|
||
|
+ .parameters.eccDetail = {
|
||
|
+ .symmetric = {
|
||
|
+ .algorithm = TPM2_ALG_AES,
|
||
|
+ .keyBits.aes = 128,
|
||
|
+ .mode.aes = TPM2_ALG_CFB,
|
||
|
+ },
|
||
|
+ .scheme.scheme = TPM2_ALG_NULL,
|
||
|
+ .curveID = curve,
|
||
|
+ .kdf.scheme = TPM2_ALG_NULL,
|
||
|
+ },
|
||
|
+ };
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(buf_x, x);
|
||
|
+ tpmt.unique.ecc.x = TPM2B_ECC_PARAMETER_MAKE(buf_x, buf_x_len);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(buf_y, y);
|
||
|
+ tpmt.unique.ecc.y = TPM2B_ECC_PARAMETER_MAKE(buf_y, buf_y_len);
|
||
|
+
|
||
|
+ public->size = sizeof(tpmt);
|
||
|
+ public->publicArea = tpmt;
|
||
|
+}
|
||
|
+
|
||
|
+#if HAVE_OPENSSL
|
||
|
+TEST(tpm2b_public_to_openssl_pkey) {
|
||
|
+ DEFINE_HEX_PTR(msg, "edc64c6523778961fe9ba03ab7d624b27ca1dd5b01e7734cc6c891d50db04269");
|
||
|
+ TPM2B_PUBLIC public;
|
||
|
+
|
||
|
+ /* RSA */
|
||
|
+ tpm2b_public_rsa_init(&public, "d71cff5bba2173f0434a389171048e7da8cf8409b892c62946481cc383089bc754324620967fea3d00a02a717cdda4bfe1525ad957d294b88434e0a3933e86fb40f234e4935fd2ba27eb1d21da87efa466b74eb4ad18d26059904643441cf402ee933d138a2151f40459c49d87fef59e2cb822768b2d8689a9b58f82bf9a37e70693f2b2d40dfa388d365c1b1f029a14c4fc8dadb68978ef377d20ff2ca24e7078464c705eab42f531557c9c6dc0df66b506d0c26ef604f8110c64867099267453c71871e7ed22505a09daf102afc34355209ca7680eccc0ed368d148f402fa58cbb6c9d52351f535f09e4e24ad805e149f130edaa2f5e7efed3a4d2d03adb85");
|
||
|
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_rsa = NULL;
|
||
|
+ assert_se(tpm2_tpm2b_public_to_openssl_pkey(&public, &pkey_rsa) >= 0);
|
||
|
+
|
||
|
+ _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx_rsa = EVP_PKEY_CTX_new((EVP_PKEY*) pkey_rsa, NULL);
|
||
|
+ assert_se(ctx_rsa);
|
||
|
+ assert_se(EVP_PKEY_verify_init(ctx_rsa) == 1);
|
||
|
+ assert_se(EVP_PKEY_CTX_set_signature_md(ctx_rsa, EVP_sha256()) > 0);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(sig_rsa, "9f70a9e68911be3ec464cae91126328307bf355872127e042d6c61e0a80982872c151033bcf727abfae5fc9500c923120011e7ef4aa5fc690a59a034697b6022c141b4b209e2df6f4b282288cd9181073fbe7158ce113c79d87623423c1f3996ff931e59cc91db74f8e8656215b1436fc93ddec0f1f8fa8510826e674b250f047e6cba94c95ff98072a286baca94646b577974a1e00d56c21944e38960d8ee90511a2f938e5cf1ac7b7cc7ff8e3ac001d321254d3e4f988b90e9f6f873c26ecd0a12a626b3474833cdbb9e9f793238f6c97ee5b75a1a89bb7a7858d34ecfa6d34ac58d95085e6c4fbbebd47a4364be2725c2c6b3fa15d916f3c0b62a66fe76ae");
|
||
|
+ assert_se(EVP_PKEY_verify(ctx_rsa, sig_rsa, sig_rsa_len, (unsigned char*) msg, msg_len) == 1);
|
||
|
+
|
||
|
+ /* ECC */
|
||
|
+ tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "6fc0ecf3645c673ab7e86d1ec5b315afb950257c5f68ab23296160006711fac2", "8dd2ef7a2c9ecede91493ba98c8fb3f893aff325c6a1e0f752c657b2d6ca1413");
|
||
|
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_ecc = NULL;
|
||
|
+ assert_se(tpm2_tpm2b_public_to_openssl_pkey(&public, &pkey_ecc) >= 0);
|
||
|
+
|
||
|
+ _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx_ecc = EVP_PKEY_CTX_new((EVP_PKEY*) pkey_ecc, NULL);
|
||
|
+ assert_se(ctx_ecc);
|
||
|
+ assert_se(EVP_PKEY_verify_init(ctx_ecc) == 1);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(sig_ecc, "304602210092447ac0b5b32e90923f79bb4aba864b9c546a9900cf193a83243d35d189a2110221009a8b4df1dfa85e225eff9c606694d4d205a7a3968c9552f50bc2790209a90001");
|
||
|
+ assert_se(EVP_PKEY_verify(ctx_ecc, sig_ecc, sig_ecc_len, (unsigned char*) msg, msg_len) == 1);
|
||
|
+}
|
||
|
+
|
||
|
+static void get_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret) {
|
||
|
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||
|
+ TPM2B_PUBLIC p1 = {}, p2 = {};
|
||
|
+
|
||
|
+ assert(pem);
|
||
|
+ assert(ret);
|
||
|
+
|
||
|
+ assert_se(openssl_pkey_from_pem(pem, pem_size, &pkey) >= 0);
|
||
|
+ assert_se(tpm2_tpm2b_public_from_openssl_pkey(pkey, &p1) >= 0);
|
||
|
+ assert_se(tpm2_tpm2b_public_from_pem(pem, pem_size, &p2) >= 0);
|
||
|
+ assert_se(memcmp_nn(&p1, sizeof(p1), &p2, sizeof(p2)) == 0);
|
||
|
+
|
||
|
+ *ret = p1;
|
||
|
+}
|
||
|
+
|
||
|
+static void check_tpm2b_public_fingerprint(const TPM2B_PUBLIC *public, const char *hexfp) {
|
||
|
+ DEFINE_HEX_PTR(expected, hexfp);
|
||
|
+ _cleanup_free_ void *fp = NULL;
|
||
|
+ size_t fp_size;
|
||
|
+
|
||
|
+ assert_se(tpm2_tpm2b_public_to_fingerprint(public, &fp, &fp_size) >= 0);
|
||
|
+ assert_se(memcmp_nn(fp, fp_size, expected, expected_len) == 0);
|
||
|
+}
|
||
|
+
|
||
|
+TEST(tpm2b_public_from_openssl_pkey) {
|
||
|
+ TPM2B_PUBLIC public;
|
||
|
+ TPMT_PUBLIC *p = &public.publicArea;
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(key_ecc, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a30444151634451674145726a6e4575424c73496c3972687068777976584e50686a346a426e500a44586e794a304b395579724e6764365335413532542b6f5376746b436a365a726c34685847337741515558706f426c532b7448717452714c35513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a");
|
||
|
+ get_tpm2b_public_from_pem(key_ecc, key_ecc_len, &public);
|
||
|
+
|
||
|
+ assert_se(p->type == TPM2_ALG_ECC);
|
||
|
+ assert_se(p->parameters.eccDetail.curveID == TPM2_ECC_NIST_P256);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(expected_x, "ae39c4b812ec225f6b869870caf5cd3e18f88c19cf0d79f22742bd532acd81de");
|
||
|
+ assert_se(memcmp_nn(p->unique.ecc.x.buffer, p->unique.ecc.x.size, expected_x, expected_x_len) == 0);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(expected_y, "92e40e764fea12bed9028fa66b9788571b7c004145e9a01952fad1eab51a8be5");
|
||
|
+ assert_se(memcmp_nn(p->unique.ecc.y.buffer, p->unique.ecc.y.size, expected_y, expected_y_len) == 0);
|
||
|
+
|
||
|
+ check_tpm2b_public_fingerprint(&public, "cd3373293b62a52b48c12100e80ea9bfd806266ce76893a5ec31cb128052d97c");
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(key_rsa, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b4341514541795639434950652f505852337a436f63787045300a6a575262546c3568585844436b472f584b79374b6d2f4439584942334b734f5a31436a5937375571372f674359363170697838697552756a73413464503165380a593445336c68556d374a332b6473766b626f4b64553243626d52494c2f6675627771694c4d587a41673342575278747234547545443533527a373634554650640a307a70304b68775231496230444c67772f344e67566f314146763378784b4d6478774d45683567676b73733038326332706c354a504e32587677426f744e6b4d0a5471526c745a4a35355244436170696e7153334577376675646c4e735851357746766c7432377a7637344b585165616d704c59433037584f6761304c676c536b0a79754774586b6a50542f735542544a705374615769674d5a6f714b7479563463515a58436b4a52684459614c47587673504233687a766d5671636e6b47654e540a65774944415141420a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a");
|
||
|
+ get_tpm2b_public_from_pem(key_rsa, key_rsa_len, &public);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(expected_n, "c95f4220f7bf3d7477cc2a1cc691348d645b4e5e615d70c2906fd72b2eca9bf0fd5c80772ac399d428d8efb52aeff80263ad698b1f22b91ba3b00e1d3f57bc638137961526ec9dfe76cbe46e829d53609b99120bfdfb9bc2a88b317cc0837056471b6be13b840f9dd1cfbeb85053ddd33a742a1c11d486f40cb830ff8360568d4016fdf1c4a31dc7030487982092cb34f36736a65e493cdd97bf0068b4d90c4ea465b59279e510c26a98a7a92dc4c3b7ee76536c5d0e7016f96ddbbcefef829741e6a6a4b602d3b5ce81ad0b8254a4cae1ad5e48cf4ffb140532694ad6968a0319a2a2adc95e1c4195c29094610d868b197bec3c1de1cef995a9c9e419e3537b");
|
||
|
+ assert_se(p->unique.rsa.size == expected_n_len);
|
||
|
+ assert_se(memcmp(p->unique.rsa.buffer, expected_n, expected_n_len) == 0);
|
||
|
+
|
||
|
+ assert_se(p->parameters.rsaDetail.keyBits == expected_n_len * 8);
|
||
|
+
|
||
|
+ assert_se(p->parameters.rsaDetail.exponent == 0);
|
||
|
+
|
||
|
+ check_tpm2b_public_fingerprint(&public, "d9186d13a7fd5b3644cee05448f49ad3574e82a2942ff93cf89598d36cca78a9");
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+static void check_name(const TPM2B_NAME *name, const char *expect) {
|
||
|
+ assert_se(name->size == SHA256_DIGEST_SIZE + 2);
|
||
|
+
|
||
|
+ DEFINE_HEX_PTR(e, expect);
|
||
|
+ assert_se(name->size == e_len);
|
||
|
+ assert_se(memcmp(name->name, e, e_len) == 0);
|
||
|
+}
|
||
|
+
|
||
|
TEST(calculate_name) {
|
||
|
TPM2B_PUBLIC public;
|
||
|
TPM2B_NAME name;
|
||
|
|
||
|
- tpm2b_public_init(&public);
|
||
|
- assert_se(tpm2_calculate_name(&public.publicArea, &name) == 0);
|
||
|
- assert_se(name.size == SHA256_DIGEST_SIZE + 2);
|
||
|
+ /* RSA */
|
||
|
+ tpm2b_public_rsa_init(&public, "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727");
|
||
|
+ assert_se(tpm2_calculate_name(&public.publicArea, &name) >= 0);
|
||
|
+ check_name(&name, "000be78f74a470dd92e979ca067cdb2293a35f075e8560b436bd2ccea5da21486a07");
|
||
|
|
||
|
- DEFINE_HEX_PTR(e, "000be78f74a470dd92e979ca067cdb2293a35f075e8560b436bd2ccea5da21486a07");
|
||
|
- assert_se(name.size == e_len);
|
||
|
- assert_se(memcmp(name.name, e, e_len) == 0);
|
||
|
+ /* ECC */
|
||
|
+ tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "238e02ee4fd5598add6b502429f1815418515e4b0d6551c8e816b38cb15451d1", "70c2d491769775ec43ccd5a571c429233e9d30cf0f486c2e01acd6cb32ba93b6");
|
||
|
+ assert_se(tpm2_calculate_name(&public.publicArea, &name) >= 0);
|
||
|
+ check_name(&name, "000b302787187ba19c82011c987bd2dcdbb652b3a543ccc5cb0b49c33d4caae604a6");
|
||
|
}
|
||
|
|
||
|
TEST(calculate_policy_auth_value) {
|
||
|
@@ -750,12 +876,21 @@ TEST(calculate_policy_authorize) {
|
||
|
TPM2B_PUBLIC public;
|
||
|
TPM2B_DIGEST d;
|
||
|
|
||
|
- tpm2b_public_init(&public);
|
||
|
+ /* RSA */
|
||
|
+ tpm2b_public_rsa_init(&public, "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727");
|
||
|
digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||
|
assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||
|
assert_se(digest_check(&d, "95213a3784eaab04f427bc7e8851c2f1df0903be8e42428ec25dcefd907baff1"));
|
||
|
assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||
|
assert_se(digest_check(&d, "95213a3784eaab04f427bc7e8851c2f1df0903be8e42428ec25dcefd907baff1"));
|
||
|
+
|
||
|
+ /* ECC */
|
||
|
+ tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "423a89da6f0998f510489ab9682706e762031ef8f9faef2a185eff67065a187e", "996f73291670cef9e303d6cd9fa19ddf2c9c1fb1e283324ca9acca07c405c8d0");
|
||
|
+ digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||
|
+ assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||
|
+ assert_se(digest_check(&d, "2a5b705e83f949c27ac4d2e79e54fb5fb0a60f0b37bbd54a0ee1022ba00d3628"));
|
||
|
+ assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||
|
+ assert_se(digest_check(&d, "2a5b705e83f949c27ac4d2e79e54fb5fb0a60f0b37bbd54a0ee1022ba00d3628"));
|
||
|
}
|
||
|
|
||
|
TEST(calculate_policy_pcr) {
|