Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor commits for tpm2 #29426

Merged
merged 5 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cryptenroll/cryptenroll-tpm2.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ int enroll_tpm2(struct crypt_device *cd,
size_t secret2_size;

log_debug("Unsealing for verification...");
r = tpm2_unseal(device,
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
hash_pcr_bank,
pubkey, pubkey_size,
Expand Down
7 changes: 6 additions & 1 deletion src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ int acquire_luks2_key(
return log_error_errno(r, "Failed to load PCR signature: %m");
}

r = tpm2_unseal(device,
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
r = tpm2_context_new(device, &tpm2_context);
if (r < 0)
return log_error_errno(r, "Failed to create TPM2 context: %m");

r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
pcr_bank,
pubkey, pubkey_size,
Expand Down
9 changes: 7 additions & 2 deletions src/cryptsetup/cryptsetup-tpm2.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,13 @@ int acquire_tpm2_key(
return log_error_errno(r, "Failed to load pcr signature: %m");
}

_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
r = tpm2_context_new(device, &tpm2_context);
if (r < 0)
return log_error_errno(r, "Failed to create TPM2 context: %m");

if (!(flags & TPM2_FLAGS_USE_PIN)) {
r = tpm2_unseal(device,
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
pcr_bank,
pubkey, pubkey_size,
Expand Down Expand Up @@ -177,7 +182,7 @@ int acquire_tpm2_key(
/* no salting needed, backwards compat with non-salted pins */
b64_salted_pin = TAKE_PTR(pin_str);

r = tpm2_unseal(device,
r = tpm2_unseal(tpm2_context,
hash_pcr_mask,
pcr_bank,
pubkey, pubkey_size,
Expand Down
7 changes: 6 additions & 1 deletion src/shared/creds-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1203,9 +1203,14 @@ int decrypt_credential_and_warn(
le32toh(z->size));
}

_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
r = tpm2_context_new(tpm2_device, &tpm2_context);
if (r < 0)
return r;

// TODO: Add the SRK data to the credential structure so it can be plumbed
// through and used to verify the TPM session.
r = tpm2_unseal(tpm2_device,
r = tpm2_unseal(tpm2_context,
le64toh(t->pcr_mask),
le16toh(t->pcr_bank),
z ? z->data : NULL,
Expand Down
80 changes: 49 additions & 31 deletions src/shared/tpm2-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,39 @@ static int tpm2_cache_capabilities(Tpm2Context *c) {
current_cc = TPMA_CC_TO_TPM2_CC(commands.commandAttributes[commands.count - 1]) + 1;
}

/* Cache the ECC curves. The spec isn't actually clear if ECC curves can be added/removed
* while running, but that would be crazy, so let's hope it is not possible. */
TPM2_ECC_CURVE current_ecc_curve = TPM2_ECC_NONE;
for (;;) {
r = tpm2_get_capability(
c,
TPM2_CAP_ECC_CURVES,
current_ecc_curve,
TPM2_MAX_ECC_CURVES,
&capability);
if (r < 0)
return r;

TPML_ECC_CURVE ecc_curves = capability.eccCurves;

/* ECC support isn't required */
if (ecc_curves.count == 0)
break;

if (!GREEDY_REALLOC_APPEND(
c->capability_ecc_curves,
c->n_capability_ecc_curves,
ecc_curves.eccCurves,
ecc_curves.count))
return log_oom_debug();

if (r == 0)
break;

/* Set current_ecc_curve to index after last ecc curve the TPM provided */
current_ecc_curve = ecc_curves.eccCurves[ecc_curves.count - 1] + 1;
}

/* Cache the PCR capabilities, which are safe to cache, as the only way they can change is
* TPM2_PCR_Allocate(), which changes the allocation after the next _TPM_Init(). If the TPM is
* reinitialized while we are using it, all our context and sessions will be invalid, so we can
Expand Down Expand Up @@ -358,23 +391,16 @@ bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command) {
return tpm2_get_capability_command(c, command, NULL);
}

/* Returns 1 if the TPM supports the ECC curve, 0 if not, or < 0 for any error. */
static int tpm2_supports_ecc_curve(Tpm2Context *c, TPM2_ECC_CURVE curve) {
TPMU_CAPABILITIES capability;
int r;

/* The spec explicitly states the TPM2_ECC_CURVE should be cast to uint32_t. */
r = tpm2_get_capability(c, TPM2_CAP_ECC_CURVES, (uint32_t) curve, 1, &capability);
if (r < 0)
return r;
/* Returns true if the TPM supports the ECC curve, otherwise false. */
bool tpm2_supports_ecc_curve(Tpm2Context *c, TPM2_ECC_CURVE ecc_curve) {
assert(c);

TPML_ECC_CURVE eccCurves = capability.eccCurves;
if (eccCurves.count == 0 || eccCurves.eccCurves[0] != curve) {
log_debug("TPM does not support ECC curve 0x%02" PRIx16 ".", curve);
return 0;
}
FOREACH_ARRAY(curve, c->capability_ecc_curves, c->n_capability_ecc_curves)
if (*curve == ecc_curve)
return true;

return 1;
log_debug("TPM does not support ECC curve 0x%" PRIx16 ".", ecc_curve);
return false;
}

/* Query the TPM for populated handles.
Expand Down Expand Up @@ -402,6 +428,8 @@ static int tpm2_get_capability_handles(
assert(ret_handles);
assert(ret_n_handles);

max = MIN(max, UINT32_MAX);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it make more sense to leave "max" as is is, but simply reduce the range passed to tpm2_get_capability(). i.e. allow ridiculous sizes to be returned if people ask for it, but never pass them to the tpm2 apis?

i.e. drop this line here, but instead change the 4th param of tpm2_get_capability() below to do MIN(max, UINT32_MAX)?


while (max > 0) {
TPMU_CAPABILITIES capability;
r = tpm2_get_capability(c, TPM2_CAP_HANDLES, current, (uint32_t) max, &capability);
Expand All @@ -417,13 +445,10 @@ static int tpm2_get_capability_handles(
if (n_handles > SIZE_MAX - handle_list.count)
return log_oom_debug();

if (!GREEDY_REALLOC(handles, n_handles + handle_list.count))
if (!GREEDY_REALLOC_APPEND(handles, n_handles, handle_list.handle, handle_list.count))
return log_oom_debug();

memcpy_safe(&handles[n_handles], handle_list.handle, sizeof(handles[0]) * handle_list.count);

max -= handle_list.count;
n_handles += handle_list.count;

/* Update current to the handle index after the last handle in the list. */
current = handles[n_handles - 1] + 1;
Expand Down Expand Up @@ -523,6 +548,7 @@ static Tpm2Context *tpm2_context_free(Tpm2Context *c) {

c->capability_algorithms = mfree(c->capability_algorithms);
c->capability_commands = mfree(c->capability_commands);
c->capability_ecc_curves = mfree(c->capability_ecc_curves);

return mfree(c);
}
Expand Down Expand Up @@ -2854,6 +2880,7 @@ static int tpm2_make_encryption_session(
int r;

assert(c);
assert(primary);
assert(ret_session);

log_debug("Starting HMAC encryption session.");
Expand All @@ -2869,7 +2896,7 @@ static int tpm2_make_encryption_session(
rc = sym_Esys_StartAuthSession(
c->esys_context,
primary->esys_handle,
bind_key->esys_handle,
bind_key ? bind_key->esys_handle : ESYS_TR_NONE,
ESYS_TR_NONE,
ESYS_TR_NONE,
ESYS_TR_NONE,
Expand Down Expand Up @@ -4021,7 +4048,7 @@ int tpm2_seal(Tpm2Context *c,
}

_cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
r = tpm2_make_encryption_session(c, primary_handle, &TPM2_HANDLE_NONE, &encryption_session);
r = tpm2_make_encryption_session(c, primary_handle, /* bind_key= */ NULL, &encryption_session);
if (r < 0)
return r;

Expand Down Expand Up @@ -4081,7 +4108,7 @@ int tpm2_seal(Tpm2Context *c,

#define RETRY_UNSEAL_MAX 30u

int tpm2_unseal(const char *device,
int tpm2_unseal(Tpm2Context *c,
uint32_t hash_pcr_mask,
uint16_t pcr_bank,
const void *pubkey,
Expand Down Expand Up @@ -4112,10 +4139,6 @@ int tpm2_unseal(const char *device,
assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));

r = dlopen_tpm2();
if (r < 0)
return r;

/* So here's what we do here: We connect to the TPM2 chip. As we do when sealing we generate a
* "primary" key on the TPM2 chip, with the same parameters as well as a PCR-bound policy session.
* Given we pass the same parameters, this will result in the same "primary" key, and same policy
Expand All @@ -4132,11 +4155,6 @@ int tpm2_unseal(const char *device,
if (r < 0)
return log_debug_errno(r, "Could not extract parts from blob: %m");

_cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
r = tpm2_context_new(device, &c);
if (r < 0)
return r;

/* Older code did not save the pcr_bank, and unsealing needed to detect the best pcr bank to use,
* so we need to handle that legacy situation. */
if (pcr_bank == UINT16_MAX) {
Expand Down
5 changes: 4 additions & 1 deletion src/shared/tpm2-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ typedef struct {
size_t n_capability_algorithms;
TPMA_CC *capability_commands;
size_t n_capability_commands;
TPM2_ECC_CURVE *capability_ecc_curves;
size_t n_capability_ecc_curves;
TPML_PCR_SELECTION capability_pcrs;
} Tpm2Context;

Expand Down Expand Up @@ -107,6 +109,7 @@ int tpm2_create_loaded(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handl

bool tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg);
bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command);
bool tpm2_supports_ecc_curve(Tpm2Context *c, TPM2_ECC_CURVE ecc_curve);

bool tpm2_test_parms(Tpm2Context *c, TPMI_ALG_PUBLIC alg, const TPMU_PUBLIC_PARMS *parms);

Expand Down Expand Up @@ -193,7 +196,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_unseal(const char *device, 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);
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
int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret);
Expand Down
17 changes: 12 additions & 5 deletions src/test/test-tpm2.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,11 +987,18 @@ TEST(tpm_required_tests) {
assert_se(tpm2_supports_alg(c, TPM2_ALG_AES));
assert_se(tpm2_supports_alg(c, TPM2_ALG_CFB));

/* Test invalid commands */
assert_se(!tpm2_supports_command(c, TPM2_CC_FIRST - 1));
assert_se(!tpm2_supports_command(c, TPM2_CC_LAST + 1));

/* Test valid commands */
/* Test invalid commands. TPM specification Part 2 ("Structures") section "TPM_CC (Command Codes)"
* states bits 31:30 and 28:16 are reserved and must be 0. */
assert_se(!tpm2_supports_command(c, UINT32_C(0x80000000)));
assert_se(!tpm2_supports_command(c, UINT32_C(0x40000000)));
assert_se(!tpm2_supports_command(c, UINT32_C(0x00100000)));
assert_se(!tpm2_supports_command(c, UINT32_C(0x80000144)));
assert_se(!tpm2_supports_command(c, UINT32_C(0x40000144)));
assert_se(!tpm2_supports_command(c, UINT32_C(0x00100144)));

/* Test valid commands. We should be able to expect all TPMs support these. */
assert_se(tpm2_supports_command(c, TPM2_CC_Startup));
assert_se(tpm2_supports_command(c, TPM2_CC_StartAuthSession));
assert_se(tpm2_supports_command(c, TPM2_CC_Create));
assert_se(tpm2_supports_command(c, TPM2_CC_CreatePrimary));
assert_se(tpm2_supports_command(c, TPM2_CC_Unseal));
Expand Down