1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "extract-word.h"
4 #include "parse-util.h"
8 #include "alloc-util.h"
9 #include "dirent-util.h"
10 #include "dlfcn-util.h"
12 #include "format-table.h"
14 #include "hexdecoct.h"
15 #include "memory-util.h"
16 #include "random-util.h"
17 #include "time-util.h"
19 static void *libtss2_esys_dl
= NULL
;
20 static void *libtss2_rc_dl
= NULL
;
21 static void *libtss2_mu_dl
= NULL
;
23 TSS2_RC (*sym_Esys_Create
)(ESYS_CONTEXT
*esysContext
, ESYS_TR parentHandle
, ESYS_TR shandle1
, ESYS_TR shandle2
, ESYS_TR shandle3
, const TPM2B_SENSITIVE_CREATE
*inSensitive
, const TPM2B_PUBLIC
*inPublic
, const TPM2B_DATA
*outsideInfo
, const TPML_PCR_SELECTION
*creationPCR
, TPM2B_PRIVATE
**outPrivate
, TPM2B_PUBLIC
**outPublic
, TPM2B_CREATION_DATA
**creationData
, TPM2B_DIGEST
**creationHash
, TPMT_TK_CREATION
**creationTicket
) = NULL
;
24 TSS2_RC (*sym_Esys_CreatePrimary
)(ESYS_CONTEXT
*esysContext
, ESYS_TR primaryHandle
, ESYS_TR shandle1
, ESYS_TR shandle2
, ESYS_TR shandle3
, const TPM2B_SENSITIVE_CREATE
*inSensitive
, const TPM2B_PUBLIC
*inPublic
, const TPM2B_DATA
*outsideInfo
, const TPML_PCR_SELECTION
*creationPCR
, ESYS_TR
*objectHandle
, TPM2B_PUBLIC
**outPublic
, TPM2B_CREATION_DATA
**creationData
, TPM2B_DIGEST
**creationHash
, TPMT_TK_CREATION
**creationTicket
) = NULL
;
25 void (*sym_Esys_Finalize
)(ESYS_CONTEXT
**context
) = NULL
;
26 TSS2_RC (*sym_Esys_FlushContext
)(ESYS_CONTEXT
*esysContext
, ESYS_TR flushHandle
) = NULL
;
27 void (*sym_Esys_Free
)(void *ptr
) = NULL
;
28 TSS2_RC (*sym_Esys_GetRandom
)(ESYS_CONTEXT
*esysContext
, ESYS_TR shandle1
, ESYS_TR shandle2
, ESYS_TR shandle3
, UINT16 bytesRequested
, TPM2B_DIGEST
**randomBytes
) = NULL
;
29 TSS2_RC (*sym_Esys_Initialize
)(ESYS_CONTEXT
**esys_context
, TSS2_TCTI_CONTEXT
*tcti
, TSS2_ABI_VERSION
*abiVersion
) = NULL
;
30 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
;
31 TSS2_RC (*sym_Esys_PolicyGetDigest
)(ESYS_CONTEXT
*esysContext
, ESYS_TR policySession
, ESYS_TR shandle1
, ESYS_TR shandle2
, ESYS_TR shandle3
, TPM2B_DIGEST
**policyDigest
) = NULL
;
32 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
;
33 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
;
34 TSS2_RC (*sym_Esys_Startup
)(ESYS_CONTEXT
*esysContext
, TPM2_SU startupType
) = NULL
;
35 TSS2_RC (*sym_Esys_Unseal
)(ESYS_CONTEXT
*esysContext
, ESYS_TR itemHandle
, ESYS_TR shandle1
, ESYS_TR shandle2
, ESYS_TR shandle3
, TPM2B_SENSITIVE_DATA
**outData
) = NULL
;
37 const char* (*sym_Tss2_RC_Decode
)(TSS2_RC rc
) = NULL
;
39 TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Marshal
)(TPM2B_PRIVATE
const *src
, uint8_t buffer
[], size_t buffer_size
, size_t *offset
) = NULL
;
40 TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal
)(uint8_t const buffer
[], size_t buffer_size
, size_t *offset
, TPM2B_PRIVATE
*dest
) = NULL
;
41 TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal
)(TPM2B_PUBLIC
const *src
, uint8_t buffer
[], size_t buffer_size
, size_t *offset
) = NULL
;
42 TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal
)(uint8_t const buffer
[], size_t buffer_size
, size_t *offset
, TPM2B_PUBLIC
*dest
) = NULL
;
44 int dlopen_tpm2(void) {
47 if (!libtss2_esys_dl
) {
48 _cleanup_(dlclosep
) void *dl
= NULL
;
50 dl
= dlopen("libtss2-esys.so.0", RTLD_LAZY
);
52 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
53 "TPM2 support is not installed: %s", dlerror());
55 r
= dlsym_many_and_warn(
58 DLSYM_ARG(Esys_Create
),
59 DLSYM_ARG(Esys_CreatePrimary
),
60 DLSYM_ARG(Esys_Finalize
),
61 DLSYM_ARG(Esys_FlushContext
),
63 DLSYM_ARG(Esys_GetRandom
),
64 DLSYM_ARG(Esys_Initialize
),
66 DLSYM_ARG(Esys_PolicyGetDigest
),
67 DLSYM_ARG(Esys_PolicyPCR
),
68 DLSYM_ARG(Esys_StartAuthSession
),
69 DLSYM_ARG(Esys_Startup
),
70 DLSYM_ARG(Esys_Unseal
),
75 libtss2_esys_dl
= TAKE_PTR(dl
);
80 _cleanup_(dlclosep
) void *dl
= NULL
;
82 dl
= dlopen("libtss2-rc.so.0", RTLD_LAZY
);
84 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
85 "TPM2 support is not installed: %s", dlerror());
87 r
= dlsym_many_and_warn(
90 DLSYM_ARG(Tss2_RC_Decode
),
95 libtss2_rc_dl
= TAKE_PTR(dl
);
100 _cleanup_(dlclosep
) void *dl
= NULL
;
102 dl
= dlopen("libtss2-mu.so.0", RTLD_LAZY
);
104 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
105 "TPM2 support is not installed: %s", dlerror());
107 r
= dlsym_many_and_warn(
110 DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal
),
111 DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal
),
112 DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal
),
113 DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal
),
118 libtss2_mu_dl
= TAKE_PTR(dl
);
125 struct tpm2_context
{
126 ESYS_CONTEXT
*esys_context
;
128 TSS2_TCTI_CONTEXT
*tcti_context
;
131 static void tpm2_context_destroy(struct tpm2_context
*c
) {
135 sym_Esys_Finalize(&c
->esys_context
);
137 c
->tcti_context
= mfree(c
->tcti_context
);
145 static inline void Esys_Finalize_wrapper(ESYS_CONTEXT
**c
) {
146 /* A wrapper around Esys_Finalize() for use with _cleanup_(). Only reasons we need this wrapper is
147 * because the function itself warn logs if we'd pass a pointer to NULL, and we don't want that. */
149 sym_Esys_Finalize(c
);
152 static inline void Esys_Freep(void *p
) {
154 sym_Esys_Free(*(void**) p
);
157 static ESYS_TR
flush_context_verbose(ESYS_CONTEXT
*c
, ESYS_TR handle
) {
160 if (!c
|| handle
== ESYS_TR_NONE
)
163 rc
= sym_Esys_FlushContext(c
, handle
);
164 if (rc
!= TSS2_RC_SUCCESS
) /* We ignore failures here (besides debug logging), since this is called
165 * in error paths, where we cannot do anything about failures anymore. And
166 * when it is called in successful codepaths by this time we already did
167 * what we wanted to do, and got the results we wanted so there's no
168 * reason to make this fail more loudly than necessary. */
169 log_debug("Failed to get flush context of TPM, ignoring: %s", sym_Tss2_RC_Decode(rc
));
174 static int tpm2_init(const char *device
, struct tpm2_context
*ret
) {
175 _cleanup_(Esys_Finalize_wrapper
) ESYS_CONTEXT
*c
= NULL
;
176 _cleanup_free_ TSS2_TCTI_CONTEXT
*tcti
= NULL
;
177 _cleanup_(dlclosep
) void *dl
= NULL
;
183 return log_error_errno(r
, "TPM2 support not installed: %m");
186 device
= secure_getenv("SYSTEMD_TPM2_DEVICE");
189 const char *param
, *driver
, *fn
;
190 const TSS2_TCTI_INFO
* info
;
191 TSS2_TCTI_INFO_FUNC func
;
194 param
= strchr(device
, ':');
196 driver
= strndupa(device
, param
- device
);
203 fn
= strjoina("libtss2-tcti-", driver
, ".so.0");
205 dl
= dlopen(fn
, RTLD_NOW
);
207 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "Failed to load %s: %s", fn
, dlerror());
209 func
= dlsym(dl
, TSS2_TCTI_INFO_SYMBOL
);
211 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
212 "Failed to find TCTI info symbol " TSS2_TCTI_INFO_SYMBOL
": %s",
217 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "Unable to get TCTI info data.");
220 log_debug("Loaded TCTI module '%s' (%s) [Version %" PRIu32
"]", info
->name
, info
->description
, info
->version
);
222 rc
= info
->init(NULL
, &sz
, NULL
);
223 if (rc
!= TPM2_RC_SUCCESS
)
224 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
225 "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc
));
231 rc
= info
->init(tcti
, &sz
, device
);
232 if (rc
!= TPM2_RC_SUCCESS
)
233 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
234 "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc
));
237 rc
= sym_Esys_Initialize(&c
, tcti
, NULL
);
238 if (rc
!= TSS2_RC_SUCCESS
)
239 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
240 "Failed to initialize TPM context: %s", sym_Tss2_RC_Decode(rc
));
242 rc
= sym_Esys_Startup(c
, TPM2_SU_CLEAR
);
243 if (rc
== TPM2_RC_INITIALIZE
)
244 log_debug("TPM already started up.");
245 else if (rc
== TSS2_RC_SUCCESS
)
246 log_debug("TPM successfully started up.");
248 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
249 "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc
));
251 *ret
= (struct tpm2_context
) {
252 .esys_context
= TAKE_PTR(c
),
253 .tcti_context
= TAKE_PTR(tcti
),
254 .tcti_dl
= TAKE_PTR(dl
),
260 static int tpm2_credit_random(ESYS_CONTEXT
*c
) {
261 size_t rps
, done
= 0;
267 /* Pulls some entropy from the TPM and adds it into the kernel RNG pool. That way we can say that the
268 * key we will ultimately generate with the kernel random pool is at least as good as the TPM's RNG,
269 * but likely better. Note that we don't trust the TPM RNG very much, hence do not actually credit
272 for (rps
= random_pool_size(); rps
> 0;) {
273 _cleanup_(Esys_Freep
) TPM2B_DIGEST
*buffer
= NULL
;
275 rc
= sym_Esys_GetRandom(
280 MIN(rps
, 32U), /* 32 is supposedly a safe choice, given that AES 256bit keys are this long, and TPM2 baseline requires support for those. */
282 if (rc
!= TSS2_RC_SUCCESS
)
283 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
284 "Failed to acquire entropy from TPM: %s", sym_Tss2_RC_Decode(rc
));
286 if (buffer
->size
== 0)
287 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
288 "Zero-sized entropy returned from TPM.");
290 r
= random_write_entropy(-1, buffer
->buffer
, buffer
->size
, false);
292 return log_error_errno(r
, "Failed wo write entropy to kernel: %m");
294 done
+= buffer
->size
;
295 rps
= LESS_BY(rps
, buffer
->size
);
298 log_debug("Added %zu bytes of entropy to the kernel random pool.", done
);
302 static int tpm2_make_primary(
304 ESYS_TR
*ret_primary
) {
306 static const TPM2B_SENSITIVE_CREATE primary_sensitive
= {};
307 static const TPM2B_PUBLIC primary_template
= {
308 .size
= sizeof(TPMT_PUBLIC
),
310 .type
= TPM2_ALG_ECC
,
311 .nameAlg
= TPM2_ALG_SHA256
,
312 .objectAttributes
= TPMA_OBJECT_RESTRICTED
|TPMA_OBJECT_DECRYPT
|TPMA_OBJECT_FIXEDTPM
|TPMA_OBJECT_FIXEDPARENT
|TPMA_OBJECT_SENSITIVEDATAORIGIN
|TPMA_OBJECT_USERWITHAUTH
,
316 .algorithm
= TPM2_ALG_AES
,
318 .mode
.aes
= TPM2_ALG_CFB
,
320 .scheme
.scheme
= TPM2_ALG_NULL
,
321 .curveID
= TPM2_ECC_NIST_P256
,
322 .kdf
.scheme
= TPM2_ALG_NULL
,
327 static const TPML_PCR_SELECTION creation_pcr
= {};
328 ESYS_TR primary
= ESYS_TR_NONE
;
331 log_debug("Creating primary key on TPM.");
333 rc
= sym_Esys_CreatePrimary(
349 if (rc
!= TSS2_RC_SUCCESS
)
350 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
351 "Failed to generate primary key in TPM: %s", sym_Tss2_RC_Decode(rc
));
353 log_debug("Successfully created primary key on TPM.");
355 *ret_primary
= primary
;
359 static int tpm2_make_pcr_session(
362 ESYS_TR
*ret_session
,
363 TPM2B_DIGEST
**ret_policy_digest
) {
365 static const TPMT_SYM_DEF symmetric
= {
366 .algorithm
= TPM2_ALG_AES
,
374 TPML_PCR_SELECTION pcr_selection
= {
376 .pcrSelections
[0].hash
= TPM2_ALG_SHA256
,
377 .pcrSelections
[0].sizeofSelect
= 3,
378 .pcrSelections
[0].pcrSelect
[0] = pcr_mask
& 0xFF,
379 .pcrSelections
[0].pcrSelect
[1] = (pcr_mask
>> 8) & 0xFF,
380 .pcrSelections
[0].pcrSelect
[2] = (pcr_mask
>> 16) & 0xFF,
382 _cleanup_(Esys_Freep
) TPM2B_DIGEST
*policy_digest
= NULL
;
383 ESYS_TR session
= ESYS_TR_NONE
;
389 log_debug("Starting authentication session.");
391 rc
= sym_Esys_StartAuthSession(
403 if (rc
!= TSS2_RC_SUCCESS
)
404 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
405 "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc
));
407 log_debug("Configuring PCR policy.");
409 rc
= sym_Esys_PolicyPCR(
417 if (rc
!= TSS2_RC_SUCCESS
) {
418 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
419 "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc
));
423 if (DEBUG_LOGGING
|| ret_policy_digest
) {
424 log_debug("Acquiring policy digest.");
426 rc
= sym_Esys_PolicyGetDigest(
434 if (rc
!= TSS2_RC_SUCCESS
) {
435 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
436 "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc
));
441 _cleanup_free_
char *h
= NULL
;
443 h
= hexmem(policy_digest
->buffer
, policy_digest
->size
);
449 log_debug("Session policy digest: %s", h
);
454 *ret_session
= session
;
455 session
= ESYS_TR_NONE
;
458 if (ret_policy_digest
)
459 *ret_policy_digest
= TAKE_PTR(policy_digest
);
464 session
= flush_context_verbose(c
, session
);
472 size_t *ret_secret_size
,
474 size_t *ret_blob_size
,
476 size_t *ret_pcr_hash_size
) {
478 _cleanup_(tpm2_context_destroy
) struct tpm2_context c
= {};
479 _cleanup_(Esys_Freep
) TPM2B_DIGEST
*policy_digest
= NULL
;
480 _cleanup_(Esys_Freep
) TPM2B_PRIVATE
*private = NULL
;
481 _cleanup_(Esys_Freep
) TPM2B_PUBLIC
*public = NULL
;
482 static const TPML_PCR_SELECTION creation_pcr
= {};
483 _cleanup_(erase_and_freep
) void *secret
= NULL
;
484 _cleanup_free_
void *blob
= NULL
, *hash
= NULL
;
485 TPM2B_SENSITIVE_CREATE hmac_sensitive
;
486 ESYS_TR primary
= ESYS_TR_NONE
;
487 TPM2B_PUBLIC hmac_template
;
494 assert(ret_secret_size
);
496 assert(ret_blob_size
);
497 assert(ret_pcr_hash
);
498 assert(ret_pcr_hash_size
);
500 assert(pcr_mask
< (UINT32_C(1) << TPM2_PCRS_MAX
)); /* Support 24 PCR banks */
502 /* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
503 * is randomized when the TPM2 is first initialized or reset and remains stable across boots. We
504 * generate a "primary" key pair derived from that (RSA). Given the seed remains fixed this will
505 * result in the same key pair whenever we specify the exact same parameters for it. We then create a
506 * PCR-bound policy session, which calculates a hash on the current PCR values of the indexes we
507 * specify. We then generate a randomized key on the host (which is the key we actually enroll in the
508 * LUKS2 keyslots), which we upload into the TPM2, where it is encrypted with the "primary" key,
509 * taking the PCR policy session into account. We then download the encrypted key from the TPM2
510 * ("sealing") and marshall it into binary form, which is ultimately placed in the LUKS2 JSON header.
512 * The TPM2 "seed" key and "primary" keys never leave the TPM2 chip (and cannot be extracted at
513 * all). The random key we enroll in LUKS2 we generate on the host using the Linux random device. It
514 * is stored in the LUKS2 JSON only in encrypted form with the "primary" key of the TPM2 chip, thus
515 * binding the unlocking to the TPM2 chip. */
517 start
= now(CLOCK_MONOTONIC
);
519 r
= tpm2_init(device
, &c
);
523 r
= tpm2_make_primary(c
.esys_context
, &primary
);
527 r
= tpm2_make_pcr_session(c
.esys_context
, pcr_mask
, NULL
, &policy_digest
);
531 /* We use a keyed hash object (i.e. HMAC) to store the secret key we want to use for unlocking the
532 * LUKS2 volume with. We don't ever use for HMAC/keyed hash operations however, we just use it
533 * because it's a key type that is universally supported and suitable for symmetric binary blobs. */
534 hmac_template
= (TPM2B_PUBLIC
) {
535 .size
= sizeof(TPMT_PUBLIC
),
537 .type
= TPM2_ALG_KEYEDHASH
,
538 .nameAlg
= TPM2_ALG_SHA256
,
539 .objectAttributes
= TPMA_OBJECT_FIXEDTPM
| TPMA_OBJECT_FIXEDPARENT
,
542 .scheme
.scheme
= TPM2_ALG_NULL
,
550 .authPolicy
= *policy_digest
,
554 hmac_sensitive
= (TPM2B_SENSITIVE_CREATE
) {
555 .size
= sizeof(hmac_sensitive
.sensitive
),
556 .sensitive
.data
.size
= 32,
558 assert(sizeof(hmac_sensitive
.sensitive
.data
.buffer
) >= hmac_sensitive
.sensitive
.data
.size
);
560 (void) tpm2_credit_random(c
.esys_context
);
562 log_debug("Generating secret key data.");
564 r
= genuine_random_bytes(hmac_sensitive
.sensitive
.data
.buffer
, hmac_sensitive
.sensitive
.data
.size
, RANDOM_BLOCK
);
566 log_error_errno(r
, "Failed to generate secret key: %m");
570 log_debug("Creating HMAC key.");
572 rc
= sym_Esys_Create(
587 if (rc
!= TSS2_RC_SUCCESS
) {
588 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
589 "Failed to generate HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc
));
593 secret
= memdup(hmac_sensitive
.sensitive
.data
.buffer
, hmac_sensitive
.sensitive
.data
.size
);
594 explicit_bzero_safe(hmac_sensitive
.sensitive
.data
.buffer
, hmac_sensitive
.sensitive
.data
.size
);
600 log_debug("Marshalling private and public part of HMAC key.");
602 k
= ALIGN8(sizeof(*private)) + ALIGN8(sizeof(*public)); /* Some roughly sensible start value */
604 _cleanup_free_
void *buf
= NULL
;
613 rc
= sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, buf
, k
, &offset
);
614 if (rc
== TSS2_RC_SUCCESS
) {
615 rc
= sym_Tss2_MU_TPM2B_PUBLIC_Marshal(public, buf
, k
, &offset
);
616 if (rc
== TSS2_RC_SUCCESS
) {
617 blob
= TAKE_PTR(buf
);
622 if (rc
!= TSS2_MU_RC_INSUFFICIENT_BUFFER
) {
623 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
624 "Failed to marshal private/public key: %s", sym_Tss2_RC_Decode(rc
));
628 if (k
> SIZE_MAX
/ 2) {
636 hash
= memdup(policy_digest
->buffer
, policy_digest
->size
);
641 char buf
[FORMAT_TIMESPAN_MAX
];
642 log_debug("Completed TPM2 key sealing in %s.", format_timespan(buf
, sizeof(buf
), now(CLOCK_MONOTONIC
) - start
, 1));
645 *ret_secret
= TAKE_PTR(secret
);
646 *ret_secret_size
= hmac_sensitive
.sensitive
.data
.size
;
647 *ret_blob
= TAKE_PTR(blob
);
648 *ret_blob_size
= blob_size
;
649 *ret_pcr_hash
= TAKE_PTR(hash
);
650 *ret_pcr_hash_size
= policy_digest
->size
;
655 primary
= flush_context_verbose(c
.esys_context
, primary
);
664 const void *known_policy_hash
,
665 size_t known_policy_hash_size
,
667 size_t *ret_secret_size
) {
669 _cleanup_(tpm2_context_destroy
) struct tpm2_context c
= {};
670 ESYS_TR primary
= ESYS_TR_NONE
, session
= ESYS_TR_NONE
, hmac_key
= ESYS_TR_NONE
;
671 _cleanup_(Esys_Freep
) TPM2B_SENSITIVE_DATA
* unsealed
= NULL
;
672 _cleanup_(Esys_Freep
) TPM2B_DIGEST
*policy_digest
= NULL
;
673 _cleanup_(erase_and_freep
) char *secret
= NULL
;
674 TPM2B_PRIVATE
private = {};
675 TPM2B_PUBLIC
public = {};
682 assert(blob_size
> 0);
683 assert(known_policy_hash_size
== 0 || known_policy_hash
);
685 assert(ret_secret_size
);
687 assert(pcr_mask
< (UINT32_C(1) << TPM2_PCRS_MAX
)); /* Support 24 PCR banks */
691 return log_error_errno(r
, "TPM2 support is not installed.");
693 /* So here's what we do here: We connect to the TPM2 chip. As we do when sealing we generate a
694 * "primary" key on the TPM2 chip, with the same parameters as well as a PCR-bound policy
695 * session. Given we pass the same parameters, this will result in the same "primary" key, and same
696 * policy hash (the latter of course, only if the PCR values didn't change in between). We unmarshal
697 * the encrypted key we stored in the LUKS2 JSON token header and upload it into the TPM2, where it
698 * is decrypted if the seed and the PCR policy were right ("unsealing"). We then download the result,
699 * and use it to unlock the LUKS2 volume. */
701 start
= now(CLOCK_MONOTONIC
);
703 log_debug("Unmarshalling private part of HMAC key.");
705 rc
= sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal(blob
, blob_size
, &offset
, &private);
706 if (rc
!= TSS2_RC_SUCCESS
)
707 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
708 "Failed to unmarshal private key: %s", sym_Tss2_RC_Decode(rc
));
710 log_debug("Unmarshalling public part of HMAC key.");
712 rc
= sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal(blob
, blob_size
, &offset
, &public);
713 if (rc
!= TSS2_RC_SUCCESS
)
714 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
715 "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc
));
717 r
= tpm2_init(device
, &c
);
721 r
= tpm2_make_pcr_session(c
.esys_context
, pcr_mask
, &session
, &policy_digest
);
725 /* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not
726 * wait until the TPM2 tells us to go away. */
727 if (known_policy_hash_size
> 0 &&
728 memcmp_nn(policy_digest
->buffer
, policy_digest
->size
, known_policy_hash
, known_policy_hash_size
) != 0)
729 return log_error_errno(SYNTHETIC_ERRNO(EPERM
),
730 "Current policy digest does not match stored policy digest, cancelling TPM2 authentication attempt.");
732 r
= tpm2_make_primary(c
.esys_context
, &primary
);
736 log_debug("Loading HMAC key into TPM.");
747 if (rc
!= TSS2_RC_SUCCESS
) {
748 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
749 "Failed to load HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc
));
753 log_debug("Unsealing HMAC key.");
755 rc
= sym_Esys_Unseal(
762 if (rc
!= TSS2_RC_SUCCESS
) {
763 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
764 "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc
));
768 secret
= memdup(unsealed
->buffer
, unsealed
->size
);
769 explicit_bzero_safe(unsealed
->buffer
, unsealed
->size
);
776 char buf
[FORMAT_TIMESPAN_MAX
];
777 log_debug("Completed TPM2 key unsealing in %s.", format_timespan(buf
, sizeof(buf
), now(CLOCK_MONOTONIC
) - start
, 1));
780 *ret_secret
= TAKE_PTR(secret
);
781 *ret_secret_size
= unsealed
->size
;
786 primary
= flush_context_verbose(c
.esys_context
, primary
);
787 session
= flush_context_verbose(c
.esys_context
, session
);
788 hmac_key
= flush_context_verbose(c
.esys_context
, hmac_key
);
794 int tpm2_list_devices(void) {
796 _cleanup_(table_unrefp
) Table
*t
= NULL
;
797 _cleanup_(closedirp
) DIR *d
= NULL
;
802 return log_error_errno(r
, "TPM2 support is not installed.");
804 t
= table_new("path", "device", "driver");
808 d
= opendir("/sys/class/tpmrm");
810 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
, "Failed to open /sys/class/tpmrm: %m");
815 _cleanup_free_
char *device_path
= NULL
, *device
= NULL
, *driver_path
= NULL
, *driver
= NULL
, *node
= NULL
;
818 de
= readdir_no_dot(d
);
822 device_path
= path_join("/sys/class/tpmrm", de
->d_name
, "device");
826 r
= readlink_malloc(device_path
, &device
);
828 log_debug_errno(r
, "Failed to read device symlink %s, ignoring: %m", device_path
);
830 driver_path
= path_join(device_path
, "driver");
834 r
= readlink_malloc(driver_path
, &driver
);
836 log_debug_errno(r
, "Failed to read driver symlink %s, ignoring: %m", driver_path
);
839 node
= path_join("/dev", de
->d_name
);
846 TABLE_STRING
, device
? last_path_component(device
) : NULL
,
847 TABLE_STRING
, driver
? last_path_component(driver
) : NULL
);
849 return table_log_add_error(r
);
853 if (table_get_rows(t
) <= 1) {
854 log_info("No suitable TPM2 devices found.");
858 r
= table_print(t
, stdout
);
860 return log_error_errno(r
, "Failed to show device table: %m");
864 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
865 "TPM2 not supported on this build.");
869 int tpm2_find_device_auto(
870 int log_level
, /* log level when no device is found */
873 _cleanup_(closedirp
) DIR *d
= NULL
;
878 return log_error_errno(r
, "TPM2 support is not installed.");
880 d
= opendir("/sys/class/tpmrm");
882 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
883 "Failed to open /sys/class/tpmrm: %m");
887 _cleanup_free_
char *node
= NULL
;
892 de
= readdir_no_dot(d
);
897 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
898 "More than one TPM2 (tpmrm) device found.");
900 node
= path_join("/dev", de
->d_name
);
906 *ret
= TAKE_PTR(node
);
911 return log_full_errno(log_level
, SYNTHETIC_ERRNO(ENODEV
), "No TPM2 (tpmrm) device found.");
913 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
914 "TPM2 not supported on this build.");
918 int tpm2_parse_pcrs(const char *s
, uint32_t *ret
) {
930 /* Parses a "," or "+" separated list of PCR indexes. We support "," since this is a list after all,
931 * and most other tools expect comma separated PCR specifications. We also support "+" since in
932 * /etc/crypttab the "," is already used to separate options, hence a different separator is nice to
936 _cleanup_free_
char *pcr
= NULL
;
939 r
= extract_first_word(&p
, &pcr
, ",+", EXTRACT_DONT_COALESCE_SEPARATORS
);
943 return log_error_errno(r
, "Failed to parse PCR list: %s", s
);
945 r
= safe_atou(pcr
, &n
);
947 return log_error_errno(r
, "Failed to parse PCR number: %s", pcr
);
948 if (n
>= TPM2_PCRS_MAX
)
949 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
),
950 "PCR number out of range (valid range 0…23): %u", n
);
952 mask
|= UINT32_C(1) << n
;
959 int tpm2_make_luks2_json(
964 const void *policy_hash
,
965 size_t policy_hash_size
,
968 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *a
= NULL
;
969 _cleanup_free_
char *keyslot_as_string
= NULL
;
970 JsonVariant
* pcr_array
[TPM2_PCRS_MAX
];
974 assert(blob
|| blob_size
== 0);
975 assert(policy_hash
|| policy_hash_size
== 0);
977 if (asprintf(&keyslot_as_string
, "%i", keyslot
) < 0)
980 for (unsigned i
= 0; i
< ELEMENTSOF(pcr_array
); i
++) {
981 if ((pcr_mask
& (UINT32_C(1) << i
)) == 0)
984 r
= json_variant_new_integer(pcr_array
+ n_pcrs
, i
);
986 json_variant_unref_many(pcr_array
, n_pcrs
);
993 r
= json_variant_new_array(&a
, pcr_array
, n_pcrs
);
994 json_variant_unref_many(pcr_array
, n_pcrs
);
1000 JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-tpm2")),
1001 JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string
))),
1002 JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob
, blob_size
)),
1003 JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a
)),
1004 JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash
, policy_hash_size
))));