summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-07-08 13:52:21 +0200
committerLennart Poettering <lennart@poettering.net>2021-07-30 19:03:35 +0200
commit07697bfee6988630cdb35887c2f2ca3283001f7a (patch)
treea046271604393d00c5f9dca9490f8f5f668681e2
parent1f0fb7d544711248cba34615e43c5a76bc902d74 (diff)
downloadsystemd-07697bfee6988630cdb35887c2f2ca3283001f7a.tar.gz
tpm2-util: auto-detect supported PCR banks
Previously, we'd encode PCR policies strictly with the SHA256 PCR bank set. However, as it appears not all hw implement those. Sad. Let's add some minimal logic to auto-detect supported PCR banks: if SHA256 is supported, use that. But if not, automatically fall back to SHA1. This then changes both the LUKS code, and the credentials code to serialize the selected bank, along with the rest of the data in order to make this robust. This extends the LUK2 JSON metadata in a compatible way. The credentials encryption format is modified in an incompatible way however, but given that this is not part of any official release should be OK. Fixes: #20134
-rw-r--r--src/cryptenroll/cryptenroll-tpm2.c7
-rw-r--r--src/cryptsetup/cryptsetup-tpm2.c23
-rw-r--r--src/cryptsetup/cryptsetup-tpm2.h4
-rw-r--r--src/cryptsetup/cryptsetup.c4
-rw-r--r--src/partition/repart.c5
-rw-r--r--src/shared/creds-util.c15
-rw-r--r--src/shared/tpm2-util.c147
-rw-r--r--src/shared/tpm2-util.h11
8 files changed, 200 insertions, 16 deletions
diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c
index 9c1478c474..697b4c2335 100644
--- a/src/cryptenroll/cryptenroll-tpm2.c
+++ b/src/cryptenroll/cryptenroll-tpm2.c
@@ -65,6 +65,7 @@ int enroll_tpm2(struct crypt_device *cd,
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
size_t secret_size, secret2_size, blob_size, hash_size;
_cleanup_free_ void *blob = NULL, *hash = NULL;
+ uint16_t pcr_bank;
const char *node;
int r, keyslot;
@@ -75,7 +76,7 @@ int enroll_tpm2(struct crypt_device *cd,
assert_se(node = crypt_get_device_name(cd));
- r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size);
+ r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
if (r < 0)
return r;
@@ -92,7 +93,7 @@ int enroll_tpm2(struct crypt_device *cd,
/* Quick verification that everything is in order, we are not in a hurry after all. */
log_debug("Unsealing for verification...");
- r = tpm2_unseal(device, pcr_mask, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
+ r = tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
if (r < 0)
return r;
@@ -118,7 +119,7 @@ int enroll_tpm2(struct crypt_device *cd,
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
- r = tpm2_make_luks2_json(keyslot, pcr_mask, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c
index 4757c5882d..8da1880a35 100644
--- a/src/cryptsetup/cryptsetup-tpm2.c
+++ b/src/cryptsetup/cryptsetup-tpm2.c
@@ -13,6 +13,7 @@ int acquire_tpm2_key(
const char *volume_name,
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
@@ -62,7 +63,7 @@ int acquire_tpm2_key(
blob = loaded_blob;
}
- return tpm2_unseal(device, pcr_mask, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
+ return tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
}
int find_tpm2_auto_data(
@@ -70,6 +71,7 @@ int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
@@ -81,6 +83,7 @@ int find_tpm2_auto_data(
size_t blob_size = 0, policy_hash_size = 0;
int r, keyslot = -1, token = -1;
uint32_t pcr_mask = 0;
+ uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
assert(cd);
@@ -119,6 +122,23 @@ int find_tpm2_auto_data(
search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
continue;
+ /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded to SHA256 */
+ assert(pcr_bank == UINT16_MAX);
+ w = json_variant_by_key(v, "tpm2-pcr-bank");
+ if (w) {
+ /* The PCR bank field is optional */
+
+ if (!json_variant_is_string(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "TPM2 PCR bank is not a string.");
+
+ r = tpm2_pcr_bank_from_string(json_variant_string(w));
+ if (r < 0)
+ return log_error_errno(r, "TPM2 PCR bank invalid or not supported: %s", json_variant_string(w));
+
+ pcr_bank = r;
+ }
+
assert(!blob);
w = json_variant_by_key(v, "tpm2-blob");
if (!w || !json_variant_is_string(w))
@@ -163,6 +183,7 @@ int find_tpm2_auto_data(
*ret_policy_hash_size = policy_hash_size;
*ret_keyslot = keyslot;
*ret_token = token;
+ *ret_pcr_bank = pcr_bank;
return 0;
}
diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h
index 8ddf301a63..a82ecb4594 100644
--- a/src/cryptsetup/cryptsetup-tpm2.h
+++ b/src/cryptsetup/cryptsetup-tpm2.h
@@ -13,6 +13,7 @@ int acquire_tpm2_key(
const char *volume_name,
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
@@ -28,6 +29,7 @@ int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
@@ -41,6 +43,7 @@ static inline int acquire_tpm2_key(
const char *volume_name,
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
@@ -60,6 +63,7 @@ static inline int find_tpm2_auto_data(
uint32_t search_pcr_mask,
int start_token,
uint32_t *ret_pcr_mask,
+ uint16_t *ret_pcr_bank,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 48621ef583..0d3ea9cda6 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -1103,6 +1103,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
name,
arg_tpm2_device,
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
+ UINT16_MAX,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
NULL, 0, /* we don't know the policy hash */
@@ -1139,12 +1140,14 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
for (;;) {
uint32_t pcr_mask;
+ uint16_t pcr_bank;
r = find_tpm2_auto_data(
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,
+ &pcr_bank,
&blob, &blob_size,
&policy_hash, &policy_hash_size,
&keyslot,
@@ -1166,6 +1169,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
name,
arg_tpm2_device,
pcr_mask,
+ pcr_bank,
NULL, 0, 0, /* no key file */
blob, blob_size,
policy_hash, policy_hash_size,
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 6d535a3bab..42a8260c2e 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -2624,9 +2624,10 @@ static int partition_encrypt(
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_free_ void *blob = NULL, *hash = NULL;
size_t secret_size, blob_size, hash_size;
+ uint16_t pcr_bank;
int keyslot;
- r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size);
+ r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
@@ -2648,7 +2649,7 @@ static int partition_encrypt(
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
- r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c
index 6c2d9dbc76..ee279e0c9c 100644
--- a/src/shared/creds-util.c
+++ b/src/shared/creds-util.c
@@ -369,7 +369,10 @@ struct _packed_ encrypted_credential_header {
};
struct _packed_ tpm2_credential_header {
- le64_t pcr_mask;
+ le64_t pcr_mask; /* Note that the spec for PC Clients only mandates 24 PCRs, and that's what systems
+ * generally have. But keep the door open for more. */
+ le16_t pcr_bank; /* For now, either TPM2_ALG_SHA256 or TPM2_ALG_SHA1 */
+ le16_t _zero; /* Filler to maintain 32bit alignment */
le32_t blob_size;
le32_t policy_hash_size;
uint8_t policy_hash_and_blob[];
@@ -439,6 +442,7 @@ int encrypt_credential_and_warn(
struct encrypted_credential_header *h;
int ksz, bsz, ivsz, tsz, added, r;
uint8_t md[SHA256_DIGEST_LENGTH];
+ uint16_t tpm2_pcr_bank = 0;
const EVP_CIPHER *cc;
#if HAVE_TPM2
bool try_tpm2 = false;
@@ -505,7 +509,8 @@ int encrypt_credential_and_warn(
&tpm2_blob,
&tpm2_blob_size,
&tpm2_policy_hash,
- &tpm2_policy_hash_size);
+ &tpm2_policy_hash_size,
+ &tpm2_pcr_bank);
if (r < 0) {
if (!sd_id128_is_null(with_key))
return r;
@@ -598,6 +603,7 @@ int encrypt_credential_and_warn(
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
t->pcr_mask = htole64(tpm2_pcr_mask);
+ t->pcr_bank = htole16(tpm2_pcr_bank);
t->blob_size = htole32(tpm2_blob_size);
t->policy_hash_size = htole32(tpm2_policy_hash_size);
memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
@@ -739,6 +745,10 @@ int decrypt_credential_and_warn(
if (le64toh(t->pcr_mask) >= (UINT64_C(1) << TPM2_PCRS_MAX))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR mask out of range.");
+ if (!tpm2_pcr_bank_supported(le16toh(t->pcr_bank)))
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR bank invalid or not supported");
+ if (le16toh(t->_zero) != 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 padding space not zero.");
if (le32toh(t->blob_size) > CREDENTIAL_FIELD_SIZE_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 blob size.");
if (le32toh(t->policy_hash_size) > CREDENTIAL_FIELD_SIZE_MAX)
@@ -755,6 +765,7 @@ int decrypt_credential_and_warn(
r = tpm2_unseal(tpm2_device,
le64toh(t->pcr_mask),
+ le16toh(t->pcr_bank),
t->policy_hash_and_blob,
le32toh(t->blob_size),
t->policy_hash_and_blob + le32toh(t->blob_size),
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 79e879b482..5cb6563b43 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -25,6 +25,7 @@ TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR primaryHand
void (*sym_Esys_Finalize)(ESYS_CONTEXT **context) = NULL;
TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle) = NULL;
void (*sym_Esys_Free)(void *ptr) = NULL;
+TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData);
TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes) = NULL;
TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL;
TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL;
@@ -51,6 +52,7 @@ int dlopen_tpm2(void) {
DLSYM_ARG(Esys_Finalize),
DLSYM_ARG(Esys_FlushContext),
DLSYM_ARG(Esys_Free),
+ DLSYM_ARG(Esys_GetCapability),
DLSYM_ARG(Esys_GetRandom),
DLSYM_ARG(Esys_Initialize),
DLSYM_ARG(Esys_Load),
@@ -310,11 +312,93 @@ static int tpm2_make_primary(
return 0;
}
+static int tpm2_get_best_pcr_bank(
+ ESYS_CONTEXT *c,
+ TPMI_ALG_HASH *ret) {
+
+ _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
+ TPMI_ALG_HASH hash = TPM2_ALG_SHA1;
+ bool found = false;
+ TPMI_YES_NO more;
+ TSS2_RC rc;
+
+ rc = sym_Esys_GetCapability(
+ c,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ TPM2_CAP_PCRS,
+ 0,
+ 1,
+ &more,
+ &pcap);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to determine TPM2 PCR bank capabilities: %s", sym_Tss2_RC_Decode(rc));
+
+ assert(pcap->capability == TPM2_CAP_PCRS);
+
+ for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
+ bool valid = true;
+
+ /* As per
+ * https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
+ * TPM2 on a Client PC must have at least 24 PCRs. If this TPM has less, just skip over
+ * it. */
+ if (pcap->data.assignedPCR.pcrSelections[i].sizeofSelect < TPM2_PCRS_MAX/8) {
+ log_debug("Skipping TPM2 PCR bank %s with fewer than 24 PCRs.",
+ strna(tpm2_pcr_bank_to_string(pcap->data.assignedPCR.pcrSelections[i].hash)));
+ continue;
+ }
+
+ assert_cc(TPM2_PCRS_MAX % 8 == 0);
+
+ /* It's not enought to check how many PCRs there are, we also need to check that the 24 are
+ * enabled for this bank. Otherwise this TPM doesn't qualify. */
+ for (size_t j = 0; j < TPM2_PCRS_MAX/8; j++)
+ if (pcap->data.assignedPCR.pcrSelections[i].pcrSelect[j] != 0xFF) {
+ valid = false;
+ break;
+ }
+
+ if (!valid) {
+ log_debug("TPM2 PCR bank %s has fewer than 24 PCR bits enabled, ignoring.",
+ strna(tpm2_pcr_bank_to_string(pcap->data.assignedPCR.pcrSelections[i].hash)));
+ continue;
+ }
+
+ if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA256) {
+ hash = TPM2_ALG_SHA256;
+ found = true;
+ break;
+ }
+
+ if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA1)
+ found = true;
+ }
+
+ if (!found)
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "TPM2 module supports neither SHA1 nor SHA256 PCR banks, cannot operate.");
+
+ if (hash == TPM2_ALG_SHA256)
+ log_debug("TPM2 device supports SHA256 PCR banks, yay!");
+ else {
+ assert(hash == TPM2_ALG_SHA1);
+ log_debug("TPM2 device lacks support for SHA256 PCR banks, falling back to SHA1 banks.");
+ }
+
+ *ret = hash;
+ return 0;
+}
+
static int tpm2_make_pcr_session(
ESYS_CONTEXT *c,
uint32_t pcr_mask,
+ uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
ESYS_TR *ret_session,
- TPM2B_DIGEST **ret_policy_digest) {
+ TPM2B_DIGEST **ret_policy_digest,
+ TPMI_ALG_HASH *ret_pcr_bank) {
static const TPMT_SYM_DEF symmetric = {
.algorithm = TPM2_ALG_AES,
@@ -327,7 +411,7 @@ static int tpm2_make_pcr_session(
};
TPML_PCR_SELECTION pcr_selection = {
.count = 1,
- .pcrSelections[0].hash = TPM2_ALG_SHA256,
+ .pcrSelections[0].hash = TPM2_ALG_SHA256, /* overriden below, depending on TPM2 capabilities */
.pcrSelections[0].sizeofSelect = 3,
.pcrSelections[0].pcrSelect[0] = pcr_mask & 0xFF,
.pcrSelections[0].pcrSelect[1] = (pcr_mask >> 8) & 0xFF,
@@ -342,6 +426,16 @@ static int tpm2_make_pcr_session(
log_debug("Starting authentication session.");
+ if (pcr_bank != UINT16_MAX)
+ pcr_selection.pcrSelections[0].hash = pcr_bank;
+ else {
+ /* No bank configured, pick automatically. Some TPM2 devices only can do SHA1. If we detect
+ * that use that, but preferably use SHA256 */
+ r = tpm2_get_best_pcr_bank(c, &pcr_selection.pcrSelections[0].hash);
+ if (r < 0)
+ return r;
+ }
+
rc = sym_Esys_StartAuthSession(
c,
ESYS_TR_NONE,
@@ -412,6 +506,9 @@ static int tpm2_make_pcr_session(
if (ret_policy_digest)
*ret_policy_digest = TAKE_PTR(policy_digest);
+ if (ret_pcr_bank)
+ *ret_pcr_bank = pcr_selection.pcrSelections[0].hash;
+
r = 0;
finish:
@@ -427,7 +524,8 @@ int tpm2_seal(
void **ret_blob,
size_t *ret_blob_size,
void **ret_pcr_hash,
- size_t *ret_pcr_hash_size) {
+ size_t *ret_pcr_hash_size,
+ uint16_t *ret_pcr_bank) {
_cleanup_(tpm2_context_destroy) struct tpm2_context c = {};
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
@@ -439,6 +537,7 @@ int tpm2_seal(
TPM2B_SENSITIVE_CREATE hmac_sensitive;
ESYS_TR primary = ESYS_TR_NONE;
TPM2B_PUBLIC hmac_template;
+ TPMI_ALG_HASH pcr_bank;
size_t k, blob_size;
usec_t start;
TSS2_RC rc;
@@ -450,6 +549,7 @@ int tpm2_seal(
assert(ret_blob_size);
assert(ret_pcr_hash);
assert(ret_pcr_hash_size);
+ assert(ret_pcr_bank);
assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */
@@ -478,7 +578,7 @@ int tpm2_seal(
if (r < 0)
return r;
- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, NULL, &policy_digest);
+ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, NULL, &policy_digest, &pcr_bank);
if (r < 0)
goto finish;
@@ -600,6 +700,7 @@ int tpm2_seal(
*ret_blob_size = blob_size;
*ret_pcr_hash = TAKE_PTR(hash);
*ret_pcr_hash_size = policy_digest->size;
+ *ret_pcr_bank = pcr_bank;
r = 0;
@@ -611,6 +712,7 @@ finish:
int tpm2_unseal(
const char *device,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const void *blob,
size_t blob_size,
const void *known_policy_hash,
@@ -670,7 +772,7 @@ int tpm2_unseal(
if (r < 0)
return r;
- r = tpm2_make_pcr_session(c.esys_context, pcr_mask, &session, &policy_digest);
+ r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, &session, &policy_digest, NULL);
if (r < 0)
goto finish;
@@ -909,6 +1011,7 @@ int tpm2_parse_pcrs(const char *s, uint32_t *ret) {
int tpm2_make_luks2_json(
int keyslot,
uint32_t pcr_mask,
+ uint16_t pcr_bank,
const void *blob,
size_t blob_size,
const void *policy_hash,
@@ -951,6 +1054,7 @@ int tpm2_make_luks2_json(
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)),
+ JSON_BUILD_PAIR_CONDITION(!!tpm2_pcr_bank_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_pcr_bank_to_string(pcr_bank))),
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size))));
if (r < 0)
return r;
@@ -960,3 +1064,36 @@ int tpm2_make_luks2_json(
return keyslot;
}
+
+/* We want the helpers below to work also if TPM2 libs are not available, hence define these two defines if
+ * they are missing. */
+#ifndef TPM2_ALG_SHA256
+#define TPM2_ALG_SHA256 0xB
+#endif
+
+#ifndef TPM2_ALG_SHA1
+#define TPM2_ALG_SHA1 0x4
+#endif
+
+int tpm2_pcr_bank_supported(uint16_t bank) {
+ /* For now, let's officially only support these two. We can extend this later on, should the need
+ * arise. */
+ return IN_SET(bank, TPM2_ALG_SHA256, TPM2_ALG_SHA1);
+}
+
+const char *tpm2_pcr_bank_to_string(uint16_t bank) {
+ /* Similar here, only support the two for now, we can always extend this later. */
+ if (bank == TPM2_ALG_SHA256)
+ return "sha256";
+ if (bank == TPM2_ALG_SHA1)
+ return "sha1";
+ return NULL;
+}
+
+int tpm2_pcr_bank_from_string(const char *bank) {
+ if (streq_ptr(bank, "sha256"))
+ return TPM2_ALG_SHA256;
+ if (streq_ptr(bank, "sha1"))
+ return TPM2_ALG_SHA1;
+ return -EINVAL;
+}
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
index 9f60fef083..8032afe7b0 100644
--- a/src/shared/tpm2-util.h
+++ b/src/shared/tpm2-util.h
@@ -15,6 +15,7 @@ extern TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR prim
extern void (*sym_Esys_Finalize)(ESYS_CONTEXT **context);
extern TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle);
extern void (*sym_Esys_Free)(void *ptr);
+extern TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData);
extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes);
extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion);
extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle);
@@ -33,8 +34,8 @@ extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], siz
int dlopen_tpm2(void);
-int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size);
-int tpm2_unseal(const char *device, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
+int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank);
+int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size);
#endif
@@ -43,13 +44,17 @@ int tpm2_find_device_auto(int log_level, char **ret);
int tpm2_parse_pcrs(const char *s, uint32_t *ret);
-int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
+int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret);
#define TPM2_PCRS_MAX 24
/* Default to PCR 7 only */
#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7)
+int tpm2_pcr_bank_supported(uint16_t bank);
+const char *tpm2_pcr_bank_to_string(uint16_t bank);
+int tpm2_pcr_bank_from_string(const char *bank);
+
typedef struct {
uint32_t search_pcr_mask;
const char *device;