summaryrefslogtreecommitdiff
path: root/src/cryptsetup
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-08-19 22:18:40 +0200
committerLennart Poettering <lennart@poettering.net>2022-09-08 16:34:27 +0200
commit75a9681ec07bee537d037843781a9ee539e1b7c3 (patch)
tree5b49212f64f83f62240a12bee8fd960cc754e887 /src/cryptsetup
parent4d5cc0d45322e71cf02cbef3022ff745e4bb3433 (diff)
downloadsystemd-75a9681ec07bee537d037843781a9ee539e1b7c3.tar.gz
cryptsetup: hook up TPM2 token code with policies based on PCR signatures, too
Diffstat (limited to 'src/cryptsetup')
-rw-r--r--src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c142
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c130
-rw-r--r--src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h18
-rw-r--r--src/cryptsetup/cryptsetup.c3
4 files changed, 114 insertions, 179 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);
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 406369329c..d6e5833b24 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -1396,7 +1396,8 @@ static int attach_luks2_by_tpm2_via_plugin(
#if HAVE_LIBCRYPTSETUP_PLUGINS
systemd_tpm2_plugin_params params = {
.search_pcr_mask = arg_tpm2_pcr_mask,
- .device = arg_tpm2_device
+ .device = arg_tpm2_device,
+ .signature_path = arg_tpm2_signature,
};
if (!libcryptsetup_plugins_support())