_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;
+ uint16_t pcr_bank, primary_alg;
const char *node;
int r, keyslot;
assert_se(node = crypt_get_device_name(cd));
- r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
+ r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg);
if (r < 0)
return r;
/* 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, pcr_bank, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
+ r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &secret2, &secret2_size);
if (r < 0)
return r;
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, pcr_bank, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
const char *json;
size_t blob_size, policy_hash_size, decrypted_key_size;
uint32_t pcr_mask;
- uint16_t pcr_bank;
+ uint16_t pcr_bank, primary_alg;
systemd_tpm2_plugin_params params = {
.search_pcr_mask = UINT32_MAX
};
if (usrptr)
params = *(systemd_tpm2_plugin_params *)usrptr;
- r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &base64_blob, &hex_policy_hash);
+ r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash);
if (r < 0)
return log_debug_open_error(cd, r);
r = acquire_luks2_key(
pcr_mask,
pcr_bank,
+ primary_alg,
params.device,
blob,
blob_size,
int r;
uint32_t pcr_mask;
- uint16_t pcr_bank;
+ uint16_t pcr_bank, primary_alg;
size_t decoded_blob_size;
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL,
*pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL;
assert(json);
- r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &base64_blob, &hex_policy_hash);
+ r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash);
if (r < 0)
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
crypt_log(cd, "\ttpm2-pcrs: %s\n", strna(pcrs_str));
crypt_log(cd, "\ttpm2-bank: %s\n", strna(tpm2_pcr_bank_to_string(pcr_bank)));
+ crypt_log(cd, "\ttpm2-primary-alg: %s\n", strna(tpm2_primary_alg_to_string(primary_alg)));
crypt_log(cd, "\ttpm2-blob: %s\n", blob_str);
crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str);
}
}
}
- /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded to SHA256 */
+ /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded
+ * to SHA256. */
w = json_variant_by_key(v, "tpm2-pcr-bank");
if (w) {
/* The PCR bank field is optional */
}
}
+ /* The primary key algorithm field is optional, since it was also added in systemd 250 only. Before
+ * the algorithm was hardcoded to ECC. */
+ w = json_variant_by_key(v, "tpm2-primary-alg");
+ if (w) {
+ /* The primary key algorithm is optional */
+
+ if (!json_variant_is_string(w)) {
+ crypt_log_debug(cd, "TPM2 primary key algorithm is not a string.");
+ return 1;
+ }
+
+ if (tpm2_primary_alg_from_string(json_variant_string(w)) < 0) {
+ crypt_log_debug(cd, "TPM2 primary key algorithm invalid or not supported: %s", json_variant_string(w));
+ return 1;
+ }
+ }
+
w = json_variant_by_key(v, "tpm2-blob");
if (!w || !json_variant_is_string(w)) {
crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-blob' field.");
int acquire_luks2_key(
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const char *device,
const void *key_data,
size_t key_data_size,
return tpm2_unseal(
device,
pcr_mask, pcr_bank,
+ primary_alg,
key_data, key_data_size,
policy_hash, policy_hash_size,
ret_decrypted_key, ret_decrypted_key_size);
uint32_t search_pcr_mask,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
+ uint16_t *ret_primary_alg,
char **ret_base64_blob,
char **ret_hex_policy_hash) {
int r;
JsonVariant *w, *e;
uint32_t pcr_mask = 0;
- uint16_t pcr_bank = UINT16_MAX;
+ uint16_t pcr_bank = UINT16_MAX, primary_alg = TPM2_ALG_ECC;
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
assert(json);
assert(ret_pcr_mask);
assert(ret_pcr_bank);
+ assert(ret_primary_alg);
assert(ret_base64_blob);
assert(ret_hex_policy_hash);
pcr_bank = r;
}
+ w = json_variant_by_key(v, "tpm2-primary-alg");
+ if (w) {
+ /* The primary key algorithm is optional */
+
+ if (!json_variant_is_string(w))
+ return -EINVAL;
+
+ r = tpm2_primary_alg_from_string(json_variant_string(w));
+ if (r < 0)
+ return r;
+
+ primary_alg = r;
+ }
+
w = json_variant_by_key(v, "tpm2-blob");
if (!w || !json_variant_is_string(w))
return -EINVAL;
*ret_pcr_mask = pcr_mask;
*ret_pcr_bank = pcr_bank;
+ *ret_primary_alg = primary_alg;
*ret_base64_blob = TAKE_PTR(base64_blob);
*ret_hex_policy_hash = TAKE_PTR(hex_policy_hash);
int acquire_luks2_key(
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const char *device,
const void *key_data,
size_t key_data_size,
uint32_t search_pcr_mask,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
+ uint16_t *ret_primary_alg,
char **ret_base64_blob,
char **ret_hex_policy_hash);
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
blob = loaded_blob;
}
- return tpm2_unseal(device, pcr_mask, pcr_bank, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
+ return tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size);
}
int find_tpm2_auto_data(
int start_token,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
+ uint16_t *ret_primary_alg,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
int r, keyslot = -1, token = -1;
uint32_t 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 */
assert(cd);
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);
+ assert(primary_alg == TPM2_ALG_ECC);
+
+ /* The bank field is optional, since it was added in systemd 250 only. Before the bank was
+ * hardcoded to SHA256. */
w = json_variant_by_key(v, "tpm2-pcr-bank");
if (w) {
/* The PCR bank field is optional */
pcr_bank = r;
}
+ /* The primary key algorithm field is optional, since it was also added in systemd 250
+ * only. Before the algorithm was hardcoded to ECC. */
+ w = json_variant_by_key(v, "tpm2-primary-alg");
+ if (w) {
+ /* The primary key algorithm is optional */
+
+ if (!json_variant_is_string(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "TPM2 primary key algorithm is not a string.");
+
+ r = tpm2_primary_alg_from_string(json_variant_string(w));
+ if (r < 0)
+ return log_error_errno(r, "TPM2 primary key algorithm invalid or not supported: %s", json_variant_string(w));
+
+ primary_alg = r;
+ }
+
assert(!blob);
w = json_variant_by_key(v, "tpm2-blob");
if (!w || !json_variant_is_string(w))
*ret_keyslot = keyslot;
*ret_token = token;
*ret_pcr_bank = pcr_bank;
+ *ret_primary_alg = primary_alg;
return 0;
}
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
int start_token,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
+ uint16_t *ret_primary_alg,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
int start_token,
uint32_t *ret_pcr_mask,
uint16_t *ret_pcr_bank,
+ uint16_t *ret_primary_alg,
void **ret_blob,
size_t *ret_blob_size,
void **ret_policy_hash,
arg_tpm2_device,
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
UINT16_MAX,
+ 0,
key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data_size,
NULL, 0, /* we don't know the policy hash */
for (;;) {
uint32_t pcr_mask;
- uint16_t pcr_bank;
+ uint16_t pcr_bank, primary_alg;
r = find_tpm2_auto_data(
cd,
token, /* search for the token with this index, or any later index than this */
&pcr_mask,
&pcr_bank,
+ &primary_alg,
&blob, &blob_size,
&policy_hash, &policy_hash_size,
&keyslot,
arg_tpm2_device,
pcr_mask,
pcr_bank,
+ primary_alg,
NULL, 0, 0, /* no key file */
blob, blob_size,
policy_hash, policy_hash_size,
_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;
+ uint16_t pcr_bank, primary_alg;
int keyslot;
- r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank);
+ r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg);
if (r < 0)
return log_error_errno(r, "Failed to seal to TPM2: %m");
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, pcr_bank, blob, blob_size, hash, hash_size, &v);
+ r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v);
if (r < 0)
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
};
struct _packed_ tpm2_credential_header {
- 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 */
+ 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 primary_alg; /* Primary key algorithm (either TPM2_ALG_RSA or TPM2_ALG_ECC for now) */
le32_t blob_size;
le32_t policy_hash_size;
uint8_t policy_hash_and_blob[];
size_t host_key_size = 0, tpm2_key_size = 0, tpm2_blob_size = 0, tpm2_policy_hash_size = 0, output_size, p, ml;
_cleanup_free_ void *tpm2_blob = NULL, *tpm2_policy_hash = NULL, *iv = NULL, *output = NULL;
_cleanup_free_ struct metadata_credential_header *m = NULL;
+ uint16_t tpm2_pcr_bank = 0, tpm2_primary_alg = 0;
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;
&tpm2_blob_size,
&tpm2_policy_hash,
&tpm2_policy_hash_size,
- &tpm2_pcr_bank);
+ &tpm2_pcr_bank,
+ &tpm2_primary_alg);
if (r < 0) {
if (!sd_id128_is_null(with_key))
return r;
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
t->pcr_mask = htole64(tpm2_pcr_mask);
t->pcr_bank = htole16(tpm2_pcr_bank);
+ t->primary_alg = htole16(tpm2_primary_alg);
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);
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)))
+ if (!tpm2_pcr_bank_to_string(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 (!tpm2_primary_alg_to_string(le16toh(t->primary_alg)))
+ return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 primary key algorithm invalid or not supported.");
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)
r = tpm2_unseal(tpm2_device,
le64toh(t->pcr_mask),
le16toh(t->pcr_bank),
+ le16toh(t->primary_alg),
t->policy_hash_and_blob,
le32toh(t->blob_size),
t->policy_hash_and_blob + le32toh(t->blob_size),
static int tpm2_make_primary(
ESYS_CONTEXT *c,
- ESYS_TR *ret_primary) {
+ ESYS_TR *ret_primary,
+ TPMI_ALG_PUBLIC alg,
+ TPMI_ALG_PUBLIC *ret_alg) {
static const TPM2B_SENSITIVE_CREATE primary_sensitive = {};
- static const TPM2B_PUBLIC primary_template = {
+ static const TPM2B_PUBLIC primary_template_ecc = {
.size = sizeof(TPMT_PUBLIC),
.publicArea = {
.type = TPM2_ALG_ECC,
},
},
};
+ static const TPM2B_PUBLIC primary_template_rsa = {
+ .size = sizeof(TPMT_PUBLIC),
+ .publicArea = {
+ .type = TPM2_ALG_RSA,
+ .nameAlg = TPM2_ALG_SHA256,
+ .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
+ .parameters = {
+ .rsaDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
+ },
+ .scheme.scheme = TPM2_ALG_NULL,
+ .keyBits = 2048,
+ },
+ },
+ },
+ };
+
static const TPML_PCR_SELECTION creation_pcr = {};
ESYS_TR primary = ESYS_TR_NONE;
TSS2_RC rc;
+ usec_t ts;
log_debug("Creating primary key on TPM.");
- rc = sym_Esys_CreatePrimary(
- c,
- ESYS_TR_RH_OWNER,
- ESYS_TR_PASSWORD,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- &primary_sensitive,
- &primary_template,
- NULL,
- &creation_pcr,
- &primary,
- NULL,
- NULL,
- NULL,
- NULL);
+ /* So apparently not all TPM2 devices support ECC. ECC is generally preferably, because it's so much
+ * faster, noticeably so (~10s vs. ~240ms on my system). Hence, unless explicitly configured let's
+ * try to use ECC first, and if that does not work, let's fall back to RSA. */
- if (rc != TSS2_RC_SUCCESS)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to generate primary key in TPM: %s", sym_Tss2_RC_Decode(rc));
+ ts = now(CLOCK_MONOTONIC);
+
+ if (IN_SET(alg, 0, TPM2_ALG_ECC)) {
+ rc = sym_Esys_CreatePrimary(
+ c,
+ ESYS_TR_RH_OWNER,
+ ESYS_TR_PASSWORD,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ &primary_sensitive,
+ &primary_template_ecc,
+ NULL,
+ &creation_pcr,
+ &primary,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (rc != TSS2_RC_SUCCESS) {
+ if (alg != 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to generate ECC primary key in TPM: %s", sym_Tss2_RC_Decode(rc));
+
+ log_debug("Failed to generate ECC primary key in TPM, trying RSA: %s", sym_Tss2_RC_Decode(rc));
+ } else {
+ log_debug("Successfully created ECC primary key on TPM.");
+ alg = TPM2_ALG_ECC;
+ }
+ }
+
+ if (IN_SET(alg, 0, TPM2_ALG_RSA)) {
+ rc = sym_Esys_CreatePrimary(
+ c,
+ ESYS_TR_RH_OWNER,
+ ESYS_TR_PASSWORD,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ &primary_sensitive,
+ &primary_template_rsa,
+ NULL,
+ &creation_pcr,
+ &primary,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to generate RSA primary key in TPM: %s", sym_Tss2_RC_Decode(rc));
+ else if (alg == 0) {
+ log_notice("TPM2 chip apparently does not support ECC primary keys, falling back to RSA. "
+ "This likely means TPM2 operations will be relatively slow, please be patient.");
+ alg = TPM2_ALG_RSA;
+ }
+
+ log_debug("Successfully created RSA primary key on TPM.");
+ }
- log_debug("Successfully created primary key on TPM.");
+ log_debug("Generating primary key on TPM2 took %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
*ret_primary = primary;
+ if (ret_alg)
+ *ret_alg = alg;
+
return 0;
}
size_t *ret_blob_size,
void **ret_pcr_hash,
size_t *ret_pcr_hash_size,
- uint16_t *ret_pcr_bank) {
+ uint16_t *ret_pcr_bank,
+ uint16_t *ret_primary_alg) {
_cleanup_(tpm2_context_destroy) struct tpm2_context c = {};
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
_cleanup_free_ void *blob = NULL, *hash = NULL;
TPM2B_SENSITIVE_CREATE hmac_sensitive;
ESYS_TR primary = ESYS_TR_NONE;
+ TPMI_ALG_PUBLIC primary_alg;
TPM2B_PUBLIC hmac_template;
TPMI_ALG_HASH pcr_bank;
size_t k, blob_size;
/* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
* is randomized when the TPM2 is first initialized or reset and remains stable across boots. We
- * generate a "primary" key pair derived from that (RSA). Given the seed remains fixed this will
- * result in the same key pair whenever we specify the exact same parameters for it. We then create a
- * PCR-bound policy session, which calculates a hash on the current PCR values of the indexes we
- * specify. We then generate a randomized key on the host (which is the key we actually enroll in the
- * LUKS2 keyslots), which we upload into the TPM2, where it is encrypted with the "primary" key,
- * taking the PCR policy session into account. We then download the encrypted key from the TPM2
- * ("sealing") and marshall it into binary form, which is ultimately placed in the LUKS2 JSON header.
+ * generate a "primary" key pair derived from that (ECC if possible, RSA as fallback). Given the seed
+ * remains fixed this will result in the same key pair whenever we specify the exact same parameters
+ * for it. We then create a PCR-bound policy session, which calculates a hash on the current PCR
+ * values of the indexes we specify. We then generate a randomized key on the host (which is the key
+ * we actually enroll in the LUKS2 keyslots), which we upload into the TPM2, where it is encrypted
+ * with the "primary" key, taking the PCR policy session into account. We then download the encrypted
+ * key from the TPM2 ("sealing") and marshall it into binary form, which is ultimately placed in the
+ * LUKS2 JSON header.
*
* The TPM2 "seed" key and "primary" keys never leave the TPM2 chip (and cannot be extracted at
* all). The random key we enroll in LUKS2 we generate on the host using the Linux random device. It
if (r < 0)
return r;
- r = tpm2_make_primary(c.esys_context, &primary);
+ r = tpm2_make_primary(c.esys_context, &primary, 0, &primary_alg);
if (r < 0)
return r;
*ret_pcr_hash = TAKE_PTR(hash);
*ret_pcr_hash_size = policy_digest->size;
*ret_pcr_bank = pcr_bank;
+ *ret_primary_alg = primary_alg;
r = 0;
const char *device,
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const void *blob,
size_t blob_size,
const void *known_policy_hash,
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
"Current policy digest does not match stored policy digest, cancelling TPM2 authentication attempt.");
- r = tpm2_make_primary(c.esys_context, &primary);
+ r = tpm2_make_primary(c.esys_context, &primary, primary_alg, NULL);
if (r < 0)
return r;
int keyslot,
uint32_t pcr_mask,
uint16_t pcr_bank,
+ uint16_t primary_alg,
const void *blob,
size_t blob_size,
const void *policy_hash,
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_CONDITION(!!tpm2_primary_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_primary_alg_to_string(primary_alg))),
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size))));
if (r < 0)
return r;
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) {
+const char *tpm2_pcr_bank_to_string(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 TPM2_ALG_SHA1;
return -EINVAL;
}
+
+const char *tpm2_primary_alg_to_string(uint16_t alg) {
+ if (alg == TPM2_ALG_ECC)
+ return "ecc";
+ if (alg == TPM2_ALG_RSA)
+ return "rsa";
+ return NULL;
+}
+
+int tpm2_primary_alg_from_string(const char *alg) {
+ if (streq_ptr(alg, "ecc"))
+ return TPM2_ALG_ECC;
+ if (streq_ptr(alg, "rsa"))
+ return TPM2_ALG_RSA;
+ return -EINVAL;
+}
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, 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);
+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, uint16_t *ret_primary_alg);
+int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, 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
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, size_t policy_hash_size, JsonVariant **ret);
+int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, 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);
+/* We want the helpers below to work also if TPM2 libs are not available, hence define these four 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
+
+#ifndef TPM2_ALG_ECC
+#define TPM2_ALG_ECC 0x23
+#endif
+
+#ifndef TPM2_ALG_RSA
+#define TPM2_ALG_RSA 0x1
+#endif
+
const char *tpm2_pcr_bank_to_string(uint16_t bank);
int tpm2_pcr_bank_from_string(const char *bank);
+const char *tpm2_primary_alg_to_string(uint16_t bank);
+int tpm2_primary_alg_from_string(const char *alg);
+
typedef struct {
uint32_t search_pcr_mask;
const char *device;