Skip to content

Commit

Permalink
cryptenroll: allow specifying handle index of key to use for sealing
Browse files Browse the repository at this point in the history
This defaults to the SRK index.
  • Loading branch information
ddstreet committed Oct 3, 2023
1 parent 639dca0 commit 470d087
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 14 deletions.
20 changes: 20 additions & 0 deletions man/systemd-cryptenroll.xml
Expand Up @@ -411,6 +411,26 @@
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>

<varlistentry>
<term><option>--tpm2-handle=</option><replaceable>HANDLE</replaceable></term>

<listitem><para>Configures which parent key to use for sealing, using the TPM handle of the
key. Expects a hexadecimal 32bit integer, optionally prefixed with <literal>0x</literal>. Allowable
values are any handle index in the persistent (0x81000000-0x81ffffff), transient
(0x80000000-0x80ffffff), or NV (0x01000000-0x01ffffff) ranges. Since transient handles are lost after
a TPM reset, and may be flushed during TPM context switching, they should not be used except for very
specific use cases, e.g. testing.</para>

<para>The default is the Storage Root Key (SRK) handle index <literal>0x81000001</literal>. A value
of 0 will use the default. For the SRK handle, a new key will be created and stored in the TPM if one
does not already exist; for any other handle, the key must already exist in the TPM at the specified
handle index.</para>

<para>This should not be changed unless you know what you are doing.</para>

<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>

<varlistentry>
<term><option>--tpm2-pcrs=</option><arg rep="repeat">PCR</arg></term>

Expand Down
2 changes: 2 additions & 0 deletions src/cryptenroll/cryptenroll-tpm2.c
Expand Up @@ -133,6 +133,7 @@ int enroll_tpm2(struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size,
const char *device,
uint32_t handle,
Tpm2PCRValue *hash_pcr_values,
size_t n_hash_pcr_values,
const char *pubkey_path,
Expand Down Expand Up @@ -252,6 +253,7 @@ int enroll_tpm2(struct crypt_device *cd,
return r;

r = tpm2_seal(tpm2_context,
handle,
&policy,
pin_str,
&secret, &secret_size,
Expand Down
4 changes: 2 additions & 2 deletions src/cryptenroll/cryptenroll-tpm2.h
Expand Up @@ -8,9 +8,9 @@
#include "tpm2-util.h"

#if HAVE_TPM2
int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin);
int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t handle, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin);
#else
static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin) {
static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t handle, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM2 key enrollment not supported.");
}
Expand Down
14 changes: 13 additions & 1 deletion src/cryptenroll/cryptenroll.c
Expand Up @@ -36,6 +36,7 @@ static char *arg_unlock_fido2_device = NULL;
static char *arg_pkcs11_token_uri = NULL;
static char *arg_fido2_device = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_handle = 0;
static Tpm2PCRValue *arg_tpm2_hash_pcr_values = NULL;
static size_t arg_tpm2_n_hash_pcr_values = 0;
static bool arg_tpm2_hash_pcr_values_use_default = true;
Expand Down Expand Up @@ -127,6 +128,8 @@ static int help(void) {
" Whether to require user verification to unlock the volume\n"
" --tpm2-device=PATH\n"
" Enroll a TPM2 device\n"
" --tpm2-handle=HANDLE\n"
" Specify handle of key to use for sealing\n"
" --tpm2-pcrs=PCR1+PCR2+PCR3+…\n"
" Specify TPM2 PCRs to seal against\n"
" --tpm2-public-key=PATH\n"
Expand Down Expand Up @@ -159,6 +162,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PKCS11_TOKEN_URI,
ARG_FIDO2_DEVICE,
ARG_TPM2_DEVICE,
ARG_TPM2_HANDLE,
ARG_TPM2_PCRS,
ARG_TPM2_PUBLIC_KEY,
ARG_TPM2_PUBLIC_KEY_PCRS,
Expand All @@ -185,6 +189,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "fido2-with-user-presence", required_argument, NULL, ARG_FIDO2_WITH_UP },
{ "fido2-with-user-verification", required_argument, NULL, ARG_FIDO2_WITH_UV },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "tpm2-handle", required_argument, NULL, ARG_TPM2_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 },
Expand Down Expand Up @@ -357,6 +362,13 @@ static int parse_argv(int argc, char *argv[]) {
break;
}

case ARG_TPM2_HANDLE:
r = safe_atou32_full(optarg, 16, &arg_tpm2_handle);
if (r < 0)
return log_error_errno(r, "Could not parse TPM2 handle index '%s': %m", optarg);

break;

case ARG_TPM2_PCRS:
arg_tpm2_hash_pcr_values_use_default = false;
r = tpm2_parse_pcr_argument_append(optarg, &arg_tpm2_hash_pcr_values, &arg_tpm2_n_hash_pcr_values);
Expand Down Expand Up @@ -664,7 +676,7 @@ static int run(int argc, char *argv[]) {
break;

case ENROLL_TPM2:
slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, arg_tpm2_public_key, arg_tpm2_public_key_pcr_mask, arg_tpm2_signature, arg_tpm2_pin);
slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_handle, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, arg_tpm2_public_key, arg_tpm2_public_key_pcr_mask, arg_tpm2_signature, arg_tpm2_pin);
break;

case _ENROLL_TYPE_INVALID:
Expand Down
1 change: 1 addition & 0 deletions src/partition/repart.c
Expand Up @@ -3797,6 +3797,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
return log_error_errno(r, "Could not calculate sealing policy digest: %m");

r = tpm2_seal(tpm2_context,
/* handle_index= */ 0,
&policy,
/* pin= */ NULL,
&secret, &secret_size,
Expand Down
1 change: 1 addition & 0 deletions src/shared/creds-util.c
Expand Up @@ -861,6 +861,7 @@ int encrypt_credential_and_warn(
return log_error_errno(r, "Could not calculate sealing policy digest: %m");

r = tpm2_seal(tpm2_context,
/* handle_index= */ 0,
&tpm2_policy,
/* pin= */ NULL,
&tpm2_key, &tpm2_key_size,
Expand Down
42 changes: 32 additions & 10 deletions src/shared/tpm2-util.c
Expand Up @@ -758,7 +758,8 @@ int tpm2_index_to_handle(

assert(c);

/* Let's restrict this, at least for now, to allow only some handle types. */
/* Only allow only some handle types. The man page for systemd-cryptenroll states only persistent,
* transient, and nv handle indexes are allowed, and it relies on this to enforce that. */
switch (TPM2_HANDLE_TYPE(index)) {
case TPM2_HT_PERSISTENT:
case TPM2_HT_NV_INDEX:
Expand Down Expand Up @@ -3931,6 +3932,7 @@ static int tpm2_deserialize(
}

int tpm2_seal(Tpm2Context *c,
uint32_t handle_index,
const TPM2B_DIGEST *policy,
const char *pin,
void **ret_secret,
Expand Down Expand Up @@ -4004,18 +4006,38 @@ int tpm2_seal(Tpm2Context *c,
_cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
if (ret_srk_buf) {
_cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
r = tpm2_get_or_create_srk(
c,
/* session= */ NULL,
&primary_public,
/* ret_name= */ NULL,
/* ret_qname= */ NULL,
&primary_handle);
if (r < 0)
return r;

if (IN_SET(handle_index, 0, TPM2_SRK_HANDLE)) {
r = tpm2_get_or_create_srk(
c,
/* session= */ NULL,
&primary_public,
/* ret_name= */ NULL,
/* ret_qname= */ NULL,
&primary_handle);
if (r < 0)
return r;
} else { /* We do NOT automatically create anything other than the SRK */
r = tpm2_index_to_handle(
c,
handle_index,
/* session= */ NULL,
&primary_public,
/* ret_name= */ NULL,
/* ret_qname= */ NULL,
&primary_handle);
if (r < 0)
return r;
if (r == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
"No handle found at index 0x%" PRIx32, handle_index);
}

primary_alg = primary_public->publicArea.type;
} else {
if (handle_index != 0)
log_debug("Using primary alg sealing, but handle index also provided; ignoring handle index.");

/* TODO: force all callers to provide ret_srk_buf, so we can stop sealing with the legacy templates. */
primary_alg = TPM2_ALG_ECC;

Expand Down
2 changes: 1 addition & 1 deletion src/shared/tpm2-util.h
Expand Up @@ -195,7 +195,7 @@ int tpm2_unmarshal_blob(const void *blob, size_t blob_size, TPM2B_PUBLIC *ret_pu

int tpm2_get_or_create_srk(Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle);

int tpm2_seal(Tpm2Context *c, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
int tpm2_seal(Tpm2Context *c, uint32_t handle_index, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
int tpm2_unseal(Tpm2Context *c, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);

#if HAVE_OPENSSL
Expand Down

0 comments on commit 470d087

Please sign in to comment.