diff options
author | Lennart Poettering <lennart@poettering.net> | 2022-08-19 22:18:40 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2022-09-08 16:34:27 +0200 |
commit | 75a9681ec07bee537d037843781a9ee539e1b7c3 (patch) | |
tree | 5b49212f64f83f62240a12bee8fd960cc754e887 /src/cryptsetup/cryptsetup-tokens | |
parent | 4d5cc0d45322e71cf02cbef3022ff745e4bb3433 (diff) | |
download | systemd-75a9681ec07bee537d037843781a9ee539e1b7c3.tar.gz |
cryptsetup: hook up TPM2 token code with policies based on PCR signatures, too
Diffstat (limited to 'src/cryptsetup/cryptsetup-tokens')
-rw-r--r-- | src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c | 142 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c | 130 | ||||
-rw-r--r-- | src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h | 18 |
3 files changed, 112 insertions, 178 deletions
diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c index bbc8a39c98..7e958a4db5 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c @@ -40,27 +40,28 @@ _public_ int cryptsetup_token_open_pin( int token /* is always >= 0 */, const char *pin, size_t pin_size, - char **password, /* freed by cryptsetup_token_buffer_free */ - size_t *password_len, + char **ret_password, /* freed by cryptsetup_token_buffer_free */ + size_t *ret_password_len, void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) { - int r; - const char *json; - size_t blob_size, policy_hash_size, decrypted_key_size; - uint32_t pcr_mask; - uint16_t pcr_bank, primary_alg; + _cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL; + _cleanup_free_ void *blob = NULL, *pubkey = NULL, *policy_hash = NULL; + size_t blob_size, policy_hash_size, decrypted_key_size, pubkey_size; + _cleanup_(erase_and_freep) void *decrypted_key = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + uint32_t hash_pcr_mask, pubkey_pcr_mask; systemd_tpm2_plugin_params params = { .search_pcr_mask = UINT32_MAX }; - _cleanup_free_ void *blob = NULL, *policy_hash = NULL; - _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL; - _cleanup_(erase_and_freep) void *decrypted_key = NULL; - _cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL; + uint16_t pcr_bank, primary_alg; + TPM2Flags flags = 0; + const char *json; + int r; - assert(!pin || pin_size); - assert(password); - assert(password_len); assert(token >= 0); + assert(!pin || pin_size > 0); + assert(ret_password); + assert(ret_password_len); /* This must not fail at this moment (internal error) */ r = crypt_token_json_get(cd, token, &json); @@ -74,32 +75,44 @@ _public_ int cryptsetup_token_open_pin( if (usrptr) params = *(systemd_tpm2_plugin_params *)usrptr; - TPM2Flags flags = 0; - r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags); + r = json_parse(json, 0, &v, NULL, NULL); if (r < 0) - return log_debug_open_error(cd, r); - - /* should not happen since cryptsetup_token_validate have passed */ - r = unbase64mem(base64_blob, SIZE_MAX, &blob, &blob_size); + return crypt_log_debug_errno(cd, r, "Failed to parse token JSON data: %m"); + + r = tpm2_parse_luks2_json( + v, + NULL, + &hash_pcr_mask, + &pcr_bank, + &pubkey, + &pubkey_size, + &pubkey_pcr_mask, + &primary_alg, + &blob, + &blob_size, + &policy_hash, + &policy_hash_size, + &flags); if (r < 0) return log_debug_open_error(cd, r); - /* should not happen since cryptsetup_token_validate have passed */ - r = unhexmem(hex_policy_hash, SIZE_MAX, &policy_hash, &policy_hash_size); - if (r < 0) - return log_debug_open_error(cd, r); + if (params.search_pcr_mask != UINT32_MAX && hash_pcr_mask != params.search_pcr_mask) + return crypt_log_debug_errno(cd, ENXIO, "PCR mask doesn't match expectation (%" PRIu32 " vs. %" PRIu32 ")", hash_pcr_mask, params.search_pcr_mask); r = acquire_luks2_key( - pcr_mask, + params.device, + hash_pcr_mask, pcr_bank, + pubkey, pubkey_size, + pubkey_pcr_mask, + params.signature_path, + pin_string, primary_alg, - params.device, blob, blob_size, policy_hash, policy_hash_size, flags, - pin_string, &decrypted_key, &decrypted_key_size); if (r < 0) @@ -111,8 +124,8 @@ _public_ int cryptsetup_token_open_pin( return log_debug_open_error(cd, r); /* free'd automatically by libcryptsetup */ - *password_len = strlen(base64_encoded); - *password = TAKE_PTR(base64_encoded); + *ret_password_len = strlen(base64_encoded); + *ret_password = TAKE_PTR(base64_encoded); return 0; } @@ -133,11 +146,11 @@ _public_ int cryptsetup_token_open_pin( _public_ int cryptsetup_token_open( struct crypt_device *cd, /* is always LUKS2 context */ int token /* is always >= 0 */, - char **password, /* freed by cryptsetup_token_buffer_free */ - size_t *password_len, + char **ret_password, /* freed by cryptsetup_token_buffer_free */ + size_t *ret_password_len, void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) { - return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr); + return cryptsetup_token_open_pin(cd, token, NULL, 0, ret_password, ret_password_len, usrptr); } /* @@ -156,45 +169,66 @@ _public_ void cryptsetup_token_dump( struct crypt_device *cd /* is always LUKS2 context */, const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) { - int r; - TPM2Flags flags = 0; - uint32_t pcr_mask; + _cleanup_free_ char *hash_pcrs_str = NULL, *pubkey_pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL, *pubkey_str = NULL; + _cleanup_free_ void *blob = NULL, *pubkey = NULL, *policy_hash = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + size_t blob_size, policy_hash_size, pubkey_size; + uint32_t hash_pcr_mask, pubkey_pcr_mask; uint16_t pcr_bank, primary_alg; - size_t decoded_blob_size; - _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL, - *pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL; - _cleanup_free_ void *decoded_blob = NULL; + TPM2Flags flags = 0; + int r; assert(json); - r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags); + r = json_parse(json, 0, &v, NULL, NULL); + if (r < 0) + return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON object: %m"); + + r = tpm2_parse_luks2_json( + v, + NULL, + &hash_pcr_mask, + &pcr_bank, + &pubkey, + &pubkey_size, + &pubkey_pcr_mask, + &primary_alg, + &blob, + &blob_size, + &policy_hash, + &policy_hash_size, + &flags); + if (r < 0) + return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " JSON fields: %m"); + + r = pcr_mask_to_string(hash_pcr_mask, &hash_pcrs_str); if (r < 0) - return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m."); + return (void) crypt_log_debug_errno(cd, r, "Cannot format PCR hash mask: %m"); - for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) { - if ((pcr_mask & (UINT32_C(1) << i)) && - ((r = strextendf_with_separator(&pcrs_str, ", ", "%" PRIu32, i)) < 0)) - return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m"); - } + r = pcr_mask_to_string(pubkey_pcr_mask, &pubkey_pcrs_str); + if (r < 0) + return (void) crypt_log_debug_errno(cd, r, "Cannot format PCR hash mask: %m"); - r = unbase64mem(base64_blob, SIZE_MAX, &decoded_blob, &decoded_blob_size); + r = crypt_dump_buffer_to_hex_string(blob, blob_size, &blob_str); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m"); - r = crypt_dump_buffer_to_hex_string(decoded_blob, decoded_blob_size, &blob_str); + r = crypt_dump_buffer_to_hex_string(pubkey, pubkey_size, &pubkey_str); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m"); - r = crypt_dump_hex_string(hex_policy_hash, &policy_hash_str); + r = crypt_dump_buffer_to_hex_string(policy_hash, policy_hash_size, &policy_hash_str); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m"); - crypt_log(cd, "\ttpm2-pcrs: %s\n", strna(pcrs_str)); - crypt_log(cd, "\ttpm2-bank: %s\n", strna(tpm2_pcr_bank_to_string(pcr_bank))); - crypt_log(cd, "\ttpm2-primary-alg: %s\n", strna(tpm2_primary_alg_to_string(primary_alg))); - crypt_log(cd, "\ttpm2-blob: %s\n", blob_str); + crypt_log(cd, "\ttpm2-hash-pcrs: %s\n", strna(hash_pcrs_str)); + crypt_log(cd, "\ttpm2-pcr-bank: %s\n", strna(tpm2_pcr_bank_to_string(pcr_bank))); + crypt_log(cd, "\ttpm2-pubkey:" CRYPT_DUMP_LINE_SEP "%s\n", pubkey_str); + crypt_log(cd, "\ttpm2-pubkey-pcrs: %s\n", strna(pubkey_pcrs_str)); + crypt_log(cd, "\ttpm2-primary-alg: %s\n", strna(tpm2_primary_alg_to_string(primary_alg))); + crypt_log(cd, "\ttpm2-blob: %s\n", blob_str); crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str); - crypt_log(cd, "\ttpm2-pin: %s\n", true_false(flags & TPM2_FLAGS_USE_PIN)); + crypt_log(cd, "\ttpm2-pin: %s\n", true_false(flags & TPM2_FLAGS_USE_PIN)); } /* diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c index 3d633de3f5..be496d4949 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c @@ -13,19 +13,24 @@ #include "tpm2-util.h" int acquire_luks2_key( - uint32_t pcr_mask, + 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, + const char *pin, uint16_t primary_alg, - const char *device, const void *key_data, size_t key_data_size, const void *policy_hash, size_t policy_hash_size, TPM2Flags flags, - const char *pin, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { + _cleanup_(json_variant_unrefp) JsonVariant *signature_json = NULL; _cleanup_free_ char *auto_device = NULL; int r; @@ -45,121 +50,22 @@ int acquire_luks2_key( if ((flags & TPM2_FLAGS_USE_PIN) && !pin) return -ENOANO; + if (pubkey_pcr_mask != 0) { + r = tpm2_load_pcr_signature(signature_path, &signature_json); + if (r < 0) + return r; + } + return tpm2_unseal( device, - pcr_mask, + hash_pcr_mask, pcr_bank, - /* pubkey= */ NULL, /* pubkey_size= */ 0, - /* pubkey_pcr_mask= */ 0, - /* signature_json= */ NULL, + pubkey, pubkey_size, + pubkey_pcr_mask, + signature_json, pin, primary_alg, key_data, key_data_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size); } - -/* this function expects valid "systemd-tpm2" in json */ -int parse_luks2_tpm2_data( - const char *json, - uint32_t search_pcr_mask, - uint32_t *ret_pcr_mask, - uint16_t *ret_pcr_bank, - uint16_t *ret_primary_alg, - char **ret_base64_blob, - char **ret_hex_policy_hash, - TPM2Flags *ret_flags) { - - int r; - JsonVariant *w; - uint32_t pcr_mask; - uint16_t pcr_bank = UINT16_MAX, primary_alg = TPM2_ALG_ECC; - _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL; - _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; - TPM2Flags flags = 0; - - assert(json); - assert(ret_pcr_mask); - assert(ret_pcr_bank); - assert(ret_primary_alg); - assert(ret_base64_blob); - assert(ret_hex_policy_hash); - - r = json_parse(json, 0, &v, NULL, NULL); - if (r < 0) - return -EINVAL; - - w = json_variant_by_key(v, "tpm2-pcrs"); - if (!w) - return -EINVAL; - - r = tpm2_parse_pcr_json_array(w, &pcr_mask); - if (r < 0) - return r; - - if (search_pcr_mask != UINT32_MAX && - search_pcr_mask != pcr_mask) - return -ENXIO; - - w = json_variant_by_key(v, "tpm2-pcr-bank"); - if (w) { - /* The PCR bank field is optional */ - - if (!json_variant_is_string(w)) - return -EINVAL; - - r = tpm2_pcr_bank_from_string(json_variant_string(w)); - if (r < 0) - return r; - - pcr_bank = r; - } - - w = json_variant_by_key(v, "tpm2-primary-alg"); - if (w) { - /* The primary key algorithm is optional */ - - if (!json_variant_is_string(w)) - return -EINVAL; - - r = tpm2_primary_alg_from_string(json_variant_string(w)); - if (r < 0) - return r; - - primary_alg = r; - } - - w = json_variant_by_key(v, "tpm2-blob"); - if (!w || !json_variant_is_string(w)) - return -EINVAL; - - base64_blob = strdup(json_variant_string(w)); - if (!base64_blob) - return -ENOMEM; - - w = json_variant_by_key(v, "tpm2-policy-hash"); - if (!w || !json_variant_is_string(w)) - return -EINVAL; - - hex_policy_hash = strdup(json_variant_string(w)); - if (!hex_policy_hash) - return -ENOMEM; - - w = json_variant_by_key(v, "tpm2-pin"); - if (w) { - if (!json_variant_is_boolean(w)) - return -EINVAL; - - if (json_variant_boolean(w)) - flags |= TPM2_FLAGS_USE_PIN; - } - - *ret_pcr_mask = pcr_mask; - *ret_pcr_bank = pcr_bank; - *ret_primary_alg = primary_alg; - *ret_base64_blob = TAKE_PTR(base64_blob); - *ret_hex_policy_hash = TAKE_PTR(hex_policy_hash); - *ret_flags = flags; - - return 0; -} diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h index 5e33418025..f3625124e5 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h @@ -7,25 +7,19 @@ struct crypt_device; int acquire_luks2_key( + const char *device, uint32_t pcr_mask, uint16_t pcr_bank, + const void *pubkey, + size_t pubkey_size, + uint32_t pubkey_pcr_mask, + const char *signature_path, + const char *pin, uint16_t primary_alg, - const char *device, const void *key_data, size_t key_data_size, const void *policy_hash, size_t policy_hash_size, TPM2Flags flags, - const char *pin, void **ret_decrypted_key, size_t *ret_decrypted_key_size); - -int parse_luks2_tpm2_data( - const char *json, - uint32_t search_pcr_mask, - uint32_t *ret_pcr_mask, - uint16_t *ret_pcr_bank, - uint16_t *ret_primary_alg, - char **ret_base64_blob, - char **ret_hex_policy_hash, - TPM2Flags *ret_flags); |