tpm2-setup: add new early boot tool for initializing the SRK

This adds an explicit service for initializing the TPM2 SRK. This is
implicitly also done by systemd-cryptsetup, hence strictly speaking
redundant, but doing this early has the benefit that we can parallelize
this in a nicer way. This also write a copy of the SRK public key in PEM
format to /run/ + /var/lib/, thus pinning the disk image to the TPM.
Making the SRK public key is also useful for allowing easy offline
encryption for a specific TPM.

Sooner or later we should probably grow what this service does, the
above is just the first step. For example, the service should probably
offer the ability to reset the TPM (clear the owner hierarchy?) on a
factory reset, if such a policy is needed. And we might want to install
some default AK (?).

Fixes: #27986
Also see: #22637
This commit is contained in:
Lennart Poettering
2023-09-29 19:36:04 +02:00
parent baab1b3faa
commit 2e64cb71b9
12 changed files with 496 additions and 5 deletions
+1 -1
View File
@@ -741,7 +741,7 @@ int generator_write_cryptsetup_unit_section(
fprintf(f,
"\n"
"DefaultDependencies=no\n"
"After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
"After=cryptsetup-pre.target systemd-udevd-kernel.socket systemd-tpm2-setup-early.service\n"
"Before=blockdev@dev-mapper-%%i.target\n"
"Wants=blockdev@dev-mapper-%%i.target\n"
"IgnoreOnIsolate=true\n");
+4 -4
View File
@@ -148,7 +148,7 @@ int dlopen_tpm2(void) {
DLSYM_ARG(Tss2_MU_TPMT_PUBLIC_Marshal));
}
static void Esys_Freep(void *p) {
void Esys_Freep(void *p) {
if (*(void**) p)
sym_Esys_Free(*(void**) p);
}
@@ -1175,7 +1175,7 @@ static int tpm2_get_srk(
}
/* Get the SRK, creating one if needed. Returns 0 on success, or < 0 on error. */
static int tpm2_get_or_create_srk(
int tpm2_get_or_create_srk(
Tpm2Context *c,
const Tpm2Handle *session,
TPM2B_PUBLIC **ret_public,
@@ -1189,7 +1189,7 @@ static int tpm2_get_or_create_srk(
if (r < 0)
return r;
if (r == 1)
return 0;
return 0; /* 0 → SRK already set up */
/* No SRK, create and persist one */
TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
@@ -1223,7 +1223,7 @@ static int tpm2_get_or_create_srk(
/* This should never happen. */
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "SRK we just persisted couldn't be found.");
return 0;
return 1; /* > 0 → SRK newly set up */
}
/* Utility functions for TPMS_PCR_SELECTION. */
+4
View File
@@ -67,6 +67,8 @@ typedef struct {
#define _tpm2_handle(c, h) { .tpm2_context = (c), .esys_handle = (h), }
static const Tpm2Handle TPM2_HANDLE_NONE = _tpm2_handle(NULL, ESYS_TR_NONE);
void Esys_Freep(void *p);
int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle);
Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle);
DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free);
@@ -188,6 +190,8 @@ int tpm2_calculate_sealing_policy(const Tpm2PCRValue *pcr_values, size_t n_pcr_v
int tpm2_marshal_blob(const TPM2B_PUBLIC *public, const TPM2B_PRIVATE *private, void **ret_blob, size_t *ret_blob_size);
int tpm2_unmarshal_blob(const void *blob, size_t blob_size, TPM2B_PUBLIC *ret_public, TPM2B_PRIVATE *ret_private);
int tpm2_get_or_create_srk(Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle);
int tpm2_seal(Tpm2Context *c, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);