]> git.proxmox.com Git - systemd.git/blob - src/shared/tpm2-util.c
New upstream version 249~rc1
[systemd.git] / src / shared / tpm2-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "extract-word.h"
4 #include "parse-util.h"
5 #include "tpm2-util.h"
6
7 #if HAVE_TPM2
8 #include "alloc-util.h"
9 #include "dirent-util.h"
10 #include "dlfcn-util.h"
11 #include "fd-util.h"
12 #include "format-table.h"
13 #include "fs-util.h"
14 #include "hexdecoct.h"
15 #include "memory-util.h"
16 #include "random-util.h"
17 #include "time-util.h"
18
19 static void *libtss2_esys_dl = NULL;
20 static void *libtss2_rc_dl = NULL;
21 static void *libtss2_mu_dl = NULL;
22
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;
36
37 const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL;
38
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;
43
44 int dlopen_tpm2(void) {
45 int r, k = 0;
46
47 if (!libtss2_esys_dl) {
48 _cleanup_(dlclosep) void *dl = NULL;
49
50 dl = dlopen("libtss2-esys.so.0", RTLD_LAZY);
51 if (!dl)
52 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
53 "TPM2 support is not installed: %s", dlerror());
54
55 r = dlsym_many_and_warn(
56 dl,
57 LOG_DEBUG,
58 DLSYM_ARG(Esys_Create),
59 DLSYM_ARG(Esys_CreatePrimary),
60 DLSYM_ARG(Esys_Finalize),
61 DLSYM_ARG(Esys_FlushContext),
62 DLSYM_ARG(Esys_Free),
63 DLSYM_ARG(Esys_GetRandom),
64 DLSYM_ARG(Esys_Initialize),
65 DLSYM_ARG(Esys_Load),
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),
71 NULL);
72 if (r < 0)
73 return r;
74
75 libtss2_esys_dl = TAKE_PTR(dl);
76 k++;
77 }
78
79 if (!libtss2_rc_dl) {
80 _cleanup_(dlclosep) void *dl = NULL;
81
82 dl = dlopen("libtss2-rc.so.0", RTLD_LAZY);
83 if (!dl)
84 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
85 "TPM2 support is not installed: %s", dlerror());
86
87 r = dlsym_many_and_warn(
88 dl,
89 LOG_DEBUG,
90 DLSYM_ARG(Tss2_RC_Decode),
91 NULL);
92 if (r < 0)
93 return r;
94
95 libtss2_rc_dl = TAKE_PTR(dl);
96 k++;
97 }
98
99 if (!libtss2_mu_dl) {
100 _cleanup_(dlclosep) void *dl = NULL;
101
102 dl = dlopen("libtss2-mu.so.0", RTLD_LAZY);
103 if (!dl)
104 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
105 "TPM2 support is not installed: %s", dlerror());
106
107 r = dlsym_many_and_warn(
108 dl,
109 LOG_DEBUG,
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),
114 NULL);
115 if (r < 0)
116 return r;
117
118 libtss2_mu_dl = TAKE_PTR(dl);
119 k++;
120 }
121
122 return k;
123 }
124
125 struct tpm2_context {
126 ESYS_CONTEXT *esys_context;
127 void *tcti_dl;
128 TSS2_TCTI_CONTEXT *tcti_context;
129 };
130
131 static void tpm2_context_destroy(struct tpm2_context *c) {
132 assert(c);
133
134 if (c->esys_context)
135 sym_Esys_Finalize(&c->esys_context);
136
137 c->tcti_context = mfree(c->tcti_context);
138
139 if (c->tcti_dl) {
140 dlclose(c->tcti_dl);
141 c->tcti_dl = NULL;
142 }
143 }
144
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. */
148 if (*c)
149 sym_Esys_Finalize(c);
150 }
151
152 static inline void Esys_Freep(void *p) {
153 if (*(void**) p)
154 sym_Esys_Free(*(void**) p);
155 }
156
157 static ESYS_TR flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle) {
158 TSS2_RC rc;
159
160 if (!c || handle == ESYS_TR_NONE)
161 return ESYS_TR_NONE;
162
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));
170
171 return ESYS_TR_NONE;
172 }
173
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;
178 TSS2_RC rc;
179 int r;
180
181 r = dlopen_tpm2();
182 if (r < 0)
183 return log_error_errno(r, "TPM2 support not installed: %m");
184
185 if (!device)
186 device = secure_getenv("SYSTEMD_TPM2_DEVICE");
187
188 if (device) {
189 const char *param, *driver, *fn;
190 const TSS2_TCTI_INFO* info;
191 TSS2_TCTI_INFO_FUNC func;
192 size_t sz = 0;
193
194 param = strchr(device, ':');
195 if (param) {
196 driver = strndupa(device, param - device);
197 param++;
198 } else {
199 driver = "device";
200 param = device;
201 }
202
203 fn = strjoina("libtss2-tcti-", driver, ".so.0");
204
205 dl = dlopen(fn, RTLD_NOW);
206 if (!dl)
207 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror());
208
209 func = dlsym(dl, TSS2_TCTI_INFO_SYMBOL);
210 if (!func)
211 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
212 "Failed to find TCTI info symbol " TSS2_TCTI_INFO_SYMBOL ": %s",
213 dlerror());
214
215 info = func();
216 if (!info)
217 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to get TCTI info data.");
218
219
220 log_debug("Loaded TCTI module '%s' (%s) [Version %" PRIu32 "]", info->name, info->description, info->version);
221
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));
226
227 tcti = malloc0(sz);
228 if (!tcti)
229 return log_oom();
230
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));
235 }
236
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));
241
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.");
247 else
248 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
249 "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc));
250
251 *ret = (struct tpm2_context) {
252 .esys_context = TAKE_PTR(c),
253 .tcti_context = TAKE_PTR(tcti),
254 .tcti_dl = TAKE_PTR(dl),
255 };
256
257 return 0;
258 }
259
260 static int tpm2_credit_random(ESYS_CONTEXT *c) {
261 size_t rps, done = 0;
262 TSS2_RC rc;
263 int r;
264
265 assert(c);
266
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
270 * any entropy. */
271
272 for (rps = random_pool_size(); rps > 0;) {
273 _cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL;
274
275 rc = sym_Esys_GetRandom(
276 c,
277 ESYS_TR_NONE,
278 ESYS_TR_NONE,
279 ESYS_TR_NONE,
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. */
281 &buffer);
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));
285
286 if (buffer->size == 0)
287 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
288 "Zero-sized entropy returned from TPM.");
289
290 r = random_write_entropy(-1, buffer->buffer, buffer->size, false);
291 if (r < 0)
292 return log_error_errno(r, "Failed wo write entropy to kernel: %m");
293
294 done += buffer->size;
295 rps = LESS_BY(rps, buffer->size);
296 }
297
298 log_debug("Added %zu bytes of entropy to the kernel random pool.", done);
299 return 0;
300 }
301
302 static int tpm2_make_primary(
303 ESYS_CONTEXT *c,
304 ESYS_TR *ret_primary) {
305
306 static const TPM2B_SENSITIVE_CREATE primary_sensitive = {};
307 static const TPM2B_PUBLIC primary_template = {
308 .size = sizeof(TPMT_PUBLIC),
309 .publicArea = {
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,
313 .parameters = {
314 .eccDetail = {
315 .symmetric = {
316 .algorithm = TPM2_ALG_AES,
317 .keyBits.aes = 128,
318 .mode.aes = TPM2_ALG_CFB,
319 },
320 .scheme.scheme = TPM2_ALG_NULL,
321 .curveID = TPM2_ECC_NIST_P256,
322 .kdf.scheme = TPM2_ALG_NULL,
323 },
324 },
325 },
326 };
327 static const TPML_PCR_SELECTION creation_pcr = {};
328 ESYS_TR primary = ESYS_TR_NONE;
329 TSS2_RC rc;
330
331 log_debug("Creating primary key on TPM.");
332
333 rc = sym_Esys_CreatePrimary(
334 c,
335 ESYS_TR_RH_OWNER,
336 ESYS_TR_PASSWORD,
337 ESYS_TR_NONE,
338 ESYS_TR_NONE,
339 &primary_sensitive,
340 &primary_template,
341 NULL,
342 &creation_pcr,
343 &primary,
344 NULL,
345 NULL,
346 NULL,
347 NULL);
348
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));
352
353 log_debug("Successfully created primary key on TPM.");
354
355 *ret_primary = primary;
356 return 0;
357 }
358
359 static int tpm2_make_pcr_session(
360 ESYS_CONTEXT *c,
361 uint32_t pcr_mask,
362 ESYS_TR *ret_session,
363 TPM2B_DIGEST **ret_policy_digest) {
364
365 static const TPMT_SYM_DEF symmetric = {
366 .algorithm = TPM2_ALG_AES,
367 .keyBits = {
368 .aes = 128
369 },
370 .mode = {
371 .aes = TPM2_ALG_CFB,
372 }
373 };
374 TPML_PCR_SELECTION pcr_selection = {
375 .count = 1,
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,
381 };
382 _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
383 ESYS_TR session = ESYS_TR_NONE;
384 TSS2_RC rc;
385 int r;
386
387 assert(c);
388
389 log_debug("Starting authentication session.");
390
391 rc = sym_Esys_StartAuthSession(
392 c,
393 ESYS_TR_NONE,
394 ESYS_TR_NONE,
395 ESYS_TR_NONE,
396 ESYS_TR_NONE,
397 ESYS_TR_NONE,
398 NULL,
399 TPM2_SE_POLICY,
400 &symmetric,
401 TPM2_ALG_SHA256,
402 &session);
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));
406
407 log_debug("Configuring PCR policy.");
408
409 rc = sym_Esys_PolicyPCR(
410 c,
411 session,
412 ESYS_TR_NONE,
413 ESYS_TR_NONE,
414 ESYS_TR_NONE,
415 NULL,
416 &pcr_selection);
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));
420 goto finish;
421 }
422
423 if (DEBUG_LOGGING || ret_policy_digest) {
424 log_debug("Acquiring policy digest.");
425
426 rc = sym_Esys_PolicyGetDigest(
427 c,
428 session,
429 ESYS_TR_NONE,
430 ESYS_TR_NONE,
431 ESYS_TR_NONE,
432 &policy_digest);
433
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));
437 goto finish;
438 }
439
440 if (DEBUG_LOGGING) {
441 _cleanup_free_ char *h = NULL;
442
443 h = hexmem(policy_digest->buffer, policy_digest->size);
444 if (!h) {
445 r = log_oom();
446 goto finish;
447 }
448
449 log_debug("Session policy digest: %s", h);
450 }
451 }
452
453 if (ret_session) {
454 *ret_session = session;
455 session = ESYS_TR_NONE;
456 }
457
458 if (ret_policy_digest)
459 *ret_policy_digest = TAKE_PTR(policy_digest);
460
461 r = 0;
462
463 finish:
464 session = flush_context_verbose(c, session);
465 return r;
466 }
467
468 int tpm2_seal(
469 const char *device,
470 uint32_t pcr_mask,
471 void **ret_secret,
472 size_t *ret_secret_size,
473 void **ret_blob,
474 size_t *ret_blob_size,
475 void **ret_pcr_hash,
476 size_t *ret_pcr_hash_size) {
477
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;
488 size_t k, blob_size;
489 usec_t start;
490 TSS2_RC rc;
491 int r;
492
493 assert(ret_secret);
494 assert(ret_secret_size);
495 assert(ret_blob);
496 assert(ret_blob_size);
497 assert(ret_pcr_hash);
498 assert(ret_pcr_hash_size);
499
500 assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */
501
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.
511 *
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. */
516
517 start = now(CLOCK_MONOTONIC);
518
519 r = tpm2_init(device, &c);
520 if (r < 0)
521 return r;
522
523 r = tpm2_make_primary(c.esys_context, &primary);
524 if (r < 0)
525 return r;
526
527 r = tpm2_make_pcr_session(c.esys_context, pcr_mask, NULL, &policy_digest);
528 if (r < 0)
529 goto finish;
530
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),
536 .publicArea = {
537 .type = TPM2_ALG_KEYEDHASH,
538 .nameAlg = TPM2_ALG_SHA256,
539 .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
540 .parameters = {
541 .keyedHashDetail = {
542 .scheme.scheme = TPM2_ALG_NULL,
543 },
544 },
545 .unique = {
546 .keyedHash = {
547 .size = 32,
548 },
549 },
550 .authPolicy = *policy_digest,
551 },
552 };
553
554 hmac_sensitive = (TPM2B_SENSITIVE_CREATE) {
555 .size = sizeof(hmac_sensitive.sensitive),
556 .sensitive.data.size = 32,
557 };
558 assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size);
559
560 (void) tpm2_credit_random(c.esys_context);
561
562 log_debug("Generating secret key data.");
563
564 r = genuine_random_bytes(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size, RANDOM_BLOCK);
565 if (r < 0) {
566 log_error_errno(r, "Failed to generate secret key: %m");
567 goto finish;
568 }
569
570 log_debug("Creating HMAC key.");
571
572 rc = sym_Esys_Create(
573 c.esys_context,
574 primary,
575 ESYS_TR_PASSWORD,
576 ESYS_TR_NONE,
577 ESYS_TR_NONE,
578 &hmac_sensitive,
579 &hmac_template,
580 NULL,
581 &creation_pcr,
582 &private,
583 &public,
584 NULL,
585 NULL,
586 NULL);
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));
590 goto finish;
591 }
592
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);
595 if (!secret) {
596 r = log_oom();
597 goto finish;
598 }
599
600 log_debug("Marshalling private and public part of HMAC key.");
601
602 k = ALIGN8(sizeof(*private)) + ALIGN8(sizeof(*public)); /* Some roughly sensible start value */
603 for (;;) {
604 _cleanup_free_ void *buf = NULL;
605 size_t offset = 0;
606
607 buf = malloc(k);
608 if (!buf) {
609 r = log_oom();
610 goto finish;
611 }
612
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);
618 blob_size = offset;
619 break;
620 }
621 }
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));
625 goto finish;
626 }
627
628 if (k > SIZE_MAX / 2) {
629 r = log_oom();
630 goto finish;
631 }
632
633 k *= 2;
634 }
635
636 hash = memdup(policy_digest->buffer, policy_digest->size);
637 if (!hash)
638 return log_oom();
639
640 if (DEBUG_LOGGING) {
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));
643 }
644
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;
651
652 r = 0;
653
654 finish:
655 primary = flush_context_verbose(c.esys_context, primary);
656 return r;
657 }
658
659 int tpm2_unseal(
660 const char *device,
661 uint32_t pcr_mask,
662 const void *blob,
663 size_t blob_size,
664 const void *known_policy_hash,
665 size_t known_policy_hash_size,
666 void **ret_secret,
667 size_t *ret_secret_size) {
668
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 = {};
676 size_t offset = 0;
677 TSS2_RC rc;
678 usec_t start;
679 int r;
680
681 assert(blob);
682 assert(blob_size > 0);
683 assert(known_policy_hash_size == 0 || known_policy_hash);
684 assert(ret_secret);
685 assert(ret_secret_size);
686
687 assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */
688
689 r = dlopen_tpm2();
690 if (r < 0)
691 return log_error_errno(r, "TPM2 support is not installed.");
692
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. */
700
701 start = now(CLOCK_MONOTONIC);
702
703 log_debug("Unmarshalling private part of HMAC key.");
704
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));
709
710 log_debug("Unmarshalling public part of HMAC key.");
711
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));
716
717 r = tpm2_init(device, &c);
718 if (r < 0)
719 return r;
720
721 r = tpm2_make_pcr_session(c.esys_context, pcr_mask, &session, &policy_digest);
722 if (r < 0)
723 goto finish;
724
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.");
731
732 r = tpm2_make_primary(c.esys_context, &primary);
733 if (r < 0)
734 return r;
735
736 log_debug("Loading HMAC key into TPM.");
737
738 rc = sym_Esys_Load(
739 c.esys_context,
740 primary,
741 ESYS_TR_PASSWORD,
742 ESYS_TR_NONE,
743 ESYS_TR_NONE,
744 &private,
745 &public,
746 &hmac_key);
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));
750 goto finish;
751 }
752
753 log_debug("Unsealing HMAC key.");
754
755 rc = sym_Esys_Unseal(
756 c.esys_context,
757 hmac_key,
758 session,
759 ESYS_TR_NONE,
760 ESYS_TR_NONE,
761 &unsealed);
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));
765 goto finish;
766 }
767
768 secret = memdup(unsealed->buffer, unsealed->size);
769 explicit_bzero_safe(unsealed->buffer, unsealed->size);
770 if (!secret) {
771 r = log_oom();
772 goto finish;
773 }
774
775 if (DEBUG_LOGGING) {
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));
778 }
779
780 *ret_secret = TAKE_PTR(secret);
781 *ret_secret_size = unsealed->size;
782
783 r = 0;
784
785 finish:
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);
789 return r;
790 }
791
792 #endif
793
794 int tpm2_list_devices(void) {
795 #if HAVE_TPM2
796 _cleanup_(table_unrefp) Table *t = NULL;
797 _cleanup_(closedirp) DIR *d = NULL;
798 int r;
799
800 r = dlopen_tpm2();
801 if (r < 0)
802 return log_error_errno(r, "TPM2 support is not installed.");
803
804 t = table_new("path", "device", "driver");
805 if (!t)
806 return log_oom();
807
808 d = opendir("/sys/class/tpmrm");
809 if (!d) {
810 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open /sys/class/tpmrm: %m");
811 if (errno != ENOENT)
812 return -errno;
813 } else {
814 for (;;) {
815 _cleanup_free_ char *device_path = NULL, *device = NULL, *driver_path = NULL, *driver = NULL, *node = NULL;
816 struct dirent *de;
817
818 de = readdir_no_dot(d);
819 if (!de)
820 break;
821
822 device_path = path_join("/sys/class/tpmrm", de->d_name, "device");
823 if (!device_path)
824 return log_oom();
825
826 r = readlink_malloc(device_path, &device);
827 if (r < 0)
828 log_debug_errno(r, "Failed to read device symlink %s, ignoring: %m", device_path);
829 else {
830 driver_path = path_join(device_path, "driver");
831 if (!driver_path)
832 return log_oom();
833
834 r = readlink_malloc(driver_path, &driver);
835 if (r < 0)
836 log_debug_errno(r, "Failed to read driver symlink %s, ignoring: %m", driver_path);
837 }
838
839 node = path_join("/dev", de->d_name);
840 if (!node)
841 return log_oom();
842
843 r = table_add_many(
844 t,
845 TABLE_PATH, node,
846 TABLE_STRING, device ? last_path_component(device) : NULL,
847 TABLE_STRING, driver ? last_path_component(driver) : NULL);
848 if (r < 0)
849 return table_log_add_error(r);
850 }
851 }
852
853 if (table_get_rows(t) <= 1) {
854 log_info("No suitable TPM2 devices found.");
855 return 0;
856 }
857
858 r = table_print(t, stdout);
859 if (r < 0)
860 return log_error_errno(r, "Failed to show device table: %m");
861
862 return 0;
863 #else
864 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
865 "TPM2 not supported on this build.");
866 #endif
867 }
868
869 int tpm2_find_device_auto(
870 int log_level, /* log level when no device is found */
871 char **ret) {
872 #if HAVE_TPM2
873 _cleanup_(closedirp) DIR *d = NULL;
874 int r;
875
876 r = dlopen_tpm2();
877 if (r < 0)
878 return log_error_errno(r, "TPM2 support is not installed.");
879
880 d = opendir("/sys/class/tpmrm");
881 if (!d) {
882 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
883 "Failed to open /sys/class/tpmrm: %m");
884 if (errno != ENOENT)
885 return -errno;
886 } else {
887 _cleanup_free_ char *node = NULL;
888
889 for (;;) {
890 struct dirent *de;
891
892 de = readdir_no_dot(d);
893 if (!de)
894 break;
895
896 if (node)
897 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
898 "More than one TPM2 (tpmrm) device found.");
899
900 node = path_join("/dev", de->d_name);
901 if (!node)
902 return log_oom();
903 }
904
905 if (node) {
906 *ret = TAKE_PTR(node);
907 return 0;
908 }
909 }
910
911 return log_full_errno(log_level, SYNTHETIC_ERRNO(ENODEV), "No TPM2 (tpmrm) device found.");
912 #else
913 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
914 "TPM2 not supported on this build.");
915 #endif
916 }
917
918 int tpm2_parse_pcrs(const char *s, uint32_t *ret) {
919 const char *p = s;
920 uint32_t mask = 0;
921 int r;
922
923 assert(s);
924
925 if (isempty(s)) {
926 *ret = 0;
927 return 0;
928 }
929
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
933 * avoid escaping. */
934
935 for (;;) {
936 _cleanup_free_ char *pcr = NULL;
937 unsigned n;
938
939 r = extract_first_word(&p, &pcr, ",+", EXTRACT_DONT_COALESCE_SEPARATORS);
940 if (r == 0)
941 break;
942 if (r < 0)
943 return log_error_errno(r, "Failed to parse PCR list: %s", s);
944
945 r = safe_atou(pcr, &n);
946 if (r < 0)
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);
951
952 mask |= UINT32_C(1) << n;
953 }
954
955 *ret = mask;
956 return 0;
957 }
958
959 int tpm2_make_luks2_json(
960 int keyslot,
961 uint32_t pcr_mask,
962 const void *blob,
963 size_t blob_size,
964 const void *policy_hash,
965 size_t policy_hash_size,
966 JsonVariant **ret) {
967
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];
971 unsigned n_pcrs = 0;
972 int r;
973
974 assert(blob || blob_size == 0);
975 assert(policy_hash || policy_hash_size == 0);
976
977 if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
978 return -ENOMEM;
979
980 for (unsigned i = 0; i < ELEMENTSOF(pcr_array); i++) {
981 if ((pcr_mask & (UINT32_C(1) << i)) == 0)
982 continue;
983
984 r = json_variant_new_integer(pcr_array + n_pcrs, i);
985 if (r < 0) {
986 json_variant_unref_many(pcr_array, n_pcrs);
987 return -ENOMEM;
988 }
989
990 n_pcrs++;
991 }
992
993 r = json_variant_new_array(&a, pcr_array, n_pcrs);
994 json_variant_unref_many(pcr_array, n_pcrs);
995 if (r < 0)
996 return -ENOMEM;
997
998 r = json_build(&v,
999 JSON_BUILD_OBJECT(
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))));
1005 if (r < 0)
1006 return r;
1007
1008 if (ret)
1009 *ret = TAKE_PTR(v);
1010
1011 return keyslot;
1012 }