diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-08-18 11:10:30 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-09-08 16:34:27 +0200 |
commit | dc63b2c90940c683a58195f43e59e1c08178629d (patch) | |
tree | b6e502efcda23777a72fab37a8983aeec66ef2ba /src/cryptsetup | |
parent | repart: hook up new TPM2 signed policies with repart (diff) | |
download | systemd-dc63b2c90940c683a58195f43e59e1c08178629d.tar.xz systemd-dc63b2c90940c683a58195f43e59e1c08178629d.zip |
cryptsetup: hook up signed PCR policies
Diffstat (limited to 'src/cryptsetup')
-rw-r--r-- | src/cryptsetup/cryptsetup-tpm2.c | 62 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup-tpm2.h | 22 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup.c | 34 |
3 files changed, 93 insertions, 25 deletions
diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c index c348e73b21..7469e7da1b 100644 --- a/src/cryptsetup/cryptsetup-tpm2.c +++ b/src/cryptsetup/cryptsetup-tpm2.c @@ -57,6 +57,10 @@ int acquire_tpm2_key( const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, + const void *pubkey, + size_t pubkey_size, + uint32_t pubkey_pcr_mask, + const char *signature_path, uint16_t primary_alg, const char *key_file, size_t key_file_size, @@ -72,6 +76,7 @@ int acquire_tpm2_key( void **ret_decrypted_key, size_t *ret_decrypted_key_size) { + _cleanup_(json_variant_unrefp) JsonVariant *signature_json = NULL; _cleanup_free_ void *loaded_blob = NULL; _cleanup_free_ char *auto_device = NULL; size_t blob_size; @@ -111,14 +116,20 @@ int acquire_tpm2_key( blob = loaded_blob; } + if (pubkey_pcr_mask != 0) { + r = tpm2_load_pcr_signature(signature_path, &signature_json); + if (r < 0) + return r; + } + if (!(flags & TPM2_FLAGS_USE_PIN)) return tpm2_unseal( device, hash_pcr_mask, pcr_bank, - /* pubkey= */ NULL, /* pubkey_size= */ 0, - /* pubkey_pcr_mask= */ 0, - /* signature= */ NULL, + pubkey, pubkey_size, + pubkey_pcr_mask, + signature_json, /* pin= */ NULL, primary_alg, blob, @@ -141,9 +152,9 @@ int acquire_tpm2_key( r = tpm2_unseal(device, hash_pcr_mask, pcr_bank, - /* pubkey= */ NULL, /* pubkey_size= */ 0, - /* pubkey_pcr_mask= */ 0, - /* signature= */ NULL, + pubkey, pubkey_size, + pubkey_pcr_mask, + signature_json, pin_str, primary_alg, blob, @@ -167,8 +178,11 @@ int find_tpm2_auto_data( struct crypt_device *cd, uint32_t search_pcr_mask, int start_token, - uint32_t *ret_pcr_mask, + uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, + void **ret_pubkey, + size_t *ret_pubkey_size, + uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, void **ret_blob, size_t *ret_blob_size, @@ -178,11 +192,11 @@ int find_tpm2_auto_data( int *ret_token, TPM2Flags *ret_flags) { - _cleanup_free_ void *blob = NULL, *policy_hash = NULL; - size_t blob_size = 0, policy_hash_size = 0; + _cleanup_free_ void *blob = NULL, *policy_hash = NULL, *pubkey = NULL; + size_t blob_size = 0, policy_hash_size = 0, pubkey_size = 0; int r, keyslot = -1, token = -1; TPM2Flags flags = 0; - uint32_t pcr_mask = 0; + uint32_t hash_pcr_mask = 0, pubkey_pcr_mask = 0; uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */ uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */ @@ -212,12 +226,12 @@ int find_tpm2_auto_data( return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-pcrs' field."); - r = tpm2_parse_pcr_json_array(w, &pcr_mask); + r = tpm2_parse_pcr_json_array(w, &hash_pcr_mask); if (r < 0) return log_error_errno(r, "Failed to parse TPM2 PCR mask: %m"); if (search_pcr_mask != UINT32_MAX && - search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */ + search_pcr_mask != hash_pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */ continue; assert(keyslot < 0); @@ -292,6 +306,21 @@ int find_tpm2_auto_data( flags |= TPM2_FLAGS_USE_PIN; } + w = json_variant_by_key(v, "tpm2_pubkey_pcrs"); + if (w) { + r = tpm2_parse_pcr_json_array(w, &pubkey_pcr_mask); + if (r < 0) + return r; + } + + w = json_variant_by_key(v, "tpm2_pubkey"); + if (w) { + r = json_variant_unbase64(w, &pubkey, &pubkey_size); + if (r < 0) + return log_error_errno(r, "Failed to decode PCR public key."); + } else if (pubkey_pcr_mask != 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Public key PCR mask set, but not public key included in JSON data, refusing."); + break; } @@ -302,15 +331,18 @@ int find_tpm2_auto_data( if (start_token <= 0) log_info("Automatically discovered security TPM2 token unlocks volume."); - *ret_pcr_mask = pcr_mask; + *ret_hash_pcr_mask = hash_pcr_mask; + *ret_pcr_bank = pcr_bank; + *ret_pubkey = TAKE_PTR(pubkey); + *ret_pubkey_size = pubkey_size; + *ret_pubkey_pcr_mask = pubkey_pcr_mask; + *ret_primary_alg = primary_alg; *ret_blob = TAKE_PTR(blob); *ret_blob_size = blob_size; *ret_policy_hash = TAKE_PTR(policy_hash); *ret_policy_hash_size = policy_hash_size; *ret_keyslot = keyslot; *ret_token = token; - *ret_pcr_bank = pcr_bank; - *ret_primary_alg = primary_alg; *ret_flags = flags; return 0; diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h index ab16d0a18f..b1bcf6de10 100644 --- a/src/cryptsetup/cryptsetup-tpm2.h +++ b/src/cryptsetup/cryptsetup-tpm2.h @@ -14,8 +14,12 @@ int acquire_tpm2_key( const char *volume_name, const char *device, - uint32_t pcr_mask, + uint32_t hash_pcr_mask, uint16_t pcr_bank, + const void *pubkey, + size_t pubkey_size, + uint32_t pubkey_pcr_mask, + const char *signature_path, uint16_t primary_alg, const char *key_file, size_t key_file_size, @@ -35,8 +39,11 @@ int find_tpm2_auto_data( struct crypt_device *cd, uint32_t search_pcr_mask, int start_token, - uint32_t *ret_pcr_mask, + uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, + void **ret_pubkey, + size_t *ret_pubkey_size, + uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, void **ret_blob, size_t *ret_blob_size, @@ -51,8 +58,12 @@ int find_tpm2_auto_data( static inline int acquire_tpm2_key( const char *volume_name, const char *device, - uint32_t pcr_mask, + uint32_t hash_pcr_mask, uint16_t pcr_bank, + const void *pubkey, + size_t pubkey_size, + uint32_t pubkey_pcr_mask, + const char *signature_path, uint16_t primary_alg, const char *key_file, size_t key_file_size, @@ -76,8 +87,11 @@ static inline int find_tpm2_auto_data( struct crypt_device *cd, uint32_t search_pcr_mask, int start_token, - uint32_t *ret_pcr_mask, + uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, + void **ret_pubkey, + size_t *ret_pubkey_size, + uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, void **ret_blob, size_t *ret_blob_size, diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 90bce953de..c419354bf5 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -92,6 +92,7 @@ static char *arg_fido2_rp_id = NULL; static char *arg_tpm2_device = NULL; static bool arg_tpm2_device_auto = false; static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; +static char *arg_tpm2_signature = NULL; static bool arg_tpm2_pin = false; static bool arg_headless = false; static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC; @@ -105,6 +106,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep); STATIC_DESTRUCTOR_REGISTER(arg_fido2_cid, freep); STATIC_DESTRUCTOR_REGISTER(arg_fido2_rp_id, freep); STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); +STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep); static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = { [PASSPHRASE_REGULAR] = "passphrase", @@ -398,6 +400,16 @@ static int parse_one_option(const char *option) { if (r < 0) return r; + } else if ((val = startswith(option, "tpm2-signature="))) { + + if (!path_is_absolute(val)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 signature path \"%s\" is not absolute, refusing.", val); + + r = free_and_strdup(&arg_tpm2_signature, val); + if (r < 0) + return log_oom(); + } else if ((val = startswith(option, "tpm2-pin="))) { r = parse_boolean(val); @@ -1441,10 +1453,13 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( arg_tpm2_device, arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask, UINT16_MAX, - 0, + /* pubkey= */ NULL, /* pubkey_size= */ 0, + /* pubkey_pcr_mask= */ 0, + /* signature_path= */ NULL, + /* primary_alg= */ 0, key_file, arg_keyfile_size, arg_keyfile_offset, key_data, key_data_size, - NULL, 0, /* we don't know the policy hash */ + /* policy_hash= */ NULL, /* policy_hash_size= */ 0, /* we don't know the policy hash */ arg_tpm2_pin, until, arg_headless, @@ -1490,7 +1505,9 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( * works. */ for (;;) { - uint32_t pcr_mask; + _cleanup_free_ void *pubkey = NULL; + size_t pubkey_size = 0; + uint32_t hash_pcr_mask, pubkey_pcr_mask; uint16_t pcr_bank, primary_alg; TPM2Flags tpm2_flags; @@ -1498,8 +1515,10 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( cd, arg_tpm2_pcr_mask, /* if != UINT32_MAX we'll only look for tokens with this PCR mask */ token, /* search for the token with this index, or any later index than this */ - &pcr_mask, + &hash_pcr_mask, &pcr_bank, + &pubkey, &pubkey_size, + &pubkey_pcr_mask, &primary_alg, &blob, &blob_size, &policy_hash, &policy_hash_size, @@ -1523,10 +1542,13 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( r = acquire_tpm2_key( name, arg_tpm2_device, - pcr_mask, + hash_pcr_mask, pcr_bank, + pubkey, pubkey_size, + pubkey_pcr_mask, + arg_tpm2_signature, primary_alg, - NULL, 0, 0, /* no key file */ + /* key_file= */ NULL, /* key_file_size= */ 0, /* key_file_offset= */ 0, /* no key file */ blob, blob_size, policy_hash, policy_hash_size, tpm2_flags, |