mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #29426 from ddstreet/tpm2_minor_changes
Minor commits for tpm2
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
FOREACH_ARRAY(curve, c->capability_ecc_curves, c->n_capability_ecc_curves)
|
||||
if (*curve == ecc_curve)
|
||||
return true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return 1;
|
||||
log_debug("TPM does not support ECC curve 0x%" PRIx16 ".", ecc_curve);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Query the TPM for populated handles.
|
||||
@@ -402,6 +428,8 @@ static int tpm2_get_capability_handles(
|
||||
assert(ret_handles);
|
||||
assert(ret_n_handles);
|
||||
|
||||
max = MIN(max, UINT32_MAX);
|
||||
|
||||
while (max > 0) {
|
||||
TPMU_CAPABILITIES capability;
|
||||
r = tpm2_get_capability(c, TPM2_CAP_HANDLES, current, (uint32_t) max, &capability);
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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.");
|
||||
@@ -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,
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 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 */
|
||||
/* 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));
|
||||
|
||||
Reference in New Issue
Block a user