diff --git a/docs/TPM2_NVINDEX_ASSIGNMENTS.md b/docs/TPM2_NVINDEX_ASSIGNMENTS.md new file mode 100644 index 00000000000..ef603f30be0 --- /dev/null +++ b/docs/TPM2_NVINDEX_ASSIGNMENTS.md @@ -0,0 +1,70 @@ +--- +title: TPM2 NV Index Assignment by systemd +category: Booting +layout: default +SPDX-License-Identifier: LGPL-2.1-or-later +--- + +# TPM 2.0 NV Index Assignments + +The Trusted Computing Group (TCG) maintains a [Registry of Reserved TPM 2.0 +Handles and Localities](https://trustedcomputinggroup.org/resource/registry/) +which assigns TPM 2.0 NV index ranges (among ther things, see section 2.2) to +organizations (by convention only!). It has assigned the NV index range +**0x01800400-0x018005FF** to the systemd project. This NV index range is subdivided +and used by systemd for the following purposes: + +## As Storage for a Disk Encryption PolicyAuthorizeNV Policy Hash + +*Scope*: Dynamic allocation at OS installation time, one for each installed +Linux/systemd based OS that uses `systemd-pcrlock` based disk encryption policies. + +*Subrange*: **0x01800400-0x0180041F** + +*Number of NV Indexes*: **32** + +*Size*: Stores one policy hash. Under the assumption SHA256 policy hashes are +used, this means **32 byte**. + +## As Storage for Additional PCRs Implemented in NV Indexes + +*Scope*: Static allocation by the systemd project, one for each additional NV +Indexed based PCR (systemd calls these "NvPCRs"). These can be shared between +multiple Linux/systemd based OSes installed on the same system. + +*Subrange*: **0x01800420-0x01800423** + +*Number of NV Indexes*: **4** + +*Size*: Stores one PCR hash each (`TPMA_NT_EXTEND`). We'd expect that typically +SHA256 PCR hashes are used, hence this means **32 byte**. + +*Detailed Assignments*: + +| NVIndex | Purpose | +|------------|---------------------------------------------------------------| +| 0x01800420 | Used LUKS unlock mechanism (TPM2, PKCS11, FIDO2, …) | +| 0x01800421 | Product UUID | +| 0x01800422 | System Extension Images (sysexts) applied to the host | +| 0x01800423 | Configuration Extension Images (confexts) applied to the host | + +## Currently Unused Range + +The following range is currently not used by the systemd project, but might be +allocated later: **0x01800424-0x018005FF** + +## Summary: + +| NVIndex Range | Number | Purpose | +|-----------------------|--------|------------------------------------------------| +| 0x01800400-0x0180041F | 32 | Assigned to systemd, used for pcrlock policies | +| 0x01800420-0x01800423 | 4 | Assigned to systemd, used as additional PCRs | +| 0x01800424-0x018005FF | 476 | Assigned to systemd, currently unused | + +# Relationship with TCG + +This document is referenced by the aforementioned registry for details about +assignments of the NV Index range delegated to the systemd project. Hence, +particular care should be taken that this page is not moved, and its URL +remains stable as +[`https://systemd.io/TPM2_NVINDEX_ASSIGNMENTS`](https://systemd.io/TPM2_NVINDEX_ASSIGNMENTS). diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 18194da3e78..4995770b433 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -5883,9 +5883,9 @@ int tpm2_unseal(Tpm2Context *c, return 0; } -static TPM2_HANDLE generate_random_nv_index(void) { - return TPM2_NV_INDEX_UNASSIGNED_FIRST + - (TPM2_HANDLE) random_u64_range(TPM2_NV_INDEX_UNASSIGNED_LAST - TPM2_NV_INDEX_UNASSIGNED_FIRST + 1); +static TPM2_HANDLE generate_random_pcrlock_nv_index(void) { + return TPM2_NV_INDEX_PCRLOCK_FIRST + + (TPM2_HANDLE) random_u64_range(TPM2_NV_INDEX_PCRLOCK_LAST - TPM2_NV_INDEX_PCRLOCK_FIRST + 1); } int tpm2_define_policy_nv_index( @@ -5919,7 +5919,7 @@ int tpm2_define_policy_nv_index( if (requested_nv_index != 0) nv_index = requested_nv_index; else - nv_index = generate_random_nv_index(); + nv_index = generate_random_pcrlock_nv_index(); TPM2B_NV_PUBLIC public_info = { .size = sizeof_field(TPM2B_NV_PUBLIC, nvPublic), diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index bffb7106788..4c825a5ccf7 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -503,13 +503,21 @@ enum { int tpm2_pcr_index_from_string(const char *s) _pure_; const char* tpm2_pcr_index_to_string(int pcr) _const_; -/* The first and last NV index handle that is not registered to any company, as per TCG's "Registry of + +/* The first and last NV index handle that is assigned to the systemd project as per TCG's "Registry of * Reserved TPM 2.0 Handles and Localities", section 2.2.2. */ -#define TPM2_NV_INDEX_UNASSIGNED_FIRST UINT32_C(0x01800000) -#define TPM2_NV_INDEX_UNASSIGNED_LAST UINT32_C(0x01BFFFFF) +#define TPM2_NV_INDEX_SYSTEMD_FIRST UINT32_C(0x01800400) +#define TPM2_NV_INDEX_SYSTEMD_LAST UINT32_C(0x018005FF) #if HAVE_TPM2 /* Verify that the above is indeed a subset of the general NV Index range */ -assert_cc(TPM2_NV_INDEX_UNASSIGNED_FIRST >= TPM2_NV_INDEX_FIRST); -assert_cc(TPM2_NV_INDEX_UNASSIGNED_LAST <= TPM2_NV_INDEX_LAST); +assert_cc(TPM2_NV_INDEX_SYSTEMD_FIRST >= TPM2_NV_INDEX_FIRST); +assert_cc(TPM2_NV_INDEX_SYSTEMD_LAST <= TPM2_NV_INDEX_LAST); #endif + +/* A subrange we use to store pcrlock policies in */ +#define TPM2_NV_INDEX_PCRLOCK_FIRST UINT32_C(0x01800400) +#define TPM2_NV_INDEX_PCRLOCK_LAST UINT32_C(0x0180041F) + +assert_cc(TPM2_NV_INDEX_PCRLOCK_FIRST >= TPM2_NV_INDEX_SYSTEMD_FIRST); +assert_cc(TPM2_NV_INDEX_PCRLOCK_LAST <= TPM2_NV_INDEX_SYSTEMD_LAST);