From 78fdf0f68b07b0539305b128a00d0f8428a055cd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Nov 2023 22:42:51 +0100 Subject: [PATCH] repart: add --tpm2-device-key= to repart, too This adds what was added to systemd-cryptenroll recently to systemd-repart too. Follow-up for: c3a2a681bed77ce4f9218cd28405994ab5263077 --- man/systemd-repart.xml | 11 +++++ src/partition/repart.c | 105 +++++++++++++++++++++++++++++++---------- 2 files changed, 90 insertions(+), 26 deletions(-) diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml index 70f8346e80e..5cd4c1ccad3 100644 --- a/man/systemd-repart.xml +++ b/man/systemd-repart.xml @@ -377,6 +377,17 @@ + + PATH + HANDLE + + Configures a TPM2 SRK key to bind encryption to. See + systemd-cryptenroll1 + for details on this option. + + + + PATH PCR diff --git a/src/partition/repart.c b/src/partition/repart.c index 01cfc46f1ce..45a214bcc8c 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -148,6 +148,8 @@ static size_t arg_key_size = 0; static EVP_PKEY *arg_private_key = NULL; static X509 *arg_certificate = NULL; static char *arg_tpm2_device = NULL; +static uint32_t arg_tpm2_seal_key_handle = 0; +static char *arg_tpm2_device_key = NULL; static Tpm2PCRValue *arg_tpm2_hash_pcr_values = NULL; static size_t arg_tpm2_n_hash_pcr_values = 0; static char *arg_tpm2_public_key = NULL; @@ -174,6 +176,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep); STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep); STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); +STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device_key, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_pcrlock, freep); @@ -3684,6 +3687,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta _cleanup_free_ char *hp = NULL, *vol = NULL, *dm_name = NULL; const char *passphrase = NULL; size_t passphrase_size = 0; + TPM2Flags flags = 0; const char *vt; int r; @@ -3790,11 +3794,6 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta } } - _cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL; - r = tpm2_context_new(arg_tpm2_device, &tpm2_context); - if (r < 0) - return log_error_errno(r, "Failed to create TPM2 context: %m"); - TPM2B_PUBLIC public; if (pubkey) { r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public); @@ -3802,9 +3801,36 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m"); } - r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values); - if (r < 0) - return log_error_errno(r, "Could not read pcr values: %m"); + _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy pcrlock_policy = {}; + if (arg_tpm2_pcrlock) { + r = tpm2_pcrlock_policy_load(arg_tpm2_pcrlock, &pcrlock_policy); + if (r < 0) + return r; + + flags |= TPM2_FLAGS_USE_PCRLOCK; + } + + _cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL; + TPM2B_PUBLIC device_key_public = {}; + if (arg_tpm2_device_key) { + r = tpm2_load_public_key_file(arg_tpm2_device_key, &device_key_public); + if (r < 0) + return r; + + if (!tpm2_pcr_values_has_all_values(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Must provide all PCR values when using TPM2 device key."); + } else { + r = tpm2_context_new(arg_tpm2_device, &tpm2_context); + if (r < 0) + return log_error_errno(r, "Failed to create TPM2 context: %m"); + + if (!tpm2_pcr_values_has_all_values(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values)) { + r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values); + if (r < 0) + return log_error_errno(r, "Could not read pcr values: %m"); + } + } uint16_t hash_pcr_bank = 0; uint32_t hash_pcr_mask = 0; @@ -3823,13 +3849,6 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta return log_error_errno(r, "Could not get hash mask: %m"); } - _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy pcrlock_policy = {}; - if (arg_tpm2_pcrlock) { - r = tpm2_pcrlock_policy_load(arg_tpm2_pcrlock, &pcrlock_policy); - if (r < 0) - return r; - } - TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE); r = tpm2_calculate_sealing_policy( arg_tpm2_hash_pcr_values, @@ -3841,14 +3860,26 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta if (r < 0) return log_error_errno(r, "Could not calculate sealing policy digest: %m"); - r = tpm2_seal(tpm2_context, - /* seal_key_handle= */ 0, - &policy, - /* pin= */ NULL, - &secret, &secret_size, - &blob, &blob_size, - /* ret_primary_alg= */ NULL, - &srk_buf, &srk_buf_size); + if (arg_tpm2_device_key) + r = tpm2_calculate_seal( + arg_tpm2_seal_key_handle, + &device_key_public, + /* attributes= */ NULL, + /* secret= */ NULL, /* secret_size= */ 0, + &policy, + /* pin= */ NULL, + &secret, &secret_size, + &blob, &blob_size, + &srk_buf, &srk_buf_size); + else + r = tpm2_seal(tpm2_context, + arg_tpm2_seal_key_handle, + &policy, + /* pin= */ NULL, + &secret, &secret_size, + &blob, &blob_size, + /* ret_primary_alg= */ NULL, + &srk_buf, &srk_buf_size); if (r < 0) return log_error_errno(r, "Failed to seal to TPM2: %m"); @@ -3863,8 +3894,8 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta keyslot = sym_crypt_keyslot_add_by_volume_key( cd, CRYPT_ANY_SLOT, - NULL, - VOLUME_KEY_SIZE, + /* volume_key= */ NULL, + /* volume_key_size= */ VOLUME_KEY_SIZE, base64_encoded, base64_encoded_size); if (keyslot < 0) @@ -3881,7 +3912,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta policy.buffer, policy.size, NULL, 0, /* no salt because tpm2_seal has no pin */ srk_buf, srk_buf_size, - 0, + flags, &v); if (r < 0) return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); @@ -6389,6 +6420,10 @@ static int help(void) { " --certificate=PATH PEM certificate to use when generating verity\n" " roothash signatures\n" " --tpm2-device=PATH Path to TPM2 device node to use\n" + " --tpm2-device-key=PATH\n" + " Enroll a TPM2 device using its public key\n" + " --tpm2-seal-key-handle=HANDLE\n" + " Specify handle of key to use for sealing\n" " --tpm2-pcrs=PCR1+PCR2+PCR3+…\n" " TPM2 PCR indexes to use for TPM2 enrollment\n" " --tpm2-public-key=PATH\n" @@ -6447,6 +6482,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_PRIVATE_KEY, ARG_CERTIFICATE, ARG_TPM2_DEVICE, + ARG_TPM2_DEVICE_KEY, + ARG_TPM2_SEAL_KEY_HANDLE, ARG_TPM2_PCRS, ARG_TPM2_PUBLIC_KEY, ARG_TPM2_PUBLIC_KEY_PCRS, @@ -6485,6 +6522,8 @@ static int parse_argv(int argc, char *argv[]) { { "private-key", required_argument, NULL, ARG_PRIVATE_KEY }, { "certificate", required_argument, NULL, ARG_CERTIFICATE }, { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, + { "tpm2-device-key", required_argument, NULL, ARG_TPM2_DEVICE_KEY }, + { "tpm2-seal-key-handle", required_argument, NULL, ARG_TPM2_SEAL_KEY_HANDLE }, { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS }, { "tpm2-public-key", required_argument, NULL, ARG_TPM2_PUBLIC_KEY }, { "tpm2-public-key-pcrs", required_argument, NULL, ARG_TPM2_PUBLIC_KEY_PCRS }, @@ -6722,6 +6761,20 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_TPM2_DEVICE_KEY: + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_tpm2_device_key); + if (r < 0) + return r; + + break; + + case ARG_TPM2_SEAL_KEY_HANDLE: + r = safe_atou32_full(optarg, 16, &arg_tpm2_seal_key_handle); + if (r < 0) + return log_error_errno(r, "Could not parse TPM2 seal key handle index '%s': %m", optarg); + + break; + case ARG_TPM2_PCRS: auto_hash_pcr_values = false; r = tpm2_parse_pcr_argument_append(optarg, &arg_tpm2_hash_pcr_values, &arg_tpm2_n_hash_pcr_values); -- 2.47.3