mirror of
https://github.com/systemd/systemd
synced 2026-03-27 17:24:51 +01:00
Compare commits
14 Commits
d7950621d2
...
f90eea7d18
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f90eea7d18 | ||
|
|
c116f23394 | ||
|
|
f4529c4d97 | ||
|
|
d38466bae6 | ||
|
|
321a9d9ee5 | ||
|
|
2b92a67261 | ||
|
|
3f9992d82e | ||
|
|
503994bada | ||
|
|
ecedc48b19 | ||
|
|
981fab5d0a | ||
|
|
18d8a33a37 | ||
|
|
7657ec3eb8 | ||
|
|
7a8685ffef | ||
|
|
2c40a8895e |
4
TODO
4
TODO
@ -83,6 +83,10 @@ Janitorial Clean-ups:
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* in uefi stub: query firmware regarding which PCRs are being used, store that
|
||||||
|
in EFI var. then use this when enrolling TPM2 in cryptsetup to verify that
|
||||||
|
the selected PCRs actually are used by firmware.
|
||||||
|
|
||||||
* rework recursive read-only remount to use new mount API
|
* rework recursive read-only remount to use new mount API
|
||||||
|
|
||||||
* PAM: pick auf one authentication token from credentials
|
* PAM: pick auf one authentication token from credentials
|
||||||
|
|||||||
@ -18,26 +18,25 @@ size_t page_size(void) {
|
|||||||
return pgsz;
|
return pgsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool memeqzero(const void *data, size_t length) {
|
bool memeqbyte(uint8_t byte, const void *data, size_t length) {
|
||||||
/* Does the buffer consist entirely of NULs?
|
/* Does the buffer consist entirely of the same specific byte value?
|
||||||
* Copied from https://github.com/systemd/casync/, copied in turn from
|
* Copied from https://github.com/systemd/casync/, copied in turn from
|
||||||
* https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
|
* https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
|
||||||
* which is licensed CC-0.
|
* which is licensed CC-0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const uint8_t *p = data;
|
const uint8_t *p = data;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
/* Check first 16 bytes manually */
|
/* Check first 16 bytes manually */
|
||||||
for (i = 0; i < 16; i++, length--) {
|
for (size_t i = 0; i < 16; i++, length--) {
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return true;
|
return true;
|
||||||
if (p[i])
|
if (p[i] != byte)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we know first 16 bytes are NUL, memcmp with self. */
|
/* Now we know first 16 bytes match, memcmp() with self. */
|
||||||
return memcmp(data, p + i, length) == 0;
|
return memcmp(data, p + 16, length) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !HAVE_EXPLICIT_BZERO
|
#if !HAVE_EXPLICIT_BZERO
|
||||||
|
|||||||
@ -47,7 +47,9 @@ static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2
|
|||||||
|
|
||||||
#define zero(x) (memzero(&(x), sizeof(x)))
|
#define zero(x) (memzero(&(x), sizeof(x)))
|
||||||
|
|
||||||
bool memeqzero(const void *data, size_t length);
|
bool memeqbyte(uint8_t byte, const void *data, size_t length);
|
||||||
|
|
||||||
|
#define memeqzero(data, length) memeqbyte(0x00, data, length)
|
||||||
|
|
||||||
#define eqzero(x) memeqzero(x, sizeof(x))
|
#define eqzero(x) memeqzero(x, sizeof(x))
|
||||||
|
|
||||||
|
|||||||
@ -235,8 +235,36 @@ static int detect_vm_dmi(void) {
|
|||||||
|
|
||||||
/* The DMI vendor tables in /sys/class/dmi/id don't help us distinguish between Amazon EC2
|
/* The DMI vendor tables in /sys/class/dmi/id don't help us distinguish between Amazon EC2
|
||||||
* virtual machines and bare-metal instances, so we need to look at SMBIOS. */
|
* virtual machines and bare-metal instances, so we need to look at SMBIOS. */
|
||||||
if (r == VIRTUALIZATION_AMAZON && detect_vm_smbios() == SMBIOS_VM_BIT_UNSET)
|
if (r == VIRTUALIZATION_AMAZON) {
|
||||||
return VIRTUALIZATION_NONE;
|
switch (detect_vm_smbios()) {
|
||||||
|
case SMBIOS_VM_BIT_SET:
|
||||||
|
return VIRTUALIZATION_AMAZON;
|
||||||
|
case SMBIOS_VM_BIT_UNSET:
|
||||||
|
return VIRTUALIZATION_NONE;
|
||||||
|
case SMBIOS_VM_BIT_UNKNOWN: {
|
||||||
|
/* The DMI information we are after is only accessible to the root user,
|
||||||
|
* so we fallback to using the product name which is less restricted
|
||||||
|
* to distinguish metal systems from virtualized instances */
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
|
||||||
|
r = read_full_virtual_file("/sys/class/dmi/id/product_name", &s, NULL);
|
||||||
|
/* In EC2, virtualized is much more common than metal, so if for some reason
|
||||||
|
* we fail to read the DMI data, assume we are virtualized. */
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Can't read /sys/class/dmi/id/product_name,"
|
||||||
|
" assuming virtualized: %m");
|
||||||
|
return VIRTUALIZATION_AMAZON;
|
||||||
|
}
|
||||||
|
if (endswith(truncate_nl(s), ".metal")) {
|
||||||
|
log_debug("DMI product name ends with '.metal', assuming no virtualization");
|
||||||
|
return VIRTUALIZATION_NONE;
|
||||||
|
} else
|
||||||
|
return VIRTUALIZATION_AMAZON;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we haven't identified a VM, but the firmware indicates that there is one, indicate as much. We
|
/* If we haven't identified a VM, but the firmware indicates that there is one, indicate as much. We
|
||||||
* have no further information about what it is. */
|
* have no further information about what it is. */
|
||||||
|
|||||||
@ -65,7 +65,7 @@ int enroll_tpm2(struct crypt_device *cd,
|
|||||||
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
||||||
size_t secret_size, secret2_size, blob_size, hash_size;
|
size_t secret_size, secret2_size, blob_size, hash_size;
|
||||||
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
||||||
uint16_t pcr_bank;
|
uint16_t pcr_bank, primary_alg;
|
||||||
const char *node;
|
const char *node;
|
||||||
int r, keyslot;
|
int r, keyslot;
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ int enroll_tpm2(struct crypt_device *cd,
|
|||||||
|
|
||||||
assert_se(node = crypt_get_device_name(cd));
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -93,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. */
|
/* Quick verification that everything is in order, we are not in a hurry after all. */
|
||||||
log_debug("Unsealing for verification...");
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ int enroll_tpm2(struct crypt_device *cd,
|
|||||||
if (keyslot < 0)
|
if (keyslot < 0)
|
||||||
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
|
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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
|
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,7 @@ _public_ int cryptsetup_token_open(
|
|||||||
const char *json;
|
const char *json;
|
||||||
size_t blob_size, policy_hash_size, decrypted_key_size;
|
size_t blob_size, policy_hash_size, decrypted_key_size;
|
||||||
uint32_t pcr_mask;
|
uint32_t pcr_mask;
|
||||||
uint16_t pcr_bank;
|
uint16_t pcr_bank, primary_alg;
|
||||||
systemd_tpm2_plugin_params params = {
|
systemd_tpm2_plugin_params params = {
|
||||||
.search_pcr_mask = UINT32_MAX
|
.search_pcr_mask = UINT32_MAX
|
||||||
};
|
};
|
||||||
@ -78,7 +78,7 @@ _public_ int cryptsetup_token_open(
|
|||||||
if (usrptr)
|
if (usrptr)
|
||||||
params = *(systemd_tpm2_plugin_params *)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)
|
if (r < 0)
|
||||||
return log_debug_open_error(cd, r);
|
return log_debug_open_error(cd, r);
|
||||||
|
|
||||||
@ -95,6 +95,7 @@ _public_ int cryptsetup_token_open(
|
|||||||
r = acquire_luks2_key(
|
r = acquire_luks2_key(
|
||||||
pcr_mask,
|
pcr_mask,
|
||||||
pcr_bank,
|
pcr_bank,
|
||||||
|
primary_alg,
|
||||||
params.device,
|
params.device,
|
||||||
blob,
|
blob,
|
||||||
blob_size,
|
blob_size,
|
||||||
@ -135,7 +136,7 @@ _public_ void cryptsetup_token_dump(
|
|||||||
|
|
||||||
int r;
|
int r;
|
||||||
uint32_t pcr_mask;
|
uint32_t pcr_mask;
|
||||||
uint16_t pcr_bank;
|
uint16_t pcr_bank, primary_alg;
|
||||||
size_t decoded_blob_size;
|
size_t decoded_blob_size;
|
||||||
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL,
|
_cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL,
|
||||||
*pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL;
|
*pcrs_str = NULL, *blob_str = NULL, *policy_hash_str = NULL;
|
||||||
@ -143,7 +144,7 @@ _public_ void cryptsetup_token_dump(
|
|||||||
|
|
||||||
assert(json);
|
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)
|
if (r < 0)
|
||||||
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
|
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
|
||||||
|
|
||||||
@ -167,6 +168,7 @@ _public_ void cryptsetup_token_dump(
|
|||||||
|
|
||||||
crypt_log(cd, "\ttpm2-pcrs: %s\n", strna(pcrs_str));
|
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-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-blob: %s\n", blob_str);
|
||||||
crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str);
|
crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str);
|
||||||
}
|
}
|
||||||
@ -212,7 +214,8 @@ _public_ int cryptsetup_token_validate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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");
|
w = json_variant_by_key(v, "tpm2-pcr-bank");
|
||||||
if (w) {
|
if (w) {
|
||||||
/* The PCR bank field is optional */
|
/* The PCR bank field is optional */
|
||||||
@ -228,6 +231,23 @@ _public_ int cryptsetup_token_validate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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");
|
w = json_variant_by_key(v, "tpm2-blob");
|
||||||
if (!w || !json_variant_is_string(w)) {
|
if (!w || !json_variant_is_string(w)) {
|
||||||
crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-blob' field.");
|
crypt_log_debug(cd, "TPM2 token data lacks 'tpm2-blob' field.");
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
int acquire_luks2_key(
|
int acquire_luks2_key(
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const char *device,
|
const char *device,
|
||||||
const void *key_data,
|
const void *key_data,
|
||||||
size_t key_data_size,
|
size_t key_data_size,
|
||||||
@ -38,6 +39,7 @@ int acquire_luks2_key(
|
|||||||
return tpm2_unseal(
|
return tpm2_unseal(
|
||||||
device,
|
device,
|
||||||
pcr_mask, pcr_bank,
|
pcr_mask, pcr_bank,
|
||||||
|
primary_alg,
|
||||||
key_data, key_data_size,
|
key_data, key_data_size,
|
||||||
policy_hash, policy_hash_size,
|
policy_hash, policy_hash_size,
|
||||||
ret_decrypted_key, ret_decrypted_key_size);
|
ret_decrypted_key, ret_decrypted_key_size);
|
||||||
@ -49,19 +51,21 @@ int parse_luks2_tpm2_data(
|
|||||||
uint32_t search_pcr_mask,
|
uint32_t search_pcr_mask,
|
||||||
uint32_t *ret_pcr_mask,
|
uint32_t *ret_pcr_mask,
|
||||||
uint16_t *ret_pcr_bank,
|
uint16_t *ret_pcr_bank,
|
||||||
|
uint16_t *ret_primary_alg,
|
||||||
char **ret_base64_blob,
|
char **ret_base64_blob,
|
||||||
char **ret_hex_policy_hash) {
|
char **ret_hex_policy_hash) {
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
JsonVariant *w, *e;
|
JsonVariant *w, *e;
|
||||||
uint32_t pcr_mask = 0;
|
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_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
|
||||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
|
||||||
assert(json);
|
assert(json);
|
||||||
assert(ret_pcr_mask);
|
assert(ret_pcr_mask);
|
||||||
assert(ret_pcr_bank);
|
assert(ret_pcr_bank);
|
||||||
|
assert(ret_primary_alg);
|
||||||
assert(ret_base64_blob);
|
assert(ret_base64_blob);
|
||||||
assert(ret_hex_policy_hash);
|
assert(ret_hex_policy_hash);
|
||||||
|
|
||||||
@ -104,6 +108,20 @@ int parse_luks2_tpm2_data(
|
|||||||
pcr_bank = r;
|
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");
|
w = json_variant_by_key(v, "tpm2-blob");
|
||||||
if (!w || !json_variant_is_string(w))
|
if (!w || !json_variant_is_string(w))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -122,6 +140,7 @@ int parse_luks2_tpm2_data(
|
|||||||
|
|
||||||
*ret_pcr_mask = pcr_mask;
|
*ret_pcr_mask = pcr_mask;
|
||||||
*ret_pcr_bank = pcr_bank;
|
*ret_pcr_bank = pcr_bank;
|
||||||
|
*ret_primary_alg = primary_alg;
|
||||||
*ret_base64_blob = TAKE_PTR(base64_blob);
|
*ret_base64_blob = TAKE_PTR(base64_blob);
|
||||||
*ret_hex_policy_hash = TAKE_PTR(hex_policy_hash);
|
*ret_hex_policy_hash = TAKE_PTR(hex_policy_hash);
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ struct crypt_device;
|
|||||||
int acquire_luks2_key(
|
int acquire_luks2_key(
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const char *device,
|
const char *device,
|
||||||
const void *key_data,
|
const void *key_data,
|
||||||
size_t key_data_size,
|
size_t key_data_size,
|
||||||
@ -20,5 +21,6 @@ int parse_luks2_tpm2_data(
|
|||||||
uint32_t search_pcr_mask,
|
uint32_t search_pcr_mask,
|
||||||
uint32_t *ret_pcr_mask,
|
uint32_t *ret_pcr_mask,
|
||||||
uint16_t *ret_pcr_bank,
|
uint16_t *ret_pcr_bank,
|
||||||
|
uint16_t *ret_primary_alg,
|
||||||
char **ret_base64_blob,
|
char **ret_base64_blob,
|
||||||
char **ret_hex_policy_hash);
|
char **ret_hex_policy_hash);
|
||||||
|
|||||||
@ -14,6 +14,7 @@ int acquire_tpm2_key(
|
|||||||
const char *device,
|
const char *device,
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
size_t key_file_size,
|
size_t key_file_size,
|
||||||
uint64_t key_file_offset,
|
uint64_t key_file_offset,
|
||||||
@ -63,7 +64,7 @@ int acquire_tpm2_key(
|
|||||||
blob = loaded_blob;
|
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 find_tpm2_auto_data(
|
||||||
@ -72,6 +73,7 @@ int find_tpm2_auto_data(
|
|||||||
int start_token,
|
int start_token,
|
||||||
uint32_t *ret_pcr_mask,
|
uint32_t *ret_pcr_mask,
|
||||||
uint16_t *ret_pcr_bank,
|
uint16_t *ret_pcr_bank,
|
||||||
|
uint16_t *ret_primary_alg,
|
||||||
void **ret_blob,
|
void **ret_blob,
|
||||||
size_t *ret_blob_size,
|
size_t *ret_blob_size,
|
||||||
void **ret_policy_hash,
|
void **ret_policy_hash,
|
||||||
@ -84,6 +86,7 @@ int find_tpm2_auto_data(
|
|||||||
int r, keyslot = -1, token = -1;
|
int r, keyslot = -1, token = -1;
|
||||||
uint32_t pcr_mask = 0;
|
uint32_t pcr_mask = 0;
|
||||||
uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
|
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);
|
assert(cd);
|
||||||
|
|
||||||
@ -122,8 +125,11 @@ int find_tpm2_auto_data(
|
|||||||
search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
|
search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
|
||||||
continue;
|
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(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");
|
w = json_variant_by_key(v, "tpm2-pcr-bank");
|
||||||
if (w) {
|
if (w) {
|
||||||
/* The PCR bank field is optional */
|
/* The PCR bank field is optional */
|
||||||
@ -139,6 +145,23 @@ int find_tpm2_auto_data(
|
|||||||
pcr_bank = r;
|
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);
|
assert(!blob);
|
||||||
w = json_variant_by_key(v, "tpm2-blob");
|
w = json_variant_by_key(v, "tpm2-blob");
|
||||||
if (!w || !json_variant_is_string(w))
|
if (!w || !json_variant_is_string(w))
|
||||||
@ -184,6 +207,7 @@ int find_tpm2_auto_data(
|
|||||||
*ret_keyslot = keyslot;
|
*ret_keyslot = keyslot;
|
||||||
*ret_token = token;
|
*ret_token = token;
|
||||||
*ret_pcr_bank = pcr_bank;
|
*ret_pcr_bank = pcr_bank;
|
||||||
|
*ret_primary_alg = primary_alg;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ int acquire_tpm2_key(
|
|||||||
const char *device,
|
const char *device,
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
size_t key_file_size,
|
size_t key_file_size,
|
||||||
uint64_t key_file_offset,
|
uint64_t key_file_offset,
|
||||||
@ -30,6 +31,7 @@ int find_tpm2_auto_data(
|
|||||||
int start_token,
|
int start_token,
|
||||||
uint32_t *ret_pcr_mask,
|
uint32_t *ret_pcr_mask,
|
||||||
uint16_t *ret_pcr_bank,
|
uint16_t *ret_pcr_bank,
|
||||||
|
uint16_t *ret_primary_alg,
|
||||||
void **ret_blob,
|
void **ret_blob,
|
||||||
size_t *ret_blob_size,
|
size_t *ret_blob_size,
|
||||||
void **ret_policy_hash,
|
void **ret_policy_hash,
|
||||||
@ -44,6 +46,7 @@ static inline int acquire_tpm2_key(
|
|||||||
const char *device,
|
const char *device,
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const char *key_file,
|
const char *key_file,
|
||||||
size_t key_file_size,
|
size_t key_file_size,
|
||||||
uint64_t key_file_offset,
|
uint64_t key_file_offset,
|
||||||
@ -64,6 +67,7 @@ static inline int find_tpm2_auto_data(
|
|||||||
int start_token,
|
int start_token,
|
||||||
uint32_t *ret_pcr_mask,
|
uint32_t *ret_pcr_mask,
|
||||||
uint16_t *ret_pcr_bank,
|
uint16_t *ret_pcr_bank,
|
||||||
|
uint16_t *ret_primary_alg,
|
||||||
void **ret_blob,
|
void **ret_blob,
|
||||||
size_t *ret_blob_size,
|
size_t *ret_blob_size,
|
||||||
void **ret_policy_hash,
|
void **ret_policy_hash,
|
||||||
|
|||||||
@ -1248,6 +1248,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
arg_tpm2_device,
|
arg_tpm2_device,
|
||||||
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
|
arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask,
|
||||||
UINT16_MAX,
|
UINT16_MAX,
|
||||||
|
0,
|
||||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||||
key_data, key_data_size,
|
key_data, key_data_size,
|
||||||
NULL, 0, /* we don't know the policy hash */
|
NULL, 0, /* we don't know the policy hash */
|
||||||
@ -1284,7 +1285,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint32_t pcr_mask;
|
uint32_t pcr_mask;
|
||||||
uint16_t pcr_bank;
|
uint16_t pcr_bank, primary_alg;
|
||||||
|
|
||||||
r = find_tpm2_auto_data(
|
r = find_tpm2_auto_data(
|
||||||
cd,
|
cd,
|
||||||
@ -1292,6 +1293,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
token, /* search for the token with this index, or any later index than this */
|
token, /* search for the token with this index, or any later index than this */
|
||||||
&pcr_mask,
|
&pcr_mask,
|
||||||
&pcr_bank,
|
&pcr_bank,
|
||||||
|
&primary_alg,
|
||||||
&blob, &blob_size,
|
&blob, &blob_size,
|
||||||
&policy_hash, &policy_hash_size,
|
&policy_hash, &policy_hash_size,
|
||||||
&keyslot,
|
&keyslot,
|
||||||
@ -1314,6 +1316,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
arg_tpm2_device,
|
arg_tpm2_device,
|
||||||
pcr_mask,
|
pcr_mask,
|
||||||
pcr_bank,
|
pcr_bank,
|
||||||
|
primary_alg,
|
||||||
NULL, 0, 0, /* no key file */
|
NULL, 0, 0, /* no key file */
|
||||||
blob, blob_size,
|
blob, blob_size,
|
||||||
policy_hash, policy_hash_size,
|
policy_hash, policy_hash_size,
|
||||||
|
|||||||
@ -436,42 +436,46 @@ static int address_add(Link *link, const Address *in, Address **ret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int address_update(Address *address, const Address *src) {
|
static int address_update(Address *address, const Address *src) {
|
||||||
bool ready;
|
Link *link;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(address);
|
assert(address);
|
||||||
assert(address->link);
|
assert(address->link);
|
||||||
assert(src);
|
assert(src);
|
||||||
|
|
||||||
ready = address_is_ready(address);
|
link = address->link;
|
||||||
|
|
||||||
address->flags = src->flags;
|
address->flags = src->flags;
|
||||||
address->scope = src->scope;
|
address->scope = src->scope;
|
||||||
address->cinfo = src->cinfo;
|
address->cinfo = src->cinfo;
|
||||||
|
|
||||||
if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
if (address_is_ready(address) &&
|
||||||
return 0;
|
address->family == AF_INET6 &&
|
||||||
|
in6_addr_is_link_local(&address->in_addr.in6) &&
|
||||||
|
in6_addr_is_null(&link->ipv6ll_address)) {
|
||||||
|
|
||||||
link_update_operstate(address->link, true);
|
link->ipv6ll_address = address->in_addr.in6;
|
||||||
link_check_ready(address->link);
|
|
||||||
|
|
||||||
if (!ready && address_is_ready(address)) {
|
r = link_ipv6ll_gained(link);
|
||||||
if (address->callback) {
|
if (r < 0)
|
||||||
r = address->callback(address);
|
return r;
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address->family == AF_INET6 &&
|
|
||||||
in6_addr_is_link_local(&address->in_addr.in6) > 0 &&
|
|
||||||
in6_addr_is_null(&address->link->ipv6ll_address)) {
|
|
||||||
|
|
||||||
r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = address_set_masquerade(address, true);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
|
||||||
|
|
||||||
|
if (address_is_ready(address) && address->callback) {
|
||||||
|
r = address->callback(address);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
link_update_operstate(link, true);
|
||||||
|
link_check_ready(link);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,7 +882,7 @@ int link_drop_foreign_addresses(Link *link) {
|
|||||||
|
|
||||||
SET_FOREACH(address, link->addresses_foreign) {
|
SET_FOREACH(address, link->addresses_foreign) {
|
||||||
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
|
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
|
||||||
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1)
|
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (link_address_is_dynamic(link, address)) {
|
if (link_address_is_dynamic(link, address)) {
|
||||||
@ -911,8 +915,8 @@ int link_drop_addresses(Link *link) {
|
|||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->addresses) {
|
||||||
/* we consider IPv6LL addresses to be managed by the kernel */
|
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
|
||||||
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6) == 1 && link_ipv6ll_enabled(link))
|
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
k = address_remove(address, link);
|
k = address_remove(address, link);
|
||||||
@ -1288,10 +1292,6 @@ int request_process_address(Request *req) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = address_set_masquerade(a, true);
|
|
||||||
if (r < 0)
|
|
||||||
log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,12 +14,13 @@
|
|||||||
|
|
||||||
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
|
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
|
||||||
|
|
||||||
|
typedef struct Address Address;
|
||||||
typedef struct Manager Manager;
|
typedef struct Manager Manager;
|
||||||
typedef struct Network Network;
|
typedef struct Network Network;
|
||||||
typedef struct Request Request;
|
typedef struct Request Request;
|
||||||
typedef int (*address_ready_callback_t)(Address *address);
|
typedef int (*address_ready_callback_t)(Address *address);
|
||||||
|
|
||||||
typedef struct Address {
|
struct Address {
|
||||||
Network *network;
|
Network *network;
|
||||||
NetworkConfigSection *section;
|
NetworkConfigSection *section;
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ typedef struct Address {
|
|||||||
|
|
||||||
/* Called when address become ready */
|
/* Called when address become ready */
|
||||||
address_ready_callback_t callback;
|
address_ready_callback_t callback;
|
||||||
} Address;
|
};
|
||||||
|
|
||||||
const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_result_;
|
const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) _warn_unused_result_;
|
||||||
/* Note: the lifetime of the compound literal is the immediately surrounding block,
|
/* Note: the lifetime of the compound literal is the immediately surrounding block,
|
||||||
|
|||||||
@ -701,24 +701,21 @@ static int link_acquire_dynamic_conf(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
|
int link_ipv6ll_gained(Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
log_link_info(link, "Gained IPv6LL");
|
log_link_info(link, "Gained IPv6LL");
|
||||||
|
|
||||||
link->ipv6ll_address = *address;
|
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = link_acquire_dynamic_ipv6_conf(link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
link_check_ready(link);
|
link_check_ready(link);
|
||||||
|
|
||||||
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
|
|
||||||
r = link_acquire_dynamic_ipv6_conf(link);
|
|
||||||
if (r < 0) {
|
|
||||||
link_enter_failed(link);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -236,7 +236,7 @@ bool link_has_carrier(Link *link);
|
|||||||
|
|
||||||
bool link_ipv6_enabled(Link *link);
|
bool link_ipv6_enabled(Link *link);
|
||||||
bool link_ipv6ll_enabled(Link *link);
|
bool link_ipv6ll_enabled(Link *link);
|
||||||
int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
|
int link_ipv6ll_gained(Link *link);
|
||||||
|
|
||||||
bool link_ipv4ll_enabled(Link *link);
|
bool link_ipv4ll_enabled(Link *link);
|
||||||
|
|
||||||
|
|||||||
@ -2618,10 +2618,10 @@ static int partition_encrypt(
|
|||||||
_cleanup_(erase_and_freep) void *secret = NULL;
|
_cleanup_(erase_and_freep) void *secret = NULL;
|
||||||
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
||||||
size_t secret_size, blob_size, hash_size;
|
size_t secret_size, blob_size, hash_size;
|
||||||
uint16_t pcr_bank;
|
uint16_t pcr_bank, primary_alg;
|
||||||
int keyslot;
|
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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to seal to TPM2: %m");
|
return log_error_errno(r, "Failed to seal to TPM2: %m");
|
||||||
|
|
||||||
@ -2643,7 +2643,7 @@ static int partition_encrypt(
|
|||||||
if (keyslot < 0)
|
if (keyslot < 0)
|
||||||
return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
|
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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
|
return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m");
|
||||||
|
|
||||||
|
|||||||
@ -371,10 +371,10 @@ struct _packed_ encrypted_credential_header {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct _packed_ tpm2_credential_header {
|
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
|
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. */
|
* 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 pcr_bank; /* For now, either TPM2_ALG_SHA256 or TPM2_ALG_SHA1 */
|
||||||
le16_t _zero; /* Filler to maintain 32bit alignment */
|
le16_t primary_alg; /* Primary key algorithm (either TPM2_ALG_RSA or TPM2_ALG_ECC for now) */
|
||||||
le32_t blob_size;
|
le32_t blob_size;
|
||||||
le32_t policy_hash_size;
|
le32_t policy_hash_size;
|
||||||
uint8_t policy_hash_and_blob[];
|
uint8_t policy_hash_and_blob[];
|
||||||
@ -441,10 +441,10 @@ int encrypt_credential_and_warn(
|
|||||||
size_t host_key_size = 0, tpm2_key_size = 0, tpm2_blob_size = 0, tpm2_policy_hash_size = 0, output_size, p, ml;
|
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_ void *tpm2_blob = NULL, *tpm2_policy_hash = NULL, *iv = NULL, *output = NULL;
|
||||||
_cleanup_free_ struct metadata_credential_header *m = NULL;
|
_cleanup_free_ struct metadata_credential_header *m = NULL;
|
||||||
|
uint16_t tpm2_pcr_bank = 0, tpm2_primary_alg = 0;
|
||||||
struct encrypted_credential_header *h;
|
struct encrypted_credential_header *h;
|
||||||
int ksz, bsz, ivsz, tsz, added, r;
|
int ksz, bsz, ivsz, tsz, added, r;
|
||||||
uint8_t md[SHA256_DIGEST_LENGTH];
|
uint8_t md[SHA256_DIGEST_LENGTH];
|
||||||
uint16_t tpm2_pcr_bank = 0;
|
|
||||||
const EVP_CIPHER *cc;
|
const EVP_CIPHER *cc;
|
||||||
#if HAVE_TPM2
|
#if HAVE_TPM2
|
||||||
bool try_tpm2 = false;
|
bool try_tpm2 = false;
|
||||||
@ -512,7 +512,8 @@ int encrypt_credential_and_warn(
|
|||||||
&tpm2_blob_size,
|
&tpm2_blob_size,
|
||||||
&tpm2_policy_hash,
|
&tpm2_policy_hash,
|
||||||
&tpm2_policy_hash_size,
|
&tpm2_policy_hash_size,
|
||||||
&tpm2_pcr_bank);
|
&tpm2_pcr_bank,
|
||||||
|
&tpm2_primary_alg);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (!sd_id128_is_null(with_key))
|
if (!sd_id128_is_null(with_key))
|
||||||
return r;
|
return r;
|
||||||
@ -606,6 +607,7 @@ int encrypt_credential_and_warn(
|
|||||||
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
|
t = (struct tpm2_credential_header*) ((uint8_t*) output + p);
|
||||||
t->pcr_mask = htole64(tpm2_pcr_mask);
|
t->pcr_mask = htole64(tpm2_pcr_mask);
|
||||||
t->pcr_bank = htole16(tpm2_pcr_bank);
|
t->pcr_bank = htole16(tpm2_pcr_bank);
|
||||||
|
t->primary_alg = htole16(tpm2_primary_alg);
|
||||||
t->blob_size = htole32(tpm2_blob_size);
|
t->blob_size = htole32(tpm2_blob_size);
|
||||||
t->policy_hash_size = htole32(tpm2_policy_hash_size);
|
t->policy_hash_size = htole32(tpm2_policy_hash_size);
|
||||||
memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
|
memcpy(t->policy_hash_and_blob, tpm2_blob, tpm2_blob_size);
|
||||||
@ -747,10 +749,10 @@ int decrypt_credential_and_warn(
|
|||||||
|
|
||||||
if (le64toh(t->pcr_mask) >= (UINT64_C(1) << TPM2_PCRS_MAX))
|
if (le64toh(t->pcr_mask) >= (UINT64_C(1) << TPM2_PCRS_MAX))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR mask out of range.");
|
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");
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 PCR bank invalid or not supported");
|
||||||
if (le16toh(t->_zero) != 0)
|
if (!tpm2_primary_alg_to_string(le16toh(t->primary_alg)))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 padding space not zero.");
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "TPM2 primary key algorithm invalid or not supported.");
|
||||||
if (le32toh(t->blob_size) > CREDENTIAL_FIELD_SIZE_MAX)
|
if (le32toh(t->blob_size) > CREDENTIAL_FIELD_SIZE_MAX)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 blob size.");
|
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected TPM2 blob size.");
|
||||||
if (le32toh(t->policy_hash_size) > CREDENTIAL_FIELD_SIZE_MAX)
|
if (le32toh(t->policy_hash_size) > CREDENTIAL_FIELD_SIZE_MAX)
|
||||||
@ -768,6 +770,7 @@ int decrypt_credential_and_warn(
|
|||||||
r = tpm2_unseal(tpm2_device,
|
r = tpm2_unseal(tpm2_device,
|
||||||
le64toh(t->pcr_mask),
|
le64toh(t->pcr_mask),
|
||||||
le16toh(t->pcr_bank),
|
le16toh(t->pcr_bank),
|
||||||
|
le16toh(t->primary_alg),
|
||||||
t->policy_hash_and_blob,
|
t->policy_hash_and_blob,
|
||||||
le32toh(t->blob_size),
|
le32toh(t->blob_size),
|
||||||
t->policy_hash_and_blob + le32toh(t->blob_size),
|
t->policy_hash_and_blob + le32toh(t->blob_size),
|
||||||
|
|||||||
@ -29,6 +29,7 @@ TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, E
|
|||||||
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_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_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;
|
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;
|
||||||
|
TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues);
|
||||||
TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL;
|
TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL;
|
||||||
TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL;
|
TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL;
|
||||||
TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL;
|
TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL;
|
||||||
@ -56,6 +57,7 @@ int dlopen_tpm2(void) {
|
|||||||
DLSYM_ARG(Esys_GetRandom),
|
DLSYM_ARG(Esys_GetRandom),
|
||||||
DLSYM_ARG(Esys_Initialize),
|
DLSYM_ARG(Esys_Initialize),
|
||||||
DLSYM_ARG(Esys_Load),
|
DLSYM_ARG(Esys_Load),
|
||||||
|
DLSYM_ARG(Esys_PCR_Read),
|
||||||
DLSYM_ARG(Esys_PolicyGetDigest),
|
DLSYM_ARG(Esys_PolicyGetDigest),
|
||||||
DLSYM_ARG(Esys_PolicyPCR),
|
DLSYM_ARG(Esys_PolicyPCR),
|
||||||
DLSYM_ARG(Esys_StartAuthSession),
|
DLSYM_ARG(Esys_StartAuthSession),
|
||||||
@ -257,10 +259,12 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) {
|
|||||||
|
|
||||||
static int tpm2_make_primary(
|
static int tpm2_make_primary(
|
||||||
ESYS_CONTEXT *c,
|
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_SENSITIVE_CREATE primary_sensitive = {};
|
||||||
static const TPM2B_PUBLIC primary_template = {
|
static const TPM2B_PUBLIC primary_template_ecc = {
|
||||||
.size = sizeof(TPMT_PUBLIC),
|
.size = sizeof(TPMT_PUBLIC),
|
||||||
.publicArea = {
|
.publicArea = {
|
||||||
.type = TPM2_ALG_ECC,
|
.type = TPM2_ALG_ECC,
|
||||||
@ -280,48 +284,207 @@ static int tpm2_make_primary(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
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 = {};
|
static const TPML_PCR_SELECTION creation_pcr = {};
|
||||||
ESYS_TR primary = ESYS_TR_NONE;
|
ESYS_TR primary = ESYS_TR_NONE;
|
||||||
TSS2_RC rc;
|
TSS2_RC rc;
|
||||||
|
usec_t ts;
|
||||||
|
|
||||||
log_debug("Creating primary key on TPM.");
|
log_debug("Creating primary key on TPM.");
|
||||||
|
|
||||||
rc = sym_Esys_CreatePrimary(
|
/* So apparently not all TPM2 devices support ECC. ECC is generally preferably, because it's so much
|
||||||
c,
|
* faster, noticeably so (~10s vs. ~240ms on my system). Hence, unless explicitly configured let's
|
||||||
ESYS_TR_RH_OWNER,
|
* try to use ECC first, and if that does not work, let's fall back to RSA. */
|
||||||
ESYS_TR_PASSWORD,
|
|
||||||
ESYS_TR_NONE,
|
|
||||||
ESYS_TR_NONE,
|
|
||||||
&primary_sensitive,
|
|
||||||
&primary_template,
|
|
||||||
NULL,
|
|
||||||
&creation_pcr,
|
|
||||||
&primary,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (rc != TSS2_RC_SUCCESS)
|
ts = now(CLOCK_MONOTONIC);
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
||||||
"Failed to generate primary key in TPM: %s", sym_Tss2_RC_Decode(rc));
|
|
||||||
|
|
||||||
log_debug("Successfully created primary key on TPM.");
|
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("Generating primary key on TPM2 took %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
|
||||||
|
|
||||||
*ret_primary = primary;
|
*ret_primary = primary;
|
||||||
|
if (ret_alg)
|
||||||
|
*ret_alg = alg;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tpm2_pcr_mask_to_selecion(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret) {
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
/* We only do 24bit here, as that's what PC TPMs are supposed to support */
|
||||||
|
assert(mask <= 0xFFFFFFU);
|
||||||
|
|
||||||
|
*ret = (TPML_PCR_SELECTION) {
|
||||||
|
.count = 1,
|
||||||
|
.pcrSelections[0].hash = bank,
|
||||||
|
.pcrSelections[0].sizeofSelect = 3,
|
||||||
|
.pcrSelections[0].pcrSelect[0] = mask & 0xFF,
|
||||||
|
.pcrSelections[0].pcrSelect[1] = (mask >> 8) & 0xFF,
|
||||||
|
.pcrSelections[0].pcrSelect[2] = (mask >> 16) & 0xFF,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned find_nth_bit(uint32_t mask, unsigned n) {
|
||||||
|
uint32_t bit = 1;
|
||||||
|
|
||||||
|
assert(n < 32);
|
||||||
|
|
||||||
|
/* Returns the bit index of the nth set bit, e.g. mask=0b101001, n=3 → 5 */
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sizeof(mask)*8; i++) {
|
||||||
|
|
||||||
|
if (bit & mask) {
|
||||||
|
if (n == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tpm2_pcr_mask_good(
|
||||||
|
ESYS_CONTEXT *c,
|
||||||
|
TPMI_ALG_HASH bank,
|
||||||
|
uint32_t mask) {
|
||||||
|
|
||||||
|
_cleanup_(Esys_Freep) TPML_DIGEST *pcr_values = NULL;
|
||||||
|
TPML_PCR_SELECTION selection;
|
||||||
|
bool good = false;
|
||||||
|
TSS2_RC rc;
|
||||||
|
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
/* So we have the problem that some systems might have working TPM2 chips, but the firmware doesn't
|
||||||
|
* actually measure into them, or only into a suboptimal bank. If so, the PCRs should be all zero or
|
||||||
|
* all 0xFF. Detect that, so that we can warn and maybe pick a better bank. */
|
||||||
|
|
||||||
|
tpm2_pcr_mask_to_selecion(mask, bank, &selection);
|
||||||
|
|
||||||
|
rc = sym_Esys_PCR_Read(
|
||||||
|
c,
|
||||||
|
ESYS_TR_NONE,
|
||||||
|
ESYS_TR_NONE,
|
||||||
|
ESYS_TR_NONE,
|
||||||
|
&selection,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&pcr_values);
|
||||||
|
if (rc != TSS2_RC_SUCCESS)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||||
|
"Failed to read TPM2 PCRs: %s", sym_Tss2_RC_Decode(rc));
|
||||||
|
|
||||||
|
/* If at least one of the selected PCR values is something other than all 0x00 or all 0xFF we are happy. */
|
||||||
|
for (unsigned i = 0; i < pcr_values->count; i++) {
|
||||||
|
if (DEBUG_LOGGING) {
|
||||||
|
_cleanup_free_ char *h = NULL;
|
||||||
|
unsigned j;
|
||||||
|
|
||||||
|
h = hexmem(pcr_values->digests[i].buffer, pcr_values->digests[i].size);
|
||||||
|
j = find_nth_bit(mask, i);
|
||||||
|
assert(j != UINT_MAX);
|
||||||
|
|
||||||
|
log_debug("PCR %u value: %s", j, strna(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memeqbyte(0x00, pcr_values->digests[i].buffer, pcr_values->digests[i].size) &&
|
||||||
|
!memeqbyte(0xFF, pcr_values->digests[i].buffer, pcr_values->digests[i].size))
|
||||||
|
good = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return good;
|
||||||
|
}
|
||||||
|
|
||||||
static int tpm2_get_best_pcr_bank(
|
static int tpm2_get_best_pcr_bank(
|
||||||
ESYS_CONTEXT *c,
|
ESYS_CONTEXT *c,
|
||||||
|
uint32_t pcr_mask,
|
||||||
TPMI_ALG_HASH *ret) {
|
TPMI_ALG_HASH *ret) {
|
||||||
|
|
||||||
_cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
|
_cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
|
||||||
TPMI_ALG_HASH hash = TPM2_ALG_SHA1;
|
TPMI_ALG_HASH supported_hash = 0, hash_with_valid_pcr = 0;
|
||||||
bool found = false;
|
|
||||||
TPMI_YES_NO more;
|
TPMI_YES_NO more;
|
||||||
TSS2_RC rc;
|
TSS2_RC rc;
|
||||||
|
|
||||||
|
assert(c);
|
||||||
|
|
||||||
rc = sym_Esys_GetCapability(
|
rc = sym_Esys_GetCapability(
|
||||||
c,
|
c,
|
||||||
ESYS_TR_NONE,
|
ESYS_TR_NONE,
|
||||||
@ -340,6 +503,11 @@ static int tpm2_get_best_pcr_bank(
|
|||||||
|
|
||||||
for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
|
for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
|
int good;
|
||||||
|
|
||||||
|
/* For now we are only interested in the SHA1 and SHA256 banks */
|
||||||
|
if (!IN_SET(pcap->data.assignedPCR.pcrSelections[i].hash, TPM2_ALG_SHA256, TPM2_ALG_SHA1))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* As per
|
/* As per
|
||||||
* https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
|
* https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
|
||||||
@ -367,28 +535,58 @@ static int tpm2_get_best_pcr_bank(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA256) {
|
good = tpm2_pcr_mask_good(c, pcap->data.assignedPCR.pcrSelections[i].hash, pcr_mask);
|
||||||
hash = TPM2_ALG_SHA256;
|
if (good < 0)
|
||||||
found = true;
|
return good;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA1)
|
if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA256) {
|
||||||
found = true;
|
supported_hash = TPM2_ALG_SHA256;
|
||||||
|
if (good) {
|
||||||
|
/* Great, SHA256 is supported and has initialized PCR values, we are done. */
|
||||||
|
hash_with_valid_pcr = TPM2_ALG_SHA256;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA1);
|
||||||
|
|
||||||
|
if (supported_hash == 0)
|
||||||
|
supported_hash = TPM2_ALG_SHA1;
|
||||||
|
|
||||||
|
if (good && hash_with_valid_pcr == 0)
|
||||||
|
hash_with_valid_pcr = TPM2_ALG_SHA1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
/* We preferably pick SHA256, but only if its PCRs are initialized or neither the SHA1 nor the SHA256
|
||||||
|
* PCRs are initialized. If SHA256 is not supported but SHA1 is and its PCRs are too, we prefer
|
||||||
|
* SHA1.
|
||||||
|
*
|
||||||
|
* We log at LOG_NOTICE level whenever we end up using the SHA1 bank or when the PCRs we bind to are
|
||||||
|
* not initialized. */
|
||||||
|
|
||||||
|
if (hash_with_valid_pcr == TPM2_ALG_SHA256) {
|
||||||
|
assert(supported_hash == TPM2_ALG_SHA256);
|
||||||
|
log_debug("TPM2 device supports SHA256 PCR bank and SHA256 PCRs are valid, yay!");
|
||||||
|
*ret = TPM2_ALG_SHA256;
|
||||||
|
} else if (hash_with_valid_pcr == TPM2_ALG_SHA1) {
|
||||||
|
if (supported_hash == TPM2_ALG_SHA256)
|
||||||
|
log_notice("TPM2 device supports both SHA1 and SHA256 PCR banks, but only SHA1 PCRs are valid, falling back to SHA1 bank. This reduces the security level substantially.");
|
||||||
|
else {
|
||||||
|
assert(supported_hash == TPM2_ALG_SHA1);
|
||||||
|
log_notice("TPM2 device lacks support for SHA256 PCR bank, but SHA1 bank is supported and SHA1 PCRs are valid, falling back to SHA1 bank. This reduces the security level substantially.");
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = TPM2_ALG_SHA1;
|
||||||
|
} else if (supported_hash == TPM2_ALG_SHA256) {
|
||||||
|
log_notice("TPM2 device supports SHA256 PCR bank but none of the selected PCRs are valid! Firmware apparently did not initialize any of the selected PCRs. Proceeding anyway with SHA256 bank. PCR policy effectively unenforced!");
|
||||||
|
*ret = TPM2_ALG_SHA256;
|
||||||
|
} else if (supported_hash == TPM2_ALG_SHA1) {
|
||||||
|
log_notice("TPM2 device lacks support for SHA256 bank, but SHA1 bank is supported, but none of the selected PCRs are valid! Firmware apparently did not initialize any of the selected PCRs. Proceeding anyway with SHA1 bank. PCR policy effectively unenforced!");
|
||||||
|
*ret = TPM2_ALG_SHA1;
|
||||||
|
} else
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"TPM2 module supports neither SHA1 nor SHA256 PCR banks, cannot operate.");
|
"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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,15 +607,8 @@ static int tpm2_make_pcr_session(
|
|||||||
.aes = TPM2_ALG_CFB,
|
.aes = TPM2_ALG_CFB,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TPML_PCR_SELECTION pcr_selection = {
|
|
||||||
.count = 1,
|
|
||||||
.pcrSelections[0].hash = TPM2_ALG_SHA256, /* overridden below, depending on TPM2 capabilities */
|
|
||||||
.pcrSelections[0].sizeofSelect = 3,
|
|
||||||
.pcrSelections[0].pcrSelect[0] = pcr_mask & 0xFF,
|
|
||||||
.pcrSelections[0].pcrSelect[1] = (pcr_mask >> 8) & 0xFF,
|
|
||||||
.pcrSelections[0].pcrSelect[2] = (pcr_mask >> 16) & 0xFF,
|
|
||||||
};
|
|
||||||
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
||||||
|
TPML_PCR_SELECTION pcr_selection;
|
||||||
ESYS_TR session = ESYS_TR_NONE;
|
ESYS_TR session = ESYS_TR_NONE;
|
||||||
TSS2_RC rc;
|
TSS2_RC rc;
|
||||||
int r;
|
int r;
|
||||||
@ -426,14 +617,24 @@ static int tpm2_make_pcr_session(
|
|||||||
|
|
||||||
log_debug("Starting authentication session.");
|
log_debug("Starting authentication session.");
|
||||||
|
|
||||||
if (pcr_bank != UINT16_MAX)
|
if (pcr_bank != UINT16_MAX) {
|
||||||
pcr_selection.pcrSelections[0].hash = pcr_bank;
|
r = tpm2_pcr_mask_good(c, pcr_bank, pcr_mask);
|
||||||
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
log_notice("Selected TPM2 PCRs are not initialized on this system, most likely due to a firmware issue. PCR policy is effectively not enforced. Proceeding anyway.");
|
||||||
|
|
||||||
|
tpm2_pcr_mask_to_selecion(pcr_mask, pcr_bank, &pcr_selection);
|
||||||
|
} else {
|
||||||
|
TPMI_ALG_HASH h;
|
||||||
|
|
||||||
|
/* 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_mask, &h);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
tpm2_pcr_mask_to_selecion(pcr_mask, h, &pcr_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sym_Esys_StartAuthSession(
|
rc = sym_Esys_StartAuthSession(
|
||||||
@ -525,7 +726,8 @@ int tpm2_seal(
|
|||||||
size_t *ret_blob_size,
|
size_t *ret_blob_size,
|
||||||
void **ret_pcr_hash,
|
void **ret_pcr_hash,
|
||||||
size_t *ret_pcr_hash_size,
|
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_(tpm2_context_destroy) struct tpm2_context c = {};
|
||||||
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
||||||
@ -536,6 +738,7 @@ int tpm2_seal(
|
|||||||
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
||||||
TPM2B_SENSITIVE_CREATE hmac_sensitive;
|
TPM2B_SENSITIVE_CREATE hmac_sensitive;
|
||||||
ESYS_TR primary = ESYS_TR_NONE;
|
ESYS_TR primary = ESYS_TR_NONE;
|
||||||
|
TPMI_ALG_PUBLIC primary_alg;
|
||||||
TPM2B_PUBLIC hmac_template;
|
TPM2B_PUBLIC hmac_template;
|
||||||
TPMI_ALG_HASH pcr_bank;
|
TPMI_ALG_HASH pcr_bank;
|
||||||
size_t k, blob_size;
|
size_t k, blob_size;
|
||||||
@ -555,13 +758,14 @@ int tpm2_seal(
|
|||||||
|
|
||||||
/* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
|
/* 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
|
* 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
|
* generate a "primary" key pair derived from that (ECC if possible, RSA as fallback). Given the seed
|
||||||
* result in the same key pair whenever we specify the exact same parameters for it. We then create a
|
* remains fixed this will result in the same key pair whenever we specify the exact same parameters
|
||||||
* PCR-bound policy session, which calculates a hash on the current PCR values of the indexes we
|
* for it. We then create a PCR-bound policy session, which calculates a hash on the current PCR
|
||||||
* specify. We then generate a randomized key on the host (which is the key we actually enroll in the
|
* values of the indexes we specify. We then generate a randomized key on the host (which is the key
|
||||||
* LUKS2 keyslots), which we upload into the TPM2, where it is encrypted with the "primary" key,
|
* we actually enroll in the LUKS2 keyslots), which we upload into the TPM2, where it is encrypted
|
||||||
* taking the PCR policy session into account. We then download the encrypted key from the TPM2
|
* with the "primary" key, taking the PCR policy session into account. We then download the encrypted
|
||||||
* ("sealing") and marshall it into binary form, which is ultimately placed in the LUKS2 JSON header.
|
* 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
|
* 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
|
* all). The random key we enroll in LUKS2 we generate on the host using the Linux random device. It
|
||||||
@ -574,7 +778,7 @@ int tpm2_seal(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = tpm2_make_primary(c.esys_context, &primary);
|
r = tpm2_make_primary(c.esys_context, &primary, 0, &primary_alg);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -701,6 +905,7 @@ int tpm2_seal(
|
|||||||
*ret_pcr_hash = TAKE_PTR(hash);
|
*ret_pcr_hash = TAKE_PTR(hash);
|
||||||
*ret_pcr_hash_size = policy_digest->size;
|
*ret_pcr_hash_size = policy_digest->size;
|
||||||
*ret_pcr_bank = pcr_bank;
|
*ret_pcr_bank = pcr_bank;
|
||||||
|
*ret_primary_alg = primary_alg;
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
@ -713,6 +918,7 @@ int tpm2_unseal(
|
|||||||
const char *device,
|
const char *device,
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const void *blob,
|
const void *blob,
|
||||||
size_t blob_size,
|
size_t blob_size,
|
||||||
const void *known_policy_hash,
|
const void *known_policy_hash,
|
||||||
@ -783,7 +989,7 @@ int tpm2_unseal(
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
|
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
|
||||||
"Current policy digest does not match stored policy digest, cancelling TPM2 authentication attempt.");
|
"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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1012,6 +1218,7 @@ int tpm2_make_luks2_json(
|
|||||||
int keyslot,
|
int keyslot,
|
||||||
uint32_t pcr_mask,
|
uint32_t pcr_mask,
|
||||||
uint16_t pcr_bank,
|
uint16_t pcr_bank,
|
||||||
|
uint16_t primary_alg,
|
||||||
const void *blob,
|
const void *blob,
|
||||||
size_t blob_size,
|
size_t blob_size,
|
||||||
const void *policy_hash,
|
const void *policy_hash,
|
||||||
@ -1055,6 +1262,7 @@ int tpm2_make_luks2_json(
|
|||||||
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
|
JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
|
||||||
JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)),
|
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_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))));
|
JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size))));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1065,24 +1273,9 @@ int tpm2_make_luks2_json(
|
|||||||
return keyslot;
|
return keyslot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We want the helpers below to work also if TPM2 libs are not available, hence define these two defines if
|
const char *tpm2_pcr_bank_to_string(uint16_t bank) {
|
||||||
* 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
|
/* For now, let's officially only support these two. We can extend this later on, should the need
|
||||||
* arise. */
|
* 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)
|
if (bank == TPM2_ALG_SHA256)
|
||||||
return "sha256";
|
return "sha256";
|
||||||
if (bank == TPM2_ALG_SHA1)
|
if (bank == TPM2_ALG_SHA1)
|
||||||
@ -1097,3 +1290,19 @@ int tpm2_pcr_bank_from_string(const char *bank) {
|
|||||||
return TPM2_ALG_SHA1;
|
return TPM2_ALG_SHA1;
|
||||||
return -EINVAL;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ extern TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shan
|
|||||||
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_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_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);
|
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);
|
||||||
|
extern TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues);
|
||||||
extern TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest);
|
extern TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest);
|
||||||
extern TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs);
|
extern TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs);
|
||||||
extern TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle);
|
extern TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle);
|
||||||
@ -34,8 +35,8 @@ extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], siz
|
|||||||
|
|
||||||
int dlopen_tpm2(void);
|
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_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, 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_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
|
#endif
|
||||||
|
|
||||||
@ -44,17 +45,37 @@ int tpm2_find_device_auto(int log_level, char **ret);
|
|||||||
|
|
||||||
int tpm2_parse_pcrs(const char *s, uint32_t *ret);
|
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
|
#define TPM2_PCRS_MAX 24
|
||||||
|
|
||||||
/* Default to PCR 7 only */
|
/* Default to PCR 7 only */
|
||||||
#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7)
|
#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);
|
const char *tpm2_pcr_bank_to_string(uint16_t bank);
|
||||||
int tpm2_pcr_bank_from_string(const char *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 {
|
typedef struct {
|
||||||
uint32_t search_pcr_mask;
|
uint32_t search_pcr_mask;
|
||||||
const char *device;
|
const char *device;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user