mirror of
https://github.com/systemd/systemd
synced 2024-10-15 12:34:37 +00:00
cryptsetup: hook up signed PCR policies
This commit is contained in:
parent
02ef97cde0
commit
dc63b2c909
|
@ -685,6 +685,21 @@
|
|||
when TPM2 enrollment metadata is not available.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>tpm2-signature=</option></term>
|
||||
|
||||
<listitem><para>Takes an absolute path to a TPM2 PCR JSON signature file, as produced by the
|
||||
<citerefentry><refentrytitle>systemd-measure</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
tool. This permits locking LUKS2 volumes to any PCR values for which a valid signature matching a
|
||||
public key specified at key enrollment time can be provided. See
|
||||
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for details on enrolling TPM2 PCR public keys. If this option is not specified but it is attempted to
|
||||
unlock a LUKS2 volume with a signed TPM2 PCR enrollment a suitable signature file
|
||||
<filename>tpm2-pcr-signature.json</filename> is searched for in <filename>/etc/systemd/</filename>,
|
||||
<filename>/run/systemd/</filename>, <filename>/usr/lib/systemd/</filename> (in this
|
||||
order).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>token-timeout=</option></term>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue