]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/tpm2-util.c
tpm2-util: do not serialize tpm2 bank if none is specified
[thirdparty/systemd.git] / src / shared / tpm2-util.c
CommitLineData
5e521624
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
cb19bdae
LP
3#include <sys/file.h>
4
5e521624 5#include "alloc-util.h"
28db6fbf 6#include "constants.h"
d37c312b 7#include "creds-util.h"
fdf6c27c 8#include "cryptsetup-util.h"
5e521624
LP
9#include "dirent-util.h"
10#include "dlfcn-util.h"
fdf6c27c
LP
11#include "efi-api.h"
12#include "extract-word.h"
5e521624 13#include "fd-util.h"
6a0779cb 14#include "fileio.h"
5e521624
LP
15#include "format-table.h"
16#include "fs-util.h"
17#include "hexdecoct.h"
aae6eb96 18#include "hmac.h"
6270b2e6 19#include "initrd-util.h"
cb19bdae 20#include "io-util.h"
acbb504e 21#include "lock-util.h"
a12bc99e
ZJS
22#include "log.h"
23#include "logarithm.h"
5e521624 24#include "memory-util.h"
cb19bdae 25#include "mkdir.h"
6270b2e6 26#include "nulstr-util.h"
fdf6c27c 27#include "parse-util.h"
5e521624 28#include "random-util.h"
d37c312b 29#include "recurse-dir.h"
2f5a892a 30#include "sha256.h"
323eb480 31#include "sort-util.h"
cb835a2e 32#include "sparse-endian.h"
fdf6c27c 33#include "stat-util.h"
96ead603 34#include "string-table.h"
cb19bdae 35#include "sync-util.h"
5e521624 36#include "time-util.h"
fdf6c27c
LP
37#include "tpm2-util.h"
38#include "virt.h"
5e521624 39
81d61d6a
NL
40#if HAVE_OPENSSL
41# include <openssl/hmac.h>
42#endif
43
fdf6c27c 44#if HAVE_TPM2
5e521624
LP
45static void *libtss2_esys_dl = NULL;
46static void *libtss2_rc_dl = NULL;
47static void *libtss2_mu_dl = NULL;
48
9dbabd0a
LP
49static DLSYM_FUNCTION(Esys_Create);
50static DLSYM_FUNCTION(Esys_CreateLoaded);
51static DLSYM_FUNCTION(Esys_CreatePrimary);
52static DLSYM_FUNCTION(Esys_EvictControl);
53static DLSYM_FUNCTION(Esys_Finalize);
54static DLSYM_FUNCTION(Esys_FlushContext);
55static DLSYM_FUNCTION(Esys_Free);
56static DLSYM_FUNCTION(Esys_GetCapability);
57static DLSYM_FUNCTION(Esys_GetRandom);
58static DLSYM_FUNCTION(Esys_Import);
59static DLSYM_FUNCTION(Esys_Initialize);
60static DLSYM_FUNCTION(Esys_Load);
61static DLSYM_FUNCTION(Esys_LoadExternal);
62static DLSYM_FUNCTION(Esys_NV_DefineSpace);
63static DLSYM_FUNCTION(Esys_NV_UndefineSpace);
64static DLSYM_FUNCTION(Esys_NV_Write);
65static DLSYM_FUNCTION(Esys_PCR_Extend);
66static DLSYM_FUNCTION(Esys_PCR_Read);
67static DLSYM_FUNCTION(Esys_PolicyAuthValue);
68static DLSYM_FUNCTION(Esys_PolicyAuthorize);
69static DLSYM_FUNCTION(Esys_PolicyAuthorizeNV);
70static DLSYM_FUNCTION(Esys_PolicyGetDigest);
71static DLSYM_FUNCTION(Esys_PolicyOR);
72static DLSYM_FUNCTION(Esys_PolicyPCR);
9892b723 73static DLSYM_FUNCTION(Esys_PolicySigned);
9dbabd0a
LP
74static DLSYM_FUNCTION(Esys_ReadPublic);
75static DLSYM_FUNCTION(Esys_StartAuthSession);
76static DLSYM_FUNCTION(Esys_Startup);
77static DLSYM_FUNCTION(Esys_TestParms);
78static DLSYM_FUNCTION(Esys_TR_Close);
79static DLSYM_FUNCTION(Esys_TR_Deserialize);
80static DLSYM_FUNCTION(Esys_TR_FromTPMPublic);
81static DLSYM_FUNCTION(Esys_TR_GetName);
82static DLSYM_FUNCTION(Esys_TR_GetTpmHandle);
83static DLSYM_FUNCTION(Esys_TR_Serialize);
84static DLSYM_FUNCTION(Esys_TR_SetAuth);
85static DLSYM_FUNCTION(Esys_TRSess_GetAttributes);
9892b723 86static DLSYM_FUNCTION(Esys_TRSess_GetNonceTPM);
9dbabd0a
LP
87static DLSYM_FUNCTION(Esys_TRSess_SetAttributes);
88static DLSYM_FUNCTION(Esys_Unseal);
89static DLSYM_FUNCTION(Esys_VerifySignature);
b57a7b3d 90
9dbabd0a
LP
91static DLSYM_FUNCTION(Tss2_MU_TPM2_CC_Marshal);
92static DLSYM_FUNCTION(Tss2_MU_TPM2_HANDLE_Marshal);
93static DLSYM_FUNCTION(Tss2_MU_TPM2B_DIGEST_Marshal);
94static DLSYM_FUNCTION(Tss2_MU_TPM2B_ENCRYPTED_SECRET_Marshal);
95static DLSYM_FUNCTION(Tss2_MU_TPM2B_ENCRYPTED_SECRET_Unmarshal);
96static DLSYM_FUNCTION(Tss2_MU_TPM2B_NAME_Marshal);
97static DLSYM_FUNCTION(Tss2_MU_TPM2B_PRIVATE_Marshal);
98static DLSYM_FUNCTION(Tss2_MU_TPM2B_PRIVATE_Unmarshal);
99static DLSYM_FUNCTION(Tss2_MU_TPM2B_PUBLIC_Marshal);
100static DLSYM_FUNCTION(Tss2_MU_TPM2B_PUBLIC_Unmarshal);
101static DLSYM_FUNCTION(Tss2_MU_TPM2B_SENSITIVE_Marshal);
102static DLSYM_FUNCTION(Tss2_MU_TPML_PCR_SELECTION_Marshal);
103static DLSYM_FUNCTION(Tss2_MU_TPMS_NV_PUBLIC_Marshal);
104static DLSYM_FUNCTION(Tss2_MU_TPM2B_NV_PUBLIC_Marshal);
105static DLSYM_FUNCTION(Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal);
106static DLSYM_FUNCTION(Tss2_MU_TPMS_ECC_POINT_Marshal);
107static DLSYM_FUNCTION(Tss2_MU_TPMT_HA_Marshal);
108static DLSYM_FUNCTION(Tss2_MU_TPMT_PUBLIC_Marshal);
109static DLSYM_FUNCTION(Tss2_MU_UINT32_Marshal);
5e521624 110
9dbabd0a 111static DLSYM_FUNCTION(Tss2_RC_Decode);
ba723ea2 112
5e521624 113int dlopen_tpm2(void) {
d32f7a8e
ZJS
114 int r;
115
cd7c2077
LP
116 ELF_NOTE_DLOPEN("tpm",
117 "Support for TPM",
118 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
119 "libtss2-esys.so.0");
120
d32f7a8e
ZJS
121 r = dlopen_many_sym_or_warn(
122 &libtss2_esys_dl, "libtss2-esys.so.0", LOG_DEBUG,
123 DLSYM_ARG(Esys_Create),
cea525a9 124 DLSYM_ARG(Esys_CreateLoaded),
d32f7a8e 125 DLSYM_ARG(Esys_CreatePrimary),
acbb504e 126 DLSYM_ARG(Esys_EvictControl),
d32f7a8e
ZJS
127 DLSYM_ARG(Esys_Finalize),
128 DLSYM_ARG(Esys_FlushContext),
129 DLSYM_ARG(Esys_Free),
07697bfe 130 DLSYM_ARG(Esys_GetCapability),
d32f7a8e 131 DLSYM_ARG(Esys_GetRandom),
0a7874ad 132 DLSYM_ARG(Esys_Import),
d32f7a8e
ZJS
133 DLSYM_ARG(Esys_Initialize),
134 DLSYM_ARG(Esys_Load),
0d756413 135 DLSYM_ARG(Esys_LoadExternal),
199d7588
LP
136 DLSYM_ARG(Esys_NV_DefineSpace),
137 DLSYM_ARG(Esys_NV_UndefineSpace),
138 DLSYM_ARG(Esys_NV_Write),
1421943a 139 DLSYM_ARG(Esys_PCR_Extend),
321a9d9e 140 DLSYM_ARG(Esys_PCR_Read),
2f5a892a 141 DLSYM_ARG(Esys_PolicyAuthValue),
199d7588
LP
142 DLSYM_ARG(Esys_PolicyAuthorize),
143 DLSYM_ARG(Esys_PolicyAuthorizeNV),
d32f7a8e 144 DLSYM_ARG(Esys_PolicyGetDigest),
199d7588 145 DLSYM_ARG(Esys_PolicyOR),
d32f7a8e 146 DLSYM_ARG(Esys_PolicyPCR),
9892b723 147 DLSYM_ARG(Esys_PolicySigned),
acbb504e 148 DLSYM_ARG(Esys_ReadPublic),
d32f7a8e
ZJS
149 DLSYM_ARG(Esys_StartAuthSession),
150 DLSYM_ARG(Esys_Startup),
a47060bb 151 DLSYM_ARG(Esys_TestParms),
c8a85240 152 DLSYM_ARG(Esys_TR_Close),
ba723ea2 153 DLSYM_ARG(Esys_TR_Deserialize),
acbb504e 154 DLSYM_ARG(Esys_TR_FromTPMPublic),
0d756413 155 DLSYM_ARG(Esys_TR_GetName),
acbb504e 156 DLSYM_ARG(Esys_TR_Serialize),
2f5a892a 157 DLSYM_ARG(Esys_TR_SetAuth),
ba723ea2 158 DLSYM_ARG(Esys_TRSess_GetAttributes),
9892b723 159 DLSYM_ARG(Esys_TRSess_GetNonceTPM),
ba723ea2 160 DLSYM_ARG(Esys_TRSess_SetAttributes),
0d756413
LP
161 DLSYM_ARG(Esys_Unseal),
162 DLSYM_ARG(Esys_VerifySignature));
d32f7a8e
ZJS
163 if (r < 0)
164 return r;
165
13cf98f3
DS
166 /* Esys_TR_GetTpmHandle was added to tpm2-tss in version 2.4.0. Once we can set a minimum tpm2-tss
167 * version of 2.4.0 this sym can be moved up to the normal list above. */
168 r = dlsym_many_or_warn(libtss2_esys_dl, LOG_DEBUG, DLSYM_ARG_FORCE(Esys_TR_GetTpmHandle));
169 if (r < 0)
170 log_debug("libtss2-esys too old, does not include Esys_TR_GetTpmHandle.");
171
cd7c2077
LP
172 ELF_NOTE_DLOPEN("tpm",
173 "Support for TPM",
174 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
175 "libtss2-rc.so.0");
176
d32f7a8e
ZJS
177 r = dlopen_many_sym_or_warn(
178 &libtss2_rc_dl, "libtss2-rc.so.0", LOG_DEBUG,
179 DLSYM_ARG(Tss2_RC_Decode));
180 if (r < 0)
181 return r;
182
cd7c2077
LP
183 ELF_NOTE_DLOPEN("tpm",
184 "Support for TPM",
185 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
186 "libtss2-mu.so.0");
187
d32f7a8e
ZJS
188 return dlopen_many_sym_or_warn(
189 &libtss2_mu_dl, "libtss2-mu.so.0", LOG_DEBUG,
dcbc4674 190 DLSYM_ARG(Tss2_MU_TPM2_CC_Marshal),
0a7874ad
DS
191 DLSYM_ARG(Tss2_MU_TPM2_HANDLE_Marshal),
192 DLSYM_ARG(Tss2_MU_TPM2B_DIGEST_Marshal),
193 DLSYM_ARG(Tss2_MU_TPM2B_ENCRYPTED_SECRET_Marshal),
194 DLSYM_ARG(Tss2_MU_TPM2B_ENCRYPTED_SECRET_Unmarshal),
195 DLSYM_ARG(Tss2_MU_TPM2B_NAME_Marshal),
d32f7a8e
ZJS
196 DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal),
197 DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal),
198 DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal),
dbae4b95 199 DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal),
0a7874ad 200 DLSYM_ARG(Tss2_MU_TPM2B_SENSITIVE_Marshal),
dcbc4674 201 DLSYM_ARG(Tss2_MU_TPML_PCR_SELECTION_Marshal),
199d7588
LP
202 DLSYM_ARG(Tss2_MU_TPMS_NV_PUBLIC_Marshal),
203 DLSYM_ARG(Tss2_MU_TPM2B_NV_PUBLIC_Marshal),
204 DLSYM_ARG(Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal),
0a7874ad 205 DLSYM_ARG(Tss2_MU_TPMS_ECC_POINT_Marshal),
dbae4b95 206 DLSYM_ARG(Tss2_MU_TPMT_HA_Marshal),
0a7874ad
DS
207 DLSYM_ARG(Tss2_MU_TPMT_PUBLIC_Marshal),
208 DLSYM_ARG(Tss2_MU_UINT32_Marshal));
5e521624
LP
209}
210
2e64cb71 211void Esys_Freep(void *p) {
b57a7b3d
DS
212 if (*(void**) p)
213 sym_Esys_Free(*(void**) p);
214}
215
3a35d6cd
DS
216/* Get a specific TPM capability (or capabilities).
217 *
218 * Returns 0 if there are no more capability properties of the requested type, or 1 if there are more, or < 0
219 * on any error. Both 0 and 1 indicate this completed successfully, but do not indicate how many capability
220 * properties were provided in 'ret_capability_data'. To find the number of provided properties, check the
221 * specific type's 'count' field (e.g. for TPM2_CAP_ALGS, check ret_capability_data->algorithms.count).
222 *
223 * This calls TPM2_GetCapability() and does not alter the provided data, so it is important to understand how
224 * that TPM function works. It is recommended to check the TCG TPM specification Part 3 ("Commands") section
225 * on TPM2_GetCapability() for full details, but a short summary is: if this returns 0, all available
226 * properties have been provided in ret_capability_data, or no properties were available. If this returns 1,
227 * there are between 1 and "count" properties provided in ret_capability_data, and there are more available.
228 * Note that this may provide less than "count" properties even if the TPM has more available. Also, each
229 * capability category may have more specific requirements than described here; see the spec for exact
230 * details. */
231static int tpm2_get_capability(
232 Tpm2Context *c,
233 TPM2_CAP capability,
234 uint32_t property,
235 uint32_t count,
236 TPMU_CAPABILITIES *ret_capability_data) {
237
238 _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *capabilities = NULL;
239 TPMI_YES_NO more;
240 TSS2_RC rc;
241
242 assert(c);
243
244 log_debug("Getting TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 " count %" PRIu32 ".",
245 capability, property, count);
246
247 rc = sym_Esys_GetCapability(
248 c->esys_context,
249 ESYS_TR_NONE,
250 ESYS_TR_NONE,
251 ESYS_TR_NONE,
252 capability,
253 property,
254 count,
255 &more,
256 &capabilities);
ae17fcb6
LP
257 if (rc == TPM2_RC_VALUE)
258 return log_debug_errno(SYNTHETIC_ERRNO(ENXIO),
259 "Requested TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 " apparently doesn't exist: %s",
260 capability, property, sym_Tss2_RC_Decode(rc));
3a35d6cd 261 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 262 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3a35d6cd
DS
263 "Failed to get TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 ": %s",
264 capability, property, sym_Tss2_RC_Decode(rc));
3a35d6cd 265 if (capabilities->capability != capability)
f9a0ee75 266 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3a35d6cd
DS
267 "TPM provided wrong capability: 0x%04" PRIx32 " instead of 0x%04" PRIx32 ".",
268 capabilities->capability, capability);
269
270 if (ret_capability_data)
271 *ret_capability_data = capabilities->data;
272
273 return more == TPM2_YES;
274}
275
adbf0c8c
DS
276#define TPMA_CC_TO_TPM2_CC(cca) (((cca) & TPMA_CC_COMMANDINDEX_MASK) >> TPMA_CC_COMMANDINDEX_SHIFT)
277
3a35d6cd
DS
278static int tpm2_cache_capabilities(Tpm2Context *c) {
279 TPMU_CAPABILITIES capability;
280 int r;
281
282 assert(c);
283
cbc92a31
DS
284 /* Cache the algorithms. The spec indicates supported algorithms can only be modified during runtime
285 * by the SetAlgorithmSet() command. Unfortunately, the spec doesn't require a TPM reinitialization
286 * after changing the algorithm set (unless the PCR algorithms are changed). However, the spec also
287 * indicates the TPM behavior after SetAlgorithmSet() is "vendor-dependent", giving the example of
627cdcc7 288 * flushing sessions and objects, erasing policies, etc. So, if the algorithm set is programmatically
cbc92a31
DS
289 * changed while we are performing some operation, it's reasonable to assume it will break us even if
290 * we don't cache the algorithms, thus they should be "safe" to cache. */
291 TPM2_ALG_ID current_alg = TPM2_ALG_FIRST;
292 for (;;) {
293 r = tpm2_get_capability(
294 c,
295 TPM2_CAP_ALGS,
296 (uint32_t) current_alg, /* The spec states to cast TPM2_ALG_ID to uint32_t. */
297 TPM2_MAX_CAP_ALGS,
298 &capability);
299 if (r < 0)
300 return r;
301
302 TPML_ALG_PROPERTY algorithms = capability.algorithms;
303
304 /* We should never get 0; the TPM must support some algorithms, and it must not set 'more' if
305 * there are no more. */
306 assert(algorithms.count > 0);
307
308 if (!GREEDY_REALLOC_APPEND(
309 c->capability_algorithms,
310 c->n_capability_algorithms,
311 algorithms.algProperties,
312 algorithms.count))
f9a0ee75 313 return log_oom_debug();
cbc92a31
DS
314
315 if (r == 0)
316 break;
317
318 /* Set current_alg to alg id after last alg id the TPM provided */
319 current_alg = algorithms.algProperties[algorithms.count - 1].alg + 1;
320 }
321
adbf0c8c 322 /* Cache the command capabilities. The spec isn't actually clear if commands can be added/removed
627cdcc7 323 * while running, but that would be crazy, so let's hope it is not possible. */
adbf0c8c
DS
324 TPM2_CC current_cc = TPM2_CC_FIRST;
325 for (;;) {
326 r = tpm2_get_capability(
327 c,
328 TPM2_CAP_COMMANDS,
329 current_cc,
330 TPM2_MAX_CAP_CC,
331 &capability);
332 if (r < 0)
333 return r;
334
335 TPML_CCA commands = capability.command;
336
337 /* We should never get 0; the TPM must support some commands, and it must not set 'more' if
338 * there are no more. */
339 assert(commands.count > 0);
340
341 if (!GREEDY_REALLOC_APPEND(
342 c->capability_commands,
343 c->n_capability_commands,
344 commands.commandAttributes,
345 commands.count))
f9a0ee75 346 return log_oom_debug();
adbf0c8c
DS
347
348 if (r == 0)
349 break;
350
351 /* Set current_cc to index after last cc the TPM provided */
352 current_cc = TPMA_CC_TO_TPM2_CC(commands.commandAttributes[commands.count - 1]) + 1;
353 }
354
639dca03
DS
355 /* Cache the ECC curves. The spec isn't actually clear if ECC curves can be added/removed
356 * while running, but that would be crazy, so let's hope it is not possible. */
357 TPM2_ECC_CURVE current_ecc_curve = TPM2_ECC_NONE;
358 for (;;) {
359 r = tpm2_get_capability(
360 c,
361 TPM2_CAP_ECC_CURVES,
362 current_ecc_curve,
363 TPM2_MAX_ECC_CURVES,
364 &capability);
ae17fcb6
LP
365 if (r == -ENXIO) /* If the TPM doesn't support ECC, it might return TPM2_RC_VALUE rather than capability.eccCurves == 0 */
366 break;
639dca03
DS
367 if (r < 0)
368 return r;
369
370 TPML_ECC_CURVE ecc_curves = capability.eccCurves;
371
372 /* ECC support isn't required */
373 if (ecc_curves.count == 0)
374 break;
375
376 if (!GREEDY_REALLOC_APPEND(
377 c->capability_ecc_curves,
378 c->n_capability_ecc_curves,
379 ecc_curves.eccCurves,
380 ecc_curves.count))
381 return log_oom_debug();
382
383 if (r == 0)
384 break;
385
386 /* Set current_ecc_curve to index after last ecc curve the TPM provided */
387 current_ecc_curve = ecc_curves.eccCurves[ecc_curves.count - 1] + 1;
388 }
389
3a35d6cd
DS
390 /* Cache the PCR capabilities, which are safe to cache, as the only way they can change is
391 * TPM2_PCR_Allocate(), which changes the allocation after the next _TPM_Init(). If the TPM is
392 * reinitialized while we are using it, all our context and sessions will be invalid, so we can
393 * safely assume the TPM PCR allocation will not change while we are using it. */
394 r = tpm2_get_capability(
395 c,
396 TPM2_CAP_PCRS,
397 /* property= */ 0,
398 /* count= */ 1,
399 &capability);
400 if (r < 0)
401 return r;
402 if (r == 1)
403 /* This should never happen. Part 3 ("Commands") of the TCG TPM2 spec in the section for
404 * TPM2_GetCapability states: "TPM_CAP_PCRS – Returns the current allocation of PCR in a
405 * TPML_PCR_SELECTION. The property parameter shall be zero. The TPM will always respond to
406 * this command with the full PCR allocation and moreData will be NO." */
f9a0ee75 407 log_debug("TPM bug: reported multiple PCR sets; using only first set.");
3a35d6cd
DS
408 c->capability_pcrs = capability.assignedPCR;
409
410 return 0;
411}
412
cbc92a31
DS
413/* Get the TPMA_ALGORITHM for a TPM2_ALG_ID. Returns true if the TPM supports the algorithm and the
414 * TPMA_ALGORITHM is provided, otherwise false. */
415static bool tpm2_get_capability_alg(Tpm2Context *c, TPM2_ALG_ID alg, TPMA_ALGORITHM *ret) {
a47060bb
DS
416 assert(c);
417
cbc92a31
DS
418 FOREACH_ARRAY(alg_prop, c->capability_algorithms, c->n_capability_algorithms)
419 if (alg_prop->alg == alg) {
420 if (ret)
421 *ret = alg_prop->algProperties;
422 return true;
423 }
a47060bb 424
cbc92a31 425 log_debug("TPM does not support alg 0x%02" PRIx16 ".", alg);
a47060bb 426 if (ret)
cbc92a31 427 *ret = 0;
a47060bb 428
cbc92a31 429 return false;
a47060bb
DS
430}
431
cbc92a31 432bool tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg) {
a47060bb
DS
433 return tpm2_get_capability_alg(c, alg, NULL);
434}
435
adbf0c8c
DS
436/* Get the TPMA_CC for a TPM2_CC. Returns true if the TPM supports the command and the TPMA_CC is provided,
437 * otherwise false. */
438static bool tpm2_get_capability_command(Tpm2Context *c, TPM2_CC command, TPMA_CC *ret) {
439 assert(c);
440
441 FOREACH_ARRAY(cca, c->capability_commands, c->n_capability_commands)
442 if (TPMA_CC_TO_TPM2_CC(*cca) == command) {
443 if (ret)
444 *ret = *cca;
445 return true;
446 }
447
448 log_debug("TPM does not support command 0x%04" PRIx32 ".", command);
449 if (ret)
450 *ret = 0;
451
452 return false;
453}
454
455bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command) {
456 return tpm2_get_capability_command(c, command, NULL);
457}
458
639dca03
DS
459/* Returns true if the TPM supports the ECC curve, otherwise false. */
460bool tpm2_supports_ecc_curve(Tpm2Context *c, TPM2_ECC_CURVE ecc_curve) {
461 assert(c);
f4f5b3a9 462
639dca03
DS
463 FOREACH_ARRAY(curve, c->capability_ecc_curves, c->n_capability_ecc_curves)
464 if (*curve == ecc_curve)
465 return true;
f4f5b3a9 466
639dca03
DS
467 log_debug("TPM does not support ECC curve 0x%" PRIx16 ".", ecc_curve);
468 return false;
f4f5b3a9
DS
469}
470
c8a85240
DS
471/* Query the TPM for populated handles.
472 *
473 * This provides an array of handle indexes populated in the TPM, starting at the requested handle. The array will
474 * contain only populated handle addresses (which might not include the requested handle). The number of
475 * handles will be no more than the 'max' number requested. This will not search past the end of the handle
476 * range (i.e. handle & 0xff000000).
477 *
478 * Returns 0 if all populated handles in the range (starting at the requested handle) were provided (or no
479 * handles were in the range), or 1 if there are more populated handles in the range, or < 0 on any error. */
480static int tpm2_get_capability_handles(
481 Tpm2Context *c,
482 TPM2_HANDLE start,
483 size_t max,
484 TPM2_HANDLE **ret_handles,
485 size_t *ret_n_handles) {
486
487 _cleanup_free_ TPM2_HANDLE *handles = NULL;
488 size_t n_handles = 0;
489 TPM2_HANDLE current = start;
490 int r = 0;
491
492 assert(c);
493 assert(ret_handles);
494 assert(ret_n_handles);
495
70140069
DS
496 max = MIN(max, UINT32_MAX);
497
c8a85240
DS
498 while (max > 0) {
499 TPMU_CAPABILITIES capability;
500 r = tpm2_get_capability(c, TPM2_CAP_HANDLES, current, (uint32_t) max, &capability);
501 if (r < 0)
502 return r;
503
504 TPML_HANDLE handle_list = capability.handles;
505 if (handle_list.count == 0)
506 break;
507
508 assert(handle_list.count <= max);
509
510 if (n_handles > SIZE_MAX - handle_list.count)
f9a0ee75 511 return log_oom_debug();
c8a85240 512
70140069 513 if (!GREEDY_REALLOC_APPEND(handles, n_handles, handle_list.handle, handle_list.count))
f9a0ee75 514 return log_oom_debug();
c8a85240 515
c8a85240 516 max -= handle_list.count;
c8a85240
DS
517
518 /* Update current to the handle index after the last handle in the list. */
519 current = handles[n_handles - 1] + 1;
520
521 if (r == 0)
522 /* No more handles in this range. */
523 break;
524 }
525
526 *ret_handles = TAKE_PTR(handles);
527 *ret_n_handles = n_handles;
528
529 return r;
530}
531
532#define TPM2_HANDLE_RANGE(h) ((TPM2_HANDLE)((h) & TPM2_HR_RANGE_MASK))
533#define TPM2_HANDLE_TYPE(h) ((TPM2_HT)(TPM2_HANDLE_RANGE(h) >> TPM2_HR_SHIFT))
534
535/* Returns 1 if the handle is populated in the TPM, 0 if not, and < 0 on any error. */
536static int tpm2_get_capability_handle(Tpm2Context *c, TPM2_HANDLE handle) {
537 _cleanup_free_ TPM2_HANDLE *handles = NULL;
538 size_t n_handles = 0;
539 int r;
540
541 r = tpm2_get_capability_handles(c, handle, 1, &handles, &n_handles);
542 if (r < 0)
543 return r;
544
545 return n_handles == 0 ? false : handles[0] == handle;
546}
547
a47060bb
DS
548/* Returns 1 if the TPM supports the parms, or 0 if the TPM does not support the parms. */
549bool tpm2_test_parms(Tpm2Context *c, TPMI_ALG_PUBLIC alg, const TPMU_PUBLIC_PARMS *parms) {
550 TSS2_RC rc;
551
552 assert(c);
553 assert(parms);
554
555 TPMT_PUBLIC_PARMS parameters = {
556 .type = alg,
557 .parameters = *parms,
558 };
559
560 rc = sym_Esys_TestParms(c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &parameters);
561 if (rc != TSS2_RC_SUCCESS)
562 /* The spec says if the parms are not supported the TPM returns "...the appropriate
563 * unmarshaling error if a parameter is not valid". Since the spec (currently) defines 15
564 * unmarshaling errors, instead of checking for them all here, let's just assume any error
565 * indicates unsupported parms, and log the specific error text. */
566 log_debug("TPM does not support tested parms: %s", sym_Tss2_RC_Decode(rc));
567
568 return rc == TSS2_RC_SUCCESS;
569}
570
cf1ab844 571static bool tpm2_supports_tpmt_public(Tpm2Context *c, const TPMT_PUBLIC *public) {
f4f5b3a9
DS
572 assert(c);
573 assert(public);
574
575 return tpm2_test_parms(c, public->type, &public->parameters);
576}
577
cf1ab844 578static bool tpm2_supports_tpmt_sym_def_object(Tpm2Context *c, const TPMT_SYM_DEF_OBJECT *parameters) {
a47060bb
DS
579 assert(c);
580 assert(parameters);
581
582 TPMU_PUBLIC_PARMS parms = {
583 .symDetail.sym = *parameters,
584 };
585
586 return tpm2_test_parms(c, TPM2_ALG_SYMCIPHER, &parms);
587}
588
cf1ab844 589static bool tpm2_supports_tpmt_sym_def(Tpm2Context *c, const TPMT_SYM_DEF *parameters) {
a47060bb
DS
590 assert(c);
591 assert(parameters);
592
593 /* Unfortunately, TPMT_SYM_DEF and TPMT_SYM_DEF_OBEJECT are separately defined, even though they are
594 * functionally identical. */
595 TPMT_SYM_DEF_OBJECT object = {
596 .algorithm = parameters->algorithm,
597 .keyBits = parameters->keyBits,
598 .mode = parameters->mode,
599 };
600
601 return tpm2_supports_tpmt_sym_def_object(c, &object);
602}
603
68d084ce
DS
604static Tpm2Context *tpm2_context_free(Tpm2Context *c) {
605 if (!c)
606 return NULL;
5e521624
LP
607
608 if (c->esys_context)
609 sym_Esys_Finalize(&c->esys_context);
610
611 c->tcti_context = mfree(c->tcti_context);
f2592ef0 612 c->tcti_dl = safe_dlclose(c->tcti_dl);
5e521624 613
cbc92a31 614 c->capability_algorithms = mfree(c->capability_algorithms);
adbf0c8c 615 c->capability_commands = mfree(c->capability_commands);
639dca03 616 c->capability_ecc_curves = mfree(c->capability_ecc_curves);
adbf0c8c 617
68d084ce 618 return mfree(c);
5e521624
LP
619}
620
68d084ce
DS
621DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free);
622
a47060bb
DS
623static const TPMT_SYM_DEF SESSION_TEMPLATE_SYM_AES_128_CFB = {
624 .algorithm = TPM2_ALG_AES,
625 .keyBits.aes = 128,
626 .mode.aes = TPM2_ALG_CFB, /* The spec requires sessions to use CFB. */
627};
628
68d084ce 629int tpm2_context_new(const char *device, Tpm2Context **ret_context) {
1dc8f518 630 _cleanup_(tpm2_context_unrefp) Tpm2Context *context = NULL;
5e521624
LP
631 TSS2_RC rc;
632 int r;
633
68d084ce
DS
634 assert(ret_context);
635
d70e4bc9 636 context = new(Tpm2Context, 1);
68d084ce 637 if (!context)
f9a0ee75 638 return log_oom_debug();
68d084ce 639
d70e4bc9
LP
640 *context = (Tpm2Context) {
641 .n_ref = 1,
642 };
68d084ce 643
5e521624
LP
644 r = dlopen_tpm2();
645 if (r < 0)
f9a0ee75 646 return log_debug_errno(r, "TPM2 support not installed: %m");
5e521624 647
34906680 648 if (!device) {
5e521624 649 device = secure_getenv("SYSTEMD_TPM2_DEVICE");
34906680
LP
650 if (device)
651 /* Setting the env var to an empty string forces tpm2-tss' own device picking
652 * logic to be used. */
653 device = empty_to_null(device);
654 else
655 /* If nothing was specified explicitly, we'll use a hardcoded default: the "device" tcti
656 * driver and the "/dev/tpmrm0" device. We do this since on some distributions the tpm2-abrmd
657 * might be used and we really don't want that, since it is a system service and that creates
658 * various ordering issues/deadlocks during early boot. */
659 device = "device:/dev/tpmrm0";
660 }
5e521624
LP
661
662 if (device) {
663 const char *param, *driver, *fn;
664 const TSS2_TCTI_INFO* info;
665 TSS2_TCTI_INFO_FUNC func;
666 size_t sz = 0;
667
668 param = strchr(device, ':');
669 if (param) {
50a08514 670 /* Syntax #1: Pair of driver string and arbitrary parameter */
2f82562b 671 driver = strndupa_safe(device, param - device);
50a08514 672 if (isempty(driver))
f9a0ee75 673 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name is empty, refusing.");
50a08514 674
5e521624 675 param++;
50a08514
LP
676 } else if (path_is_absolute(device) && path_is_valid(device)) {
677 /* Syntax #2: TPM device node */
5e521624
LP
678 driver = "device";
679 param = device;
50a08514 680 } else
f9a0ee75 681 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid TPM2 driver string, refusing.");
50a08514
LP
682
683 log_debug("Using TPM2 TCTI driver '%s' with device '%s'.", driver, param);
5e521624
LP
684
685 fn = strjoina("libtss2-tcti-", driver, ".so.0");
686
50a08514
LP
687 /* Better safe than sorry, let's refuse strings that cannot possibly be valid driver early, before going to disk. */
688 if (!filename_is_valid(fn))
f9a0ee75 689 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name '%s' not valid, refusing.", driver);
50a08514 690
68d084ce
DS
691 context->tcti_dl = dlopen(fn, RTLD_NOW);
692 if (!context->tcti_dl)
21a3bc6b 693 return log_debug_errno(SYNTHETIC_ERRNO(ENOPKG), "Failed to load %s: %s", fn, dlerror());
5e521624 694
dd6c0df6
LB
695 log_debug("Loaded '%s' via dlopen()", fn);
696
68d084ce 697 func = dlsym(context->tcti_dl, TSS2_TCTI_INFO_SYMBOL);
5e521624 698 if (!func)
f9a0ee75 699 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
700 "Failed to find TCTI info symbol " TSS2_TCTI_INFO_SYMBOL ": %s",
701 dlerror());
702
703 info = func();
704 if (!info)
f9a0ee75 705 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to get TCTI info data.");
5e521624 706
5e521624
LP
707 log_debug("Loaded TCTI module '%s' (%s) [Version %" PRIu32 "]", info->name, info->description, info->version);
708
21a3bc6b 709 rc = info->init(/* context= */ NULL, &sz, /* param= */ NULL);
5e521624 710 if (rc != TPM2_RC_SUCCESS)
f9a0ee75 711 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
712 "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc));
713
68d084ce
DS
714 context->tcti_context = malloc0(sz);
715 if (!context->tcti_context)
f9a0ee75 716 return log_oom_debug();
5e521624 717
68d084ce 718 rc = info->init(context->tcti_context, &sz, param);
5e521624 719 if (rc != TPM2_RC_SUCCESS)
f9a0ee75 720 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
721 "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc));
722 }
723
68d084ce 724 rc = sym_Esys_Initialize(&context->esys_context, context->tcti_context, NULL);
5e521624 725 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 726 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
727 "Failed to initialize TPM context: %s", sym_Tss2_RC_Decode(rc));
728
68d084ce 729 rc = sym_Esys_Startup(context->esys_context, TPM2_SU_CLEAR);
5e521624
LP
730 if (rc == TPM2_RC_INITIALIZE)
731 log_debug("TPM already started up.");
732 else if (rc == TSS2_RC_SUCCESS)
733 log_debug("TPM successfully started up.");
734 else
f9a0ee75 735 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
736 "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc));
737
3a35d6cd
DS
738 r = tpm2_cache_capabilities(context);
739 if (r < 0)
fcdd21ec 740 return log_debug_errno(r, "Failed to cache TPM capabilities: %m");
3a35d6cd 741
a47060bb 742 /* We require AES and CFB support for session encryption. */
cbc92a31 743 if (!tpm2_supports_alg(context, TPM2_ALG_AES))
21a3bc6b 744 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM does not support AES.");
a47060bb 745
cbc92a31 746 if (!tpm2_supports_alg(context, TPM2_ALG_CFB))
21a3bc6b 747 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM does not support CFB.");
a47060bb
DS
748
749 if (!tpm2_supports_tpmt_sym_def(context, &SESSION_TEMPLATE_SYM_AES_128_CFB))
21a3bc6b 750 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM does not support AES-128-CFB.");
a47060bb 751
68d084ce 752 *ret_context = TAKE_PTR(context);
5e521624
LP
753
754 return 0;
755}
756
21a3bc6b
LP
757int tpm2_context_new_or_warn(const char *device, Tpm2Context **ret_context) {
758 int r;
759
760 assert(ret_context);
761
762 r = tpm2_context_new(device, ret_context);
763 if (r == -EOPNOTSUPP)
764 return log_error_errno(r, "TPM device not usable as it does not support the required functionality (AES-128-CFB missing?).");
765 if (r == -ENOPKG)
766 return log_error_errno(r, "TPM TCTI driver not available.");
767 if (r == -ENOENT)
768 return log_error_errno(r, "TPM device not found.");
769 if (r < 0)
770 return log_error_errno(r, "Failed to create TPM2 context: %m");
771
772 return 0;
773}
774
c8a85240
DS
775static void tpm2_handle_cleanup(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle, bool flush) {
776 TSS2_RC rc;
777
16e16b8c
DS
778 if (!esys_context || esys_handle == ESYS_TR_NONE)
779 return;
780
c8a85240
DS
781 /* Closing the handle removes its reference from the esys_context, but leaves the corresponding
782 * handle in the actual TPM. Flushing the handle removes its reference from the esys_context as well
783 * as removing its corresponding handle from the actual TPM. */
784 if (flush)
785 rc = sym_Esys_FlushContext(esys_context, esys_handle);
786 else
1524184d
DS
787 /* We can't use Esys_TR_Close() because the tpm2-tss library does not use reference counting
788 * for handles, and a single Esys_TR_Close() will remove the handle (internal to the tpm2-tss
789 * library) that might be in use by other code that is using the same ESYS_CONTEXT. This
790 * directly affects us; for example the src/test/test-tpm2.c test function
791 * check_seal_unseal() will encounter this issue and will result in a failure when trying to
792 * cleanup (i.e. Esys_FlushContext) the transient primary key that the test function
793 * generates. However, not calling Esys_TR_Close() here should be ok, since any leaked handle
794 * references will be cleaned up when we free our ESYS_CONTEXT.
795 *
796 * An upstream bug is open here: https://github.com/tpm2-software/tpm2-tss/issues/2693 */
797 rc = TSS2_RC_SUCCESS; // FIXME: restore sym_Esys_TR_Close() use once tpm2-tss is fixed and adopted widely enough
798 if (rc != TSS2_RC_SUCCESS)
799 /* We ignore failures here (besides debug logging), since this is called in error paths,
800 * where we cannot do anything about failures anymore. And when it is called in successful
801 * codepaths by this time we already did what we wanted to do, and got the results we wanted
802 * so there's no reason to make this fail more loudly than necessary. */
c8a85240 803 log_debug("Failed to %s TPM handle, ignoring: %s", flush ? "flush" : "close", sym_Tss2_RC_Decode(rc));
16e16b8c
DS
804}
805
806Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle) {
807 if (!handle)
808 return NULL;
809
1dc8f518 810 _cleanup_(tpm2_context_unrefp) Tpm2Context *context = (Tpm2Context*)handle->tpm2_context;
c8a85240
DS
811 if (context)
812 tpm2_handle_cleanup(context->esys_context, handle->esys_handle, handle->flush);
16e16b8c
DS
813
814 return mfree(handle);
815}
816
817int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) {
1dc8f518 818 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
16e16b8c
DS
819
820 assert(ret_handle);
821
d70e4bc9 822 handle = new(Tpm2Handle, 1);
16e16b8c 823 if (!handle)
f9a0ee75 824 return log_oom_debug();
16e16b8c 825
d70e4bc9
LP
826 *handle = (Tpm2Handle) {
827 .tpm2_context = tpm2_context_ref(context),
828 .esys_handle = ESYS_TR_NONE,
c8a85240 829 .flush = true,
d70e4bc9 830 };
16e16b8c
DS
831
832 *ret_handle = TAKE_PTR(handle);
833
834 return 0;
835}
836
add8091c
LP
837static int tpm2_read_public(
838 Tpm2Context *c,
839 const Tpm2Handle *session,
840 const Tpm2Handle *handle,
841 TPM2B_PUBLIC **ret_public,
842 TPM2B_NAME **ret_name,
843 TPM2B_NAME **ret_qname) {
844
845 TSS2_RC rc;
846
847 assert(c);
848 assert(handle);
849
850 rc = sym_Esys_ReadPublic(
851 c->esys_context,
852 handle->esys_handle,
853 session ? session->esys_handle : ESYS_TR_NONE,
854 ESYS_TR_NONE,
855 ESYS_TR_NONE,
856 ret_public,
857 ret_name,
858 ret_qname);
859 if (rc != TSS2_RC_SUCCESS)
860 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
861 "Failed to read public info: %s", sym_Tss2_RC_Decode(rc));
862
863 return 0;
864}
865
13cf98f3
DS
866/* Create a Tpm2Handle object that references a pre-existing handle in the TPM, at the handle index provided.
867 * This should be used only for persistent, transient, or NV handles; and the handle must already exist in
868 * the TPM at the specified handle index. The handle index should not be 0. Returns 1 if found, 0 if the
869 * index is empty, or < 0 on error. Also see tpm2_get_srk() below; the SRK is a commonly used persistent
870 * Tpm2Handle. */
871int tpm2_index_to_handle(
c8a85240 872 Tpm2Context *c,
13cf98f3 873 TPM2_HANDLE index,
c8a85240 874 const Tpm2Handle *session,
13cf98f3
DS
875 TPM2B_PUBLIC **ret_public,
876 TPM2B_NAME **ret_name,
877 TPM2B_NAME **ret_qname,
c8a85240
DS
878 Tpm2Handle **ret_handle) {
879
880 TSS2_RC rc;
881 int r;
882
883 assert(c);
c8a85240 884
382bfd90 885 /* Only allow persistent, transient, or NV index handle types. */
13cf98f3 886 switch (TPM2_HANDLE_TYPE(index)) {
c8a85240
DS
887 case TPM2_HT_PERSISTENT:
888 case TPM2_HT_NV_INDEX:
889 case TPM2_HT_TRANSIENT:
890 break;
891 case TPM2_HT_PCR:
382bfd90 892 /* PCR handles are referenced by their actual index number and do not need a Tpm2Handle */
f9a0ee75 893 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 894 "Invalid handle 0x%08" PRIx32 " (in PCR range).", index);
c8a85240
DS
895 case TPM2_HT_HMAC_SESSION:
896 case TPM2_HT_POLICY_SESSION:
382bfd90 897 /* Session indexes are only used internally by tpm2-tss (or lower code) */
f9a0ee75 898 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 899 "Invalid handle 0x%08" PRIx32 " (in session range).", index);
382bfd90
DS
900 case TPM2_HT_PERMANENT:
901 /* Permanent handles are defined, e.g. ESYS_TR_RH_OWNER. */
f9a0ee75 902 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 903 "Invalid handle 0x%08" PRIx32 " (in permanent range).", index);
c8a85240 904 default:
f9a0ee75 905 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 906 "Invalid handle 0x%08" PRIx32 " (in unknown range).", index);
c8a85240
DS
907 }
908
0f1cb04f
DS
909 /* For transient handles, the kernel tpm "resource manager" (i.e. /dev/tpmrm0) performs mapping
910 * which breaks GetCapability requests, so only check GetCapability if it's not a transient handle.
911 * https://bugzilla.kernel.org/show_bug.cgi?id=218009 */
912 if (TPM2_HANDLE_TYPE(index) != TPM2_HT_TRANSIENT) { // FIXME: once kernel bug is fixed, check transient handles too
9c180197
DS
913 r = tpm2_get_capability_handle(c, index);
914 if (r < 0)
915 return r;
916 if (r == 0) {
917 log_debug("TPM handle 0x%08" PRIx32 " not populated.", index);
918 if (ret_public)
919 *ret_public = NULL;
920 if (ret_name)
921 *ret_name = NULL;
922 if (ret_qname)
923 *ret_qname = NULL;
924 if (ret_handle)
925 *ret_handle = NULL;
926 return 0;
927 }
c8a85240
DS
928 }
929
930 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
931 r = tpm2_handle_new(c, &handle);
932 if (r < 0)
933 return r;
934
935 /* Since we didn't create this handle in the TPM (this is only creating an ESYS_TR handle for the
936 * pre-existing TPM handle), we shouldn't flush (or evict) it on cleanup. */
937 handle->flush = false;
938
939 rc = sym_Esys_TR_FromTPMPublic(
940 c->esys_context,
13cf98f3 941 index,
c8a85240
DS
942 session ? session->esys_handle : ESYS_TR_NONE,
943 ESYS_TR_NONE,
944 ESYS_TR_NONE,
945 &handle->esys_handle);
946 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 947 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
c8a85240
DS
948 "Failed to read public info: %s", sym_Tss2_RC_Decode(rc));
949
13cf98f3
DS
950 if (ret_public || ret_name || ret_qname) {
951 r = tpm2_read_public(c, session, handle, ret_public, ret_name, ret_qname);
952 if (r < 0)
953 return r;
954 }
955
956 if (ret_handle)
957 *ret_handle = TAKE_PTR(handle);
c8a85240
DS
958
959 return 1;
960}
961
13cf98f3
DS
962/* Get the handle index for the provided Tpm2Handle. */
963int tpm2_index_from_handle(Tpm2Context *c, const Tpm2Handle *handle, TPM2_HANDLE *ret_index) {
964 TSS2_RC rc;
965
966 assert(c);
967 assert(handle);
968 assert(ret_index);
969
970 /* Esys_TR_GetTpmHandle was added to tpm2-tss in version 2.4.0. Once we can set a minimum tpm2-tss
971 * version of 2.4.0 this check can be removed. */
972 if (!sym_Esys_TR_GetTpmHandle)
f9a0ee75 973 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
13cf98f3
DS
974 "libtss2-esys too old, does not include Esys_TR_GetTpmHandle.");
975
976 rc = sym_Esys_TR_GetTpmHandle(c->esys_context, handle->esys_handle, ret_index);
977 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 978 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
13cf98f3
DS
979 "Failed to get handle index: %s", sym_Tss2_RC_Decode(rc));
980
981 return 0;
982}
983
984/* Copy an object in the TPM at a transient handle to a persistent handle.
d2d29c3b 985 *
13cf98f3
DS
986 * The provided transient handle must exist in the TPM in the transient range. The persistent handle may be 0
987 * or any handle in the persistent range. If 0, this will try each handle in the persistent range, in
988 * ascending order, until an available one is found. If non-zero, only the requested persistent handle will
d2d29c3b
DS
989 * be used.
990 *
13cf98f3
DS
991 * Note that the persistent handle parameter is an handle index (i.e. number), while the transient handle is
992 * a Tpm2Handle object. The returned persistent handle will be a Tpm2Handle object that is located in the TPM
993 * at the requested persistent handle index (or the first available if none was requested).
994 *
d2d29c3b 995 * Returns 1 if the object was successfully persisted, or 0 if there is already a key at the requested
13cf98f3 996 * handle, or < 0 on error. Theoretically, this would also return 0 if no specific persistent handle is
fcdd21ec 997 * requested but all persistent handles are used, but it is extremely unlikely the TPM has enough internal
13cf98f3
DS
998 * memory to store the entire persistent range, in which case an error will be returned if the TPM is out of
999 * memory for persistent storage. The persistent handle is only provided when returning 1. */
d2d29c3b
DS
1000static int tpm2_persist_handle(
1001 Tpm2Context *c,
1002 const Tpm2Handle *transient_handle,
1003 const Tpm2Handle *session,
13cf98f3 1004 TPMI_DH_PERSISTENT persistent_handle_index,
d2d29c3b
DS
1005 Tpm2Handle **ret_persistent_handle) {
1006
1007 /* We don't use TPM2_PERSISTENT_FIRST and TPM2_PERSISTENT_LAST here due to:
1008 * https://github.com/systemd/systemd/pull/27713#issuecomment-1591864753 */
1009 TPMI_DH_PERSISTENT first = UINT32_C(0x81000000), last = UINT32_C(0x81ffffff);
1010 TSS2_RC rc;
1011 int r;
1012
1013 assert(c);
1014 assert(transient_handle);
1015
13cf98f3
DS
1016 /* If persistent handle index specified, only try that. */
1017 if (persistent_handle_index != 0) {
1018 if (TPM2_HANDLE_TYPE(persistent_handle_index) != TPM2_HT_PERSISTENT)
d2d29c3b 1019 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 1020 "Handle not in persistent range: 0x%x", persistent_handle_index);
d2d29c3b 1021
13cf98f3 1022 first = last = persistent_handle_index;
d2d29c3b
DS
1023 }
1024
1025 for (TPMI_DH_PERSISTENT requested = first; requested <= last; requested++) {
1026 _cleanup_(tpm2_handle_freep) Tpm2Handle *persistent_handle = NULL;
1027 r = tpm2_handle_new(c, &persistent_handle);
1028 if (r < 0)
1029 return r;
1030
1031 /* Since this is a persistent handle, don't flush it. */
1032 persistent_handle->flush = false;
1033
1034 rc = sym_Esys_EvictControl(
1035 c->esys_context,
1036 ESYS_TR_RH_OWNER,
1037 transient_handle->esys_handle,
1038 session ? session->esys_handle : ESYS_TR_PASSWORD,
1039 ESYS_TR_NONE,
1040 ESYS_TR_NONE,
1041 requested,
1042 &persistent_handle->esys_handle);
1043 if (rc == TSS2_RC_SUCCESS) {
1044 if (ret_persistent_handle)
1045 *ret_persistent_handle = TAKE_PTR(persistent_handle);
1046
1047 return 1;
1048 }
1049 if (rc != TPM2_RC_NV_DEFINED)
f9a0ee75 1050 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
d2d29c3b
DS
1051 "Failed to persist handle: %s", sym_Tss2_RC_Decode(rc));
1052 }
1053
1054 if (ret_persistent_handle)
1055 *ret_persistent_handle = NULL;
1056
1057 return 0;
1058}
1059
aba5dac3
LP
1060#define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited"
1061
23e9ccc2 1062static int tpm2_credit_random(Tpm2Context *c) {
5e521624
LP
1063 size_t rps, done = 0;
1064 TSS2_RC rc;
aba5dac3 1065 usec_t t;
5e521624
LP
1066 int r;
1067
1068 assert(c);
1069
1070 /* Pulls some entropy from the TPM and adds it into the kernel RNG pool. That way we can say that the
1071 * key we will ultimately generate with the kernel random pool is at least as good as the TPM's RNG,
1072 * but likely better. Note that we don't trust the TPM RNG very much, hence do not actually credit
1073 * any entropy. */
1074
aba5dac3
LP
1075 if (access(TPM2_CREDIT_RANDOM_FLAG_PATH, F_OK) < 0) {
1076 if (errno != ENOENT)
1077 log_debug_errno(errno, "Failed to detect if '" TPM2_CREDIT_RANDOM_FLAG_PATH "' exists, ignoring: %m");
1078 } else {
1079 log_debug("Not adding TPM2 entropy to the kernel random pool again.");
1080 return 0; /* Already done */
1081 }
1082
1083 t = now(CLOCK_MONOTONIC);
1084
5e521624
LP
1085 for (rps = random_pool_size(); rps > 0;) {
1086 _cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL;
1087
1088 rc = sym_Esys_GetRandom(
23e9ccc2 1089 c->esys_context,
5e521624
LP
1090 ESYS_TR_NONE,
1091 ESYS_TR_NONE,
1092 ESYS_TR_NONE,
1093 MIN(rps, 32U), /* 32 is supposedly a safe choice, given that AES 256bit keys are this long, and TPM2 baseline requires support for those. */
1094 &buffer);
1095 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 1096 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
1097 "Failed to acquire entropy from TPM: %s", sym_Tss2_RC_Decode(rc));
1098
1099 if (buffer->size == 0)
f9a0ee75 1100 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
1101 "Zero-sized entropy returned from TPM.");
1102
aba5dac3 1103 r = random_write_entropy(-1, buffer->buffer, buffer->size, /* credit= */ false);
5e521624 1104 if (r < 0)
f9a0ee75 1105 return log_debug_errno(r, "Failed wo write entropy to kernel: %m");
5e521624
LP
1106
1107 done += buffer->size;
1108 rps = LESS_BY(rps, buffer->size);
1109 }
1110
aba5dac3
LP
1111 log_debug("Added %zu bytes of TPM2 entropy to the kernel random pool in %s.", done, FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - t, 0));
1112
1113 r = touch(TPM2_CREDIT_RANDOM_FLAG_PATH);
1114 if (r < 0)
1115 log_debug_errno(r, "Failed to touch '" TPM2_CREDIT_RANDOM_FLAG_PATH "', ignoring: %m");
1116
5e521624
LP
1117 return 0;
1118}
1119
f4f5b3a9
DS
1120/* Get one of the legacy primary key templates.
1121 *
1122 * The legacy templates should only be used for older sealed data that did not use the SRK. Instead of a
1123 * persistent SRK, a transient key was created to seal the data and then flushed; and the exact same template
1124 * must be used to recreate the same transient key to unseal the data. The alg parameter must be TPM2_ALG_RSA
1125 * or TPM2_ALG_ECC. This does not check if the alg is actually supported on this TPM. */
1126static int tpm2_get_legacy_template(TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template) {
1127 /* Do not modify. */
1128 static const TPMT_PUBLIC legacy_ecc = {
1129 .type = TPM2_ALG_ECC,
1130 .nameAlg = TPM2_ALG_SHA256,
2216c27c
LP
1131 .objectAttributes =
1132 TPMA_OBJECT_RESTRICTED|
1133 TPMA_OBJECT_DECRYPT|
1134 TPMA_OBJECT_FIXEDTPM|
1135 TPMA_OBJECT_FIXEDPARENT|
1136 TPMA_OBJECT_SENSITIVEDATAORIGIN|
1137 TPMA_OBJECT_USERWITHAUTH,
f4f5b3a9
DS
1138 .parameters.eccDetail = {
1139 .symmetric = {
1140 .algorithm = TPM2_ALG_AES,
1141 .keyBits.aes = 128,
1142 .mode.aes = TPM2_ALG_CFB,
5e521624 1143 },
f4f5b3a9
DS
1144 .scheme.scheme = TPM2_ALG_NULL,
1145 .curveID = TPM2_ECC_NIST_P256,
1146 .kdf.scheme = TPM2_ALG_NULL,
5e521624 1147 },
f4f5b3a9
DS
1148 };
1149
1150 /* Do not modify. */
1151 static const TPMT_PUBLIC legacy_rsa = {
1152 .type = TPM2_ALG_RSA,
1153 .nameAlg = TPM2_ALG_SHA256,
1154 .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
1155 .parameters.rsaDetail = {
1156 .symmetric = {
1157 .algorithm = TPM2_ALG_AES,
1158 .keyBits.aes = 128,
1159 .mode.aes = TPM2_ALG_CFB,
acbb504e 1160 },
f4f5b3a9
DS
1161 .scheme.scheme = TPM2_ALG_NULL,
1162 .keyBits = 2048,
acbb504e 1163 },
f4f5b3a9
DS
1164 };
1165
1166 assert(ret_template);
1167
1168 if (alg == TPM2_ALG_ECC)
1169 *ret_template = legacy_ecc;
1170 else if (alg == TPM2_ALG_RSA)
1171 *ret_template = legacy_rsa;
1172 else
1173 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1174 "Unsupported legacy SRK alg: 0x%x", alg);
1175
1176 return 0;
1177}
1178
1179/* Get a Storage Root Key (SRK) template.
1180 *
1181 * The SRK template values are recommended by the "TCG TPM v2.0 Provisioning Guidance" document in section
1182 * 7.5.1 "Storage Primary Key (SRK) Templates", referencing "TCG EK Credential Profile for TPM Family 2.0".
1183 * The EK Credential Profile version 2.0 provides only a single template each for RSA and ECC, while later EK
1184 * Credential Profile versions provide more templates, and keep the original templates as "L-1" (for RSA) and
1185 * "L-2" (for ECC).
1186 *
1187 * https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance
1188 * https://trustedcomputinggroup.org/resource/http-trustedcomputinggroup-org-wp-content-uploads-tcg-ek-credential-profile
1189 *
1190 * These templates are only needed to create a new persistent SRK (or a new transient key that is
1191 * SRK-compatible). Preferably, the TPM should contain a shared SRK located at the reserved shared SRK handle
adcd3266 1192 * (see TPM2_SRK_HANDLE in tpm2-util.h, and tpm2_get_srk() below).
f4f5b3a9 1193 *
78893337
DS
1194 * Returns 0 if the specified algorithm is ECC or RSA, otherwise -EOPNOTSUPP. */
1195int tpm2_get_srk_template(TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template) {
f4f5b3a9
DS
1196 /* The attributes are the same between ECC and RSA templates. This has the changes specified in the
1197 * Provisioning Guidance document, specifically:
1198 * TPMA_OBJECT_USERWITHAUTH is added.
1199 * TPMA_OBJECT_ADMINWITHPOLICY is removed.
1200 * TPMA_OBJECT_NODA is added. */
1201 TPMA_OBJECT srk_attributes =
1202 TPMA_OBJECT_DECRYPT |
1203 TPMA_OBJECT_FIXEDPARENT |
1204 TPMA_OBJECT_FIXEDTPM |
1205 TPMA_OBJECT_NODA |
1206 TPMA_OBJECT_RESTRICTED |
1207 TPMA_OBJECT_SENSITIVEDATAORIGIN |
1208 TPMA_OBJECT_USERWITHAUTH;
1209
1210 /* The symmetric configuration is the same between ECC and RSA templates. */
1211 TPMT_SYM_DEF_OBJECT srk_symmetric = {
1212 .algorithm = TPM2_ALG_AES,
1213 .keyBits.aes = 128,
1214 .mode.aes = TPM2_ALG_CFB,
1215 };
1216
1217 /* Both templates have an empty authPolicy as specified by the Provisioning Guidance document. */
1218
1219 /* From the EK Credential Profile template "L-2". */
1220 TPMT_PUBLIC srk_ecc = {
1221 .type = TPM2_ALG_ECC,
1222 .nameAlg = TPM2_ALG_SHA256,
1223 .objectAttributes = srk_attributes,
1224 .parameters.eccDetail = {
1225 .symmetric = srk_symmetric,
1226 .scheme.scheme = TPM2_ALG_NULL,
1227 .curveID = TPM2_ECC_NIST_P256,
1228 .kdf.scheme = TPM2_ALG_NULL,
acbb504e 1229 },
f4f5b3a9
DS
1230 };
1231
1232 /* From the EK Credential Profile template "L-1". */
1233 TPMT_PUBLIC srk_rsa = {
1234 .type = TPM2_ALG_RSA,
1235 .nameAlg = TPM2_ALG_SHA256,
1236 .objectAttributes = srk_attributes,
1237 .parameters.rsaDetail = {
1238 .symmetric = srk_symmetric,
1239 .scheme.scheme = TPM2_ALG_NULL,
1240 .keyBits = 2048,
2b92a672
LP
1241 },
1242 };
1243
f4f5b3a9
DS
1244 assert(ret_template);
1245
78893337
DS
1246 switch (alg) {
1247 case TPM2_ALG_ECC:
f4f5b3a9
DS
1248 *ret_template = srk_ecc;
1249 return 0;
78893337 1250 case TPM2_ALG_RSA:
f4f5b3a9
DS
1251 *ret_template = srk_rsa;
1252 return 0;
1253 }
1254
78893337 1255 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "No SRK for algorithm 0x%" PRIx16, alg);
acbb504e
WR
1256}
1257
cea525a9 1258/* Get the best supported SRK template. ECC is preferred, then RSA. */
2eea1b8f 1259int tpm2_get_best_srk_template(Tpm2Context *c, TPMT_PUBLIC *ret_template) {
78893337
DS
1260 TPMT_PUBLIC template;
1261 int r;
1262
1263 assert(c);
1264 assert(ret_template);
1265
1266 r = tpm2_get_srk_template(TPM2_ALG_ECC, &template);
1267 if (r < 0)
1268 return r;
1269
1270 if (!tpm2_supports_alg(c, TPM2_ALG_ECC))
1271 log_debug("TPM does not support ECC.");
1272 else if (!tpm2_supports_ecc_curve(c, template.parameters.eccDetail.curveID))
1273 log_debug("TPM does not support ECC-NIST-P256 curve.");
1274 else if (!tpm2_supports_tpmt_public(c, &template))
1275 log_debug("TPM does not support SRK ECC template L-2.");
1276 else {
1277 *ret_template = template;
cea525a9 1278 return 0;
78893337
DS
1279 }
1280
1281 r = tpm2_get_srk_template(TPM2_ALG_RSA, &template);
1282 if (r < 0)
1283 return r;
1284
1285 if (!tpm2_supports_alg(c, TPM2_ALG_RSA))
1286 log_debug("TPM does not support RSA.");
1287 else if (!tpm2_supports_tpmt_public(c, &template))
1288 log_debug("TPM does not support SRK RSA template L-1.");
1289 else {
1290 *ret_template = template;
1291 return 0;
1292 }
cea525a9
DS
1293
1294 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1295 "TPM does not support either SRK template L-1 (RSA) or L-2 (ECC).");
1296}
1297
cea525a9
DS
1298/* Get the SRK. Returns 1 if SRK is found, 0 if there is no SRK, or < 0 on error. Also see
1299 * tpm2_get_or_create_srk() below. */
2eea1b8f 1300int tpm2_get_srk(
acbb504e 1301 Tpm2Context *c,
c8a85240 1302 const Tpm2Handle *session,
98d6a809
DS
1303 TPM2B_PUBLIC **ret_public,
1304 TPM2B_NAME **ret_name,
1305 TPM2B_NAME **ret_qname,
c8a85240 1306 Tpm2Handle **ret_handle) {
acbb504e 1307
13cf98f3 1308 return tpm2_index_to_handle(c, TPM2_SRK_HANDLE, session, ret_public, ret_name, ret_qname, ret_handle);
acbb504e
WR
1309}
1310
3ed34256
DS
1311/* Get the SRK, creating one if needed. Returns 1 if a new SRK was created and persisted, 0 if an SRK already
1312 * exists, or < 0 on error. */
2e64cb71 1313int tpm2_get_or_create_srk(
cea525a9
DS
1314 Tpm2Context *c,
1315 const Tpm2Handle *session,
1316 TPM2B_PUBLIC **ret_public,
1317 TPM2B_NAME **ret_name,
1318 TPM2B_NAME **ret_qname,
1319 Tpm2Handle **ret_handle) {
1320
1321 int r;
1322
1323 r = tpm2_get_srk(c, session, ret_public, ret_name, ret_qname, ret_handle);
1324 if (r < 0)
1325 return r;
1326 if (r == 1)
2e64cb71 1327 return 0; /* 0 → SRK already set up */
cea525a9
DS
1328
1329 /* No SRK, create and persist one */
4af7f27a
LP
1330 TPM2B_PUBLIC template = {
1331 .size = sizeof(TPMT_PUBLIC),
1332 };
aff853f8 1333 r = tpm2_get_best_srk_template(c, &template.publicArea);
cea525a9 1334 if (r < 0)
f9a0ee75 1335 return log_debug_errno(r, "Could not get best SRK template: %m");
cea525a9
DS
1336
1337 _cleanup_(tpm2_handle_freep) Tpm2Handle *transient_handle = NULL;
aff853f8 1338 r = tpm2_create_primary(
cea525a9 1339 c,
cea525a9
DS
1340 session,
1341 &template,
1342 /* sensitive= */ NULL,
1343 /* ret_public= */ NULL,
cea525a9
DS
1344 &transient_handle);
1345 if (r < 0)
1346 return r;
1347
1348 /* Try to persist the transient SRK we created. No locking needed; if multiple threads are trying to
1349 * persist SRKs concurrently, only one will succeed (r == 1) while the rest will fail (r == 0). In
1350 * either case, all threads will get the persistent SRK below. */
1351 r = tpm2_persist_handle(c, transient_handle, session, TPM2_SRK_HANDLE, /* ret_persistent_handle= */ NULL);
1352 if (r < 0)
1353 return r;
1354
1355 /* The SRK should exist now. */
1356 r = tpm2_get_srk(c, session, ret_public, ret_name, ret_qname, ret_handle);
1357 if (r < 0)
1358 return r;
1359 if (r == 0)
1360 /* This should never happen. */
f9a0ee75 1361 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "SRK we just persisted couldn't be found.");
cea525a9 1362
2e64cb71 1363 return 1; /* > 0 → SRK newly set up */
cea525a9
DS
1364}
1365
c69bd0ab
DS
1366/* Utility functions for TPMS_PCR_SELECTION. */
1367
1368/* Convert a TPMS_PCR_SELECTION object to a mask. */
dbaae766 1369uint32_t tpm2_tpms_pcr_selection_to_mask(const TPMS_PCR_SELECTION *s) {
c69bd0ab
DS
1370 assert(s);
1371 assert(s->sizeofSelect <= sizeof(s->pcrSelect));
321a9d9e 1372
c69bd0ab
DS
1373 uint32_t mask = 0;
1374 for (unsigned i = 0; i < s->sizeofSelect; i++)
1375 SET_FLAG(mask, (uint32_t)s->pcrSelect[i] << (i * 8), true);
dbaae766 1376 return mask;
c69bd0ab 1377}
321a9d9e 1378
c69bd0ab
DS
1379/* Convert a mask and hash alg to a TPMS_PCR_SELECTION object. */
1380void tpm2_tpms_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash_alg, TPMS_PCR_SELECTION *ret) {
1381 assert(ret);
1382
1383 /* This is currently hardcoded at 24 PCRs, above. */
1384 if (!TPM2_PCR_MASK_VALID(mask))
f9a0ee75
DS
1385 log_debug("PCR mask selections (%x) out of range, ignoring.",
1386 mask & ~((uint32_t)TPM2_PCRS_MASK));
c69bd0ab
DS
1387
1388 *ret = (TPMS_PCR_SELECTION){
1389 .hash = hash_alg,
1390 .sizeofSelect = TPM2_PCRS_MAX / 8,
1391 .pcrSelect[0] = mask & 0xff,
1392 .pcrSelect[1] = (mask >> 8) & 0xff,
1393 .pcrSelect[2] = (mask >> 16) & 0xff,
1394 };
1395}
1396
13b55174
DS
1397/* Test if all bits in the mask are set in the TPMS_PCR_SELECTION. */
1398bool tpm2_tpms_pcr_selection_has_mask(const TPMS_PCR_SELECTION *s, uint32_t mask) {
1399 assert(s);
1400
1401 return FLAGS_SET(tpm2_tpms_pcr_selection_to_mask(s), mask);
1402}
1403
1404static void tpm2_tpms_pcr_selection_update_mask(TPMS_PCR_SELECTION *s, uint32_t mask, bool b) {
1405 assert(s);
1406
1407 tpm2_tpms_pcr_selection_from_mask(UPDATE_FLAG(tpm2_tpms_pcr_selection_to_mask(s), mask, b), s->hash, s);
1408}
1409
1410/* Add all PCR selections in the mask. */
1411void tpm2_tpms_pcr_selection_add_mask(TPMS_PCR_SELECTION *s, uint32_t mask) {
1412 tpm2_tpms_pcr_selection_update_mask(s, mask, 1);
1413}
1414
1415/* Remove all PCR selections in the mask. */
1416void tpm2_tpms_pcr_selection_sub_mask(TPMS_PCR_SELECTION *s, uint32_t mask) {
1417 tpm2_tpms_pcr_selection_update_mask(s, mask, 0);
1418}
1419
c69bd0ab
DS
1420/* Add all PCR selections in 'b' to 'a'. Both must have the same hash alg. */
1421void tpm2_tpms_pcr_selection_add(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b) {
1422 assert(a);
1423 assert(b);
1424 assert(a->hash == b->hash);
1425
13b55174 1426 tpm2_tpms_pcr_selection_add_mask(a, tpm2_tpms_pcr_selection_to_mask(b));
c69bd0ab
DS
1427}
1428
1429/* Remove all PCR selections in 'b' from 'a'. Both must have the same hash alg. */
1430void tpm2_tpms_pcr_selection_sub(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b) {
1431 assert(a);
1432 assert(b);
1433 assert(a->hash == b->hash);
1434
13b55174 1435 tpm2_tpms_pcr_selection_sub_mask(a, tpm2_tpms_pcr_selection_to_mask(b));
c69bd0ab
DS
1436}
1437
1438/* Move all PCR selections in 'b' to 'a'. Both must have the same hash alg. */
1439void tpm2_tpms_pcr_selection_move(TPMS_PCR_SELECTION *a, TPMS_PCR_SELECTION *b) {
1440 if (a == b)
1441 return;
1442
1443 tpm2_tpms_pcr_selection_add(a, b);
1444 tpm2_tpms_pcr_selection_from_mask(0, b->hash, b);
1445}
1446
193fd573
DS
1447#define FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \
1448 _FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml, UNIQ_T(l, UNIQ))
1449#define _FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml, l) \
1450 for (typeof(tpml) (l) = (tpml); (l); (l) = NULL) \
1451 FOREACH_ARRAY(tpms, (l)->pcrSelections, (l)->count)
1452
c69bd0ab 1453#define FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms) \
dbaae766 1454 FOREACH_PCR_IN_MASK(pcr, tpm2_tpms_pcr_selection_to_mask(tpms))
c69bd0ab 1455
c69bd0ab
DS
1456#define FOREACH_PCR_IN_TPML_PCR_SELECTION(pcr, tpms, tpml) \
1457 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \
1458 FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms)
1459
1460char *tpm2_tpms_pcr_selection_to_string(const TPMS_PCR_SELECTION *s) {
1461 assert(s);
1462
1463 const char *algstr = strna(tpm2_hash_alg_to_string(s->hash));
1464
dbaae766
DS
1465 _cleanup_free_ char *mask = tpm2_pcr_mask_to_string(tpm2_tpms_pcr_selection_to_mask(s));
1466 if (!mask)
c69bd0ab
DS
1467 return NULL;
1468
dbaae766 1469 return strjoin(algstr, "(", mask, ")");
c69bd0ab
DS
1470}
1471
1472size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s) {
1473 assert(s);
1474
dbaae766 1475 return popcount(tpm2_tpms_pcr_selection_to_mask(s));
c69bd0ab
DS
1476}
1477
1478/* Utility functions for TPML_PCR_SELECTION. */
1479
1480/* Remove the (0-based) index entry from 'l', shift all following entries, and update the count. */
1481static void tpm2_tpml_pcr_selection_remove_index(TPML_PCR_SELECTION *l, uint32_t index) {
1482 assert(l);
9afd4dde 1483 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1484 assert(index < l->count);
1485
1486 size_t s = l->count - (index + 1);
1487 memmove(&l->pcrSelections[index], &l->pcrSelections[index + 1], s * sizeof(l->pcrSelections[0]));
1488 l->count--;
1489}
1490
1491/* Get a TPMS_PCR_SELECTION from a TPML_PCR_SELECTION for the given hash alg. Returns NULL if there is no
1492 * entry for the hash alg. This guarantees the returned entry contains all the PCR selections for the given
1493 * hash alg, which may require modifying the TPML_PCR_SELECTION by removing duplicate entries. */
1494static TPMS_PCR_SELECTION *tpm2_tpml_pcr_selection_get_tpms_pcr_selection(
1495 TPML_PCR_SELECTION *l,
1496 TPMI_ALG_HASH hash_alg) {
1497
1498 assert(l);
9afd4dde 1499 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1500
1501 TPMS_PCR_SELECTION *selection = NULL;
1502 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l)
1503 if (s->hash == hash_alg) {
1504 selection = s;
1505 break;
1506 }
1507
1508 if (!selection)
1509 return NULL;
1510
1511 /* Iterate backwards through the entries, removing any other entries for the hash alg. */
1512 for (uint32_t i = l->count - 1; i > 0; i--) {
1513 TPMS_PCR_SELECTION *s = &l->pcrSelections[i];
1514
1515 if (selection == s)
1516 break;
1517
1518 if (s->hash == hash_alg) {
1519 tpm2_tpms_pcr_selection_move(selection, s);
1520 tpm2_tpml_pcr_selection_remove_index(l, i);
4dde902e 1521 }
c69bd0ab
DS
1522 }
1523
1524 return selection;
1525}
1526
193fd573
DS
1527/* Combine all duplicate (same hash alg) TPMS_PCR_SELECTION entries in 'l'. */
1528static void tpm2_tpml_pcr_selection_cleanup(TPML_PCR_SELECTION *l) {
1529 /* Can't use FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION() because we might modify l->count */
1530 for (uint32_t i = 0; i < l->count; i++)
1531 /* This removes all duplicate TPMS_PCR_SELECTION entries for this hash. */
1532 (void) tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, l->pcrSelections[i].hash);
1533}
1534
dbaae766
DS
1535/* Convert a TPML_PCR_SELECTION object to a mask. Returns empty mask (i.e. 0) if 'hash_alg' is not in the object. */
1536uint32_t tpm2_tpml_pcr_selection_to_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash_alg) {
c69bd0ab 1537 assert(l);
c69bd0ab
DS
1538
1539 /* Make a copy, as tpm2_tpml_pcr_selection_get_tpms_pcr_selection() will modify the object if there
1540 * are multiple entries with the requested hash alg. */
1541 TPML_PCR_SELECTION lcopy = *l;
1542
1543 TPMS_PCR_SELECTION *s;
1544 s = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(&lcopy, hash_alg);
1545 if (!s)
dbaae766 1546 return 0;
c69bd0ab 1547
dbaae766 1548 return tpm2_tpms_pcr_selection_to_mask(s);
c69bd0ab
DS
1549}
1550
1551/* Convert a mask and hash alg to a TPML_PCR_SELECTION object. */
1552void tpm2_tpml_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash_alg, TPML_PCR_SELECTION *ret) {
1553 assert(ret);
1554
1555 TPMS_PCR_SELECTION s;
1556 tpm2_tpms_pcr_selection_from_mask(mask, hash_alg, &s);
1557
1558 *ret = (TPML_PCR_SELECTION){
1559 .count = 1,
1560 .pcrSelections[0] = s,
321a9d9e
LP
1561 };
1562}
1563
c69bd0ab
DS
1564/* Add the PCR selections in 's' to the corresponding hash alg TPMS_PCR_SELECTION entry in 'l'. Adds a new
1565 * TPMS_PCR_SELECTION entry for the hash alg if needed. This may modify the TPML_PCR_SELECTION by combining
1566 * entries with the same hash alg. */
1567void tpm2_tpml_pcr_selection_add_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s) {
1568 assert(l);
1569 assert(s);
1570
1571 if (tpm2_tpms_pcr_selection_is_empty(s))
1572 return;
1573
1574 TPMS_PCR_SELECTION *selection = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash);
1575 if (selection) {
1576 tpm2_tpms_pcr_selection_add(selection, s);
1577 return;
1578 }
1579
1580 /* It's already broken if the count is higher than the array has size for. */
9afd4dde 1581 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1582
1583 /* If full, the cleanup should result in at least one available entry. */
9afd4dde 1584 if (l->count == ELEMENTSOF(l->pcrSelections))
c69bd0ab
DS
1585 tpm2_tpml_pcr_selection_cleanup(l);
1586
9afd4dde 1587 assert(l->count < ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1588 l->pcrSelections[l->count++] = *s;
1589}
1590
1591/* Remove the PCR selections in 's' from the corresponding hash alg TPMS_PCR_SELECTION entry in 'l'. This
1592 * will combine all entries for 's->hash' in 'l'. */
1593void tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s) {
1594 assert(l);
1595 assert(s);
1596
1597 if (tpm2_tpms_pcr_selection_is_empty(s))
1598 return;
1599
1600 TPMS_PCR_SELECTION *selection = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash);
1601 if (selection)
1602 tpm2_tpms_pcr_selection_sub(selection, s);
1603}
1604
13b55174
DS
1605/* Test if all bits in the mask for the hash are set in the TPML_PCR_SELECTION. */
1606bool tpm2_tpml_pcr_selection_has_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask) {
1607 assert(l);
1608
1609 return FLAGS_SET(tpm2_tpml_pcr_selection_to_mask(l, hash), mask);
1610}
1611
1612/* Add the PCR selections in the mask, with the provided hash. */
1613void tpm2_tpml_pcr_selection_add_mask(TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask) {
1614 TPMS_PCR_SELECTION tpms;
1615
1616 assert(l);
1617
1618 tpm2_tpms_pcr_selection_from_mask(mask, hash, &tpms);
1619 tpm2_tpml_pcr_selection_add_tpms_pcr_selection(l, &tpms);
1620}
1621
1622/* Remove the PCR selections in the mask, with the provided hash. */
1623void tpm2_tpml_pcr_selection_sub_mask(TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask) {
1624 TPMS_PCR_SELECTION tpms;
1625
1626 assert(l);
1627
1628 tpm2_tpms_pcr_selection_from_mask(mask, hash, &tpms);
1629 tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(l, &tpms);
1630}
1631
c69bd0ab
DS
1632/* Add all PCR selections in 'b' to 'a'. */
1633void tpm2_tpml_pcr_selection_add(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b) {
1634 assert(a);
1635 assert(b);
1636
193fd573 1637 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection_b, b)
c69bd0ab
DS
1638 tpm2_tpml_pcr_selection_add_tpms_pcr_selection(a, selection_b);
1639}
1640
1641/* Remove all PCR selections in 'b' from 'a'. */
1642void tpm2_tpml_pcr_selection_sub(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b) {
1643 assert(a);
1644 assert(b);
1645
193fd573 1646 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection_b, b)
c69bd0ab
DS
1647 tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(a, selection_b);
1648}
1649
1650char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l) {
1651 assert(l);
1652
1653 _cleanup_free_ char *banks = NULL;
193fd573 1654 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) {
c69bd0ab
DS
1655 if (tpm2_tpms_pcr_selection_is_empty(s))
1656 continue;
1657
1658 _cleanup_free_ char *str = tpm2_tpms_pcr_selection_to_string(s);
1659 if (!str || !strextend_with_separator(&banks, ",", str))
1660 return NULL;
1661 }
1662
1663 return strjoin("[", strempty(banks), "]");
1664}
1665
1666size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l) {
1667 assert(l);
9afd4dde 1668 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1669
1670 size_t weight = 0;
1671 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) {
1672 size_t w = tpm2_tpms_pcr_selection_weight(s);
1673 assert(weight <= SIZE_MAX - w);
1674 weight += w;
1675 }
1676
1677 return weight;
1678}
1679
cc1a78d5 1680bool tpm2_pcr_value_valid(const Tpm2PCRValue *pcr_value) {
323eb480
DS
1681 int r;
1682
064ac95d
DS
1683 if (!pcr_value)
1684 return false;
323eb480
DS
1685
1686 if (!TPM2_PCR_INDEX_VALID(pcr_value->index)) {
1687 log_debug("PCR index %u invalid.", pcr_value->index);
1688 return false;
1689 }
1690
1691 /* If it contains a value, the value size must match the hash size. */
1692 if (pcr_value->value.size > 0) {
1693 r = tpm2_hash_alg_to_size(pcr_value->hash);
1694 if (r < 0)
1695 return false;
1696
3cd4145f 1697 if (pcr_value->value.size != (size_t) r) {
323eb480
DS
1698 log_debug("PCR hash 0x%" PRIx16 " expected size %d does not match actual size %" PRIu16 ".",
1699 pcr_value->hash, r, pcr_value->value.size);
1700 return false;
1701 }
1702 }
1703
1704 return true;
1705}
1706
1707/* Verify all entries are valid, and consistent with each other. The requirements for consistency are:
1708 *
1709 * 1) all entries must be sorted in ascending order (e.g. using tpm2_sort_pcr_values())
1710 * 2) all entries must be unique, i.e. there cannot be 2 entries with the same hash and index
064ac95d
DS
1711 *
1712 * Returns true if all entries are valid (or if no entries are provided), false otherwise.
323eb480 1713 */
cc1a78d5 1714bool tpm2_pcr_values_valid(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
064ac95d
DS
1715 if (!pcr_values && n_pcr_values > 0)
1716 return false;
323eb480 1717
193fd573
DS
1718 const Tpm2PCRValue *previous = NULL;
1719 FOREACH_ARRAY(current, pcr_values, n_pcr_values) {
1720 if (!tpm2_pcr_value_valid(current))
323eb480
DS
1721 return false;
1722
193fd573
DS
1723 if (!previous) {
1724 previous = current;
323eb480 1725 continue;
193fd573 1726 }
323eb480
DS
1727
1728 /* Hashes must be sorted in ascending order */
193fd573 1729 if (current->hash < previous->hash) {
323eb480 1730 log_debug("PCR values not in ascending order, hash %" PRIu16 " is after %" PRIu16 ".",
193fd573 1731 current->hash, previous->hash);
323eb480
DS
1732 return false;
1733 }
1734
193fd573 1735 if (current->hash == previous->hash) {
323eb480 1736 /* Indexes (for the same hash) must be sorted in ascending order */
193fd573 1737 if (current->index < previous->index) {
323eb480 1738 log_debug("PCR values not in ascending order, hash %" PRIu16 " index %u is after %u.",
193fd573 1739 current->hash, current->index, previous->index);
323eb480
DS
1740 return false;
1741 }
1742
1743 /* Indexes (for the same hash) must not be duplicates */
193fd573 1744 if (current->index == previous->index) {
323eb480 1745 log_debug("PCR values contain duplicates for hash %" PRIu16 " index %u.",
193fd573 1746 current->hash, previous->index);
323eb480
DS
1747 return false;
1748 }
1749 }
1750 }
1751
1752 return true;
1753}
1754
26d8d71f
DS
1755/* Returns true if any of the provided PCR values has an actual hash value included, false otherwise. */
1756bool tpm2_pcr_values_has_any_values(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1757 assert(pcr_values || n_pcr_values == 0);
1758
1759 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
1760 if (v->value.size > 0)
1761 return true;
1762
1763 return false;
1764}
1765
1766/* Returns true if all of the provided PCR values has an actual hash value included, false otherwise. */
1767bool tpm2_pcr_values_has_all_values(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1768 assert(pcr_values || n_pcr_values == 0);
1769
1770 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
1771 if (v->value.size == 0)
1772 return false;
1773
1774 return true;
1775}
1776
323eb480
DS
1777static int cmp_pcr_values(const Tpm2PCRValue *a, const Tpm2PCRValue *b) {
1778 assert(a);
1779 assert(b);
1780
1781 return CMP(a->hash, b->hash) ?: CMP(a->index, b->index);
1782}
1783
1784/* Sort the array of Tpm2PCRValue entries in-place. This sorts first in ascending order of hash algorithm
1785 * (sorting simply by the TPM2 hash algorithm number), and then sorting by pcr index. */
1786void tpm2_sort_pcr_values(Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1787 typesafe_qsort(pcr_values, n_pcr_values, cmp_pcr_values);
1788}
1789
1790int tpm2_pcr_values_from_mask(uint32_t mask, TPMI_ALG_HASH hash, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values) {
1791 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
1792 size_t n_pcr_values = 0;
1793
1794 assert(ret_pcr_values);
1795 assert(ret_n_pcr_values);
1796
1797 FOREACH_PCR_IN_MASK(index, mask)
1798 if (!GREEDY_REALLOC_APPEND(
1799 pcr_values,
1800 n_pcr_values,
1801 &TPM2_PCR_VALUE_MAKE(index, hash, {}),
1802 1))
1803 return log_oom_debug();
1804
1805 *ret_pcr_values = TAKE_PTR(pcr_values);
1806 *ret_n_pcr_values = n_pcr_values;
1807
1808 return 0;
1809}
1810
1811int tpm2_pcr_values_to_mask(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPMI_ALG_HASH hash, uint32_t *ret_mask) {
1812 uint32_t mask = 0;
1813
1814 assert(pcr_values || n_pcr_values == 0);
1815 assert(ret_mask);
1816
cc1a78d5 1817 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
323eb480
DS
1818 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PCR values.");
1819
193fd573
DS
1820 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
1821 if (v->hash == hash)
1822 SET_BIT(mask, v->index);
323eb480
DS
1823
1824 *ret_mask = mask;
1825
1826 return 0;
1827}
1828
1829int tpm2_tpml_pcr_selection_from_pcr_values(
1830 const Tpm2PCRValue *pcr_values,
1831 size_t n_pcr_values,
1832 TPML_PCR_SELECTION *ret_selection,
1833 TPM2B_DIGEST **ret_values,
1834 size_t *ret_n_values) {
1835
1836 TPML_PCR_SELECTION selection = {};
1837 _cleanup_free_ TPM2B_DIGEST *values = NULL;
1838 size_t n_values = 0;
1839
1840 assert(pcr_values || n_pcr_values == 0);
1841
cc1a78d5 1842 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
323eb480
DS
1843 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "PCR values are not valid.");
1844
193fd573
DS
1845 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
1846 tpm2_tpml_pcr_selection_add_mask(&selection, v->hash, INDEX_TO_MASK(uint32_t, v->index));
323eb480 1847
193fd573 1848 if (!GREEDY_REALLOC_APPEND(values, n_values, &v->value, 1))
323eb480
DS
1849 return log_oom_debug();
1850 }
1851
1852 if (ret_selection)
1853 *ret_selection = selection;
1854 if (ret_values)
1855 *ret_values = TAKE_PTR(values);
1856 if (ret_n_values)
1857 *ret_n_values = n_values;
1858
1859 return 0;
1860}
1861
1862/* Count the number of different hash algorithms for all the entries. */
1863int tpm2_pcr_values_hash_count(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, size_t *ret_count) {
1864 TPML_PCR_SELECTION selection;
1865 int r;
1866
1867 assert(pcr_values);
1868 assert(ret_count);
1869
1870 r = tpm2_tpml_pcr_selection_from_pcr_values(
1871 pcr_values,
1872 n_pcr_values,
1873 &selection,
1874 /* ret_values= */ NULL,
1875 /* ret_n_values= */ NULL);
1876 if (r < 0)
1877 return r;
1878
1879 *ret_count = selection.count;
1880
1881 return 0;
1882}
1883
1884/* Parse a string argument into a Tpm2PCRValue object.
1885 *
1886 * The format is <index>[:hash[=value]] where index is the index number (or name) of the PCR, e.g. 0 (or
1887 * platform-code), hash is the name of the hash algorithm (e.g. sha256) and value is the hex hash digest
1888 * value, optionally with a leading 0x. This does not check for validity of the fields. */
1889int tpm2_pcr_value_from_string(const char *arg, Tpm2PCRValue *ret_pcr_value) {
1890 Tpm2PCRValue pcr_value = {};
1891 const char *p = arg;
1892 int r;
1893
1894 assert(arg);
1895 assert(ret_pcr_value);
1896
1897 _cleanup_free_ char *index = NULL;
1898 r = extract_first_word(&p, &index, ":", /* flags= */ 0);
1899 if (r < 1)
f9a0ee75 1900 return log_debug_errno(r, "Could not parse pcr value '%s': %m", p);
323eb480 1901
2099cd62 1902 r = tpm2_pcr_index_from_string(index);
323eb480 1903 if (r < 0)
f9a0ee75 1904 return log_debug_errno(r, "Invalid pcr index '%s': %m", index);
323eb480
DS
1905 pcr_value.index = (unsigned) r;
1906
1907 if (!isempty(p)) {
1908 _cleanup_free_ char *hash = NULL;
1909 r = extract_first_word(&p, &hash, "=", /* flags= */ 0);
1910 if (r < 1)
f9a0ee75 1911 return log_debug_errno(r, "Could not parse pcr hash algorithm '%s': %m", p);
323eb480
DS
1912
1913 r = tpm2_hash_alg_from_string(hash);
1914 if (r < 0)
f9a0ee75 1915 return log_debug_errno(r, "Invalid pcr hash algorithm '%s': %m", hash);
323eb480 1916 pcr_value.hash = (TPMI_ALG_HASH) r;
323eb480 1917
2b2ee3f2
DS
1918 if (!isempty(p)) {
1919 /* Remove leading 0x if present */
1920 p = startswith_no_case(p, "0x") ?: p;
323eb480 1921
2b2ee3f2
DS
1922 _cleanup_free_ void *buf = NULL;
1923 size_t buf_size = 0;
bdd2036e 1924 r = unhexmem(p, &buf, &buf_size);
2b2ee3f2 1925 if (r < 0)
f9a0ee75 1926 return log_debug_errno(r, "Invalid pcr hash value '%s': %m", p);
323eb480 1927
2b2ee3f2
DS
1928 r = TPM2B_DIGEST_CHECK_SIZE(buf_size);
1929 if (r < 0)
f9a0ee75 1930 return log_debug_errno(r, "PCR hash value size %zu too large.", buf_size);
53b91e19 1931
2b2ee3f2
DS
1932 pcr_value.value = TPM2B_DIGEST_MAKE(buf, buf_size);
1933 }
323eb480
DS
1934 }
1935
1936 *ret_pcr_value = pcr_value;
1937
1938 return 0;
1939}
1940
1941/* Return a string for the PCR value. The format is described in tpm2_pcr_value_from_string(). Note that if
1942 * the hash algorithm is not recognized, neither hash name nor hash digest value is included in the
1943 * string. This does not check for validity. */
1944char *tpm2_pcr_value_to_string(const Tpm2PCRValue *pcr_value) {
1945 _cleanup_free_ char *index = NULL, *value = NULL;
323eb480 1946
495f2bf5 1947 if (asprintf(&index, "%u", pcr_value->index) < 0)
323eb480
DS
1948 return NULL;
1949
8e757259 1950 const char *hash = pcr_value->hash > 0 ? tpm2_hash_alg_to_string(pcr_value->hash) : NULL;
323eb480
DS
1951
1952 if (hash && pcr_value->value.size > 0) {
1953 value = hexmem(pcr_value->value.buffer, pcr_value->value.size);
1954 if (!value)
1955 return NULL;
1956 }
1957
85b6f299 1958 return strjoin(index, hash ? ":" : "", strempty(hash), value ? "=" : "", strempty(value));
323eb480
DS
1959}
1960
1961/* Parse a string argument into an array of Tpm2PCRValue objects.
1962 *
1963 * The format is zero or more entries separated by ',' or '+'. The format of each entry is described in
1964 * tpm2_pcr_value_from_string(). This does not check for validity of the entries. */
1965int tpm2_pcr_values_from_string(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values) {
1966 const char *p = arg;
1967 int r;
1968
1969 assert(arg);
1970 assert(ret_pcr_values);
1971 assert(ret_n_pcr_values);
1972
1973 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
1974 size_t n_pcr_values = 0;
1975
1976 for (;;) {
1977 _cleanup_free_ char *pcr_arg = NULL;
1978 r = extract_first_word(&p, &pcr_arg, ",+", /* flags= */ 0);
1979 if (r < 0)
f9a0ee75 1980 return log_debug_errno(r, "Could not parse pcr values '%s': %m", p);
323eb480
DS
1981 if (r == 0)
1982 break;
1983
1984 Tpm2PCRValue pcr_value;
1985 r = tpm2_pcr_value_from_string(pcr_arg, &pcr_value);
1986 if (r < 0)
1987 return r;
1988
1989 if (!GREEDY_REALLOC_APPEND(pcr_values, n_pcr_values, &pcr_value, 1))
f9a0ee75 1990 return log_oom_debug();
323eb480
DS
1991 }
1992
1993 *ret_pcr_values = TAKE_PTR(pcr_values);
1994 *ret_n_pcr_values = n_pcr_values;
1995
1996 return 0;
1997}
1998
1999/* Return a string representing the array of PCR values. The format is as described in
2000 * tpm2_pcr_values_from_string(). This does not check for validity. */
2001char *tpm2_pcr_values_to_string(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
2002 _cleanup_free_ char *s = NULL;
2003
193fd573
DS
2004 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
2005 _cleanup_free_ char *pcrstr = tpm2_pcr_value_to_string(v);
323eb480
DS
2006 if (!pcrstr || !strextend_with_separator(&s, "+", pcrstr))
2007 return NULL;
2008 }
2009
2010 return s ? TAKE_PTR(s) : strdup("");
2011}
2012
75de375a 2013void tpm2_log_debug_tpml_pcr_selection(const TPML_PCR_SELECTION *l, const char *msg) {
c57d8bc8
DS
2014 if (!DEBUG_LOGGING || !l)
2015 return;
2016
2017 _cleanup_free_ char *s = tpm2_tpml_pcr_selection_to_string(l);
2018 log_debug("%s: %s", msg ?: "PCR selection", strna(s));
2019}
2020
75de375a 2021void tpm2_log_debug_pcr_value(const Tpm2PCRValue *pcr_value, const char *msg) {
323eb480
DS
2022 if (!DEBUG_LOGGING || !pcr_value)
2023 return;
2024
2025 _cleanup_free_ char *s = tpm2_pcr_value_to_string(pcr_value);
2026 log_debug("%s: %s", msg ?: "PCR value", strna(s));
2027}
2028
75de375a 2029void tpm2_log_debug_buffer(const void *buffer, size_t size, const char *msg) {
23b972d5
DS
2030 if (!DEBUG_LOGGING || !buffer || size == 0)
2031 return;
2032
2033 _cleanup_free_ char *h = hexmem(buffer, size);
2034 log_debug("%s: %s", msg ?: "Buffer", strna(h));
2035}
2036
75de375a 2037void tpm2_log_debug_digest(const TPM2B_DIGEST *digest, const char *msg) {
23b972d5
DS
2038 if (digest)
2039 tpm2_log_debug_buffer(digest->buffer, digest->size, msg ?: "Digest");
2040}
2041
75de375a 2042void tpm2_log_debug_name(const TPM2B_NAME *name, const char *msg) {
dbae4b95
DS
2043 if (name)
2044 tpm2_log_debug_buffer(name->name, name->size, msg ?: "Name");
2045}
2046
23b972d5
DS
2047static int tpm2_get_policy_digest(
2048 Tpm2Context *c,
2049 const Tpm2Handle *session,
2050 TPM2B_DIGEST **ret_policy_digest) {
2051
2052 TSS2_RC rc;
2053
2054 if (!DEBUG_LOGGING && !ret_policy_digest)
2055 return 0;
2056
2057 assert(c);
2058 assert(session);
2059
2060 log_debug("Acquiring policy digest.");
2061
2062 _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
2063 rc = sym_Esys_PolicyGetDigest(
2064 c->esys_context,
2065 session->esys_handle,
2066 ESYS_TR_NONE,
2067 ESYS_TR_NONE,
2068 ESYS_TR_NONE,
2069 &policy_digest);
2070 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2071 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
23b972d5
DS
2072 "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
2073
2074 tpm2_log_debug_digest(policy_digest, "Session policy digest");
2075
2076 if (ret_policy_digest)
2077 *ret_policy_digest = TAKE_PTR(policy_digest);
2078
2079 return 0;
2080}
2081
aff853f8 2082int tpm2_create_primary(
e3f1f210 2083 Tpm2Context *c,
aff853f8
DS
2084 const Tpm2Handle *session,
2085 const TPM2B_PUBLIC *template,
2086 const TPM2B_SENSITIVE_CREATE *sensitive,
2087 TPM2B_PUBLIC **ret_public,
2088 Tpm2Handle **ret_handle) {
2089
2090 usec_t ts;
2091 TSS2_RC rc;
2092 int r;
2093
2094 assert(c);
2095 assert(template);
2096
2097 log_debug("Creating primary key on TPM.");
2098
2099 ts = now(CLOCK_MONOTONIC);
2100
2101 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2102 r = tpm2_handle_new(c, &handle);
2103 if (r < 0)
2104 return r;
2105
2106 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2107 rc = sym_Esys_CreatePrimary(
2108 c->esys_context,
2109 ESYS_TR_RH_OWNER,
2110 session ? session->esys_handle : ESYS_TR_PASSWORD,
2111 ESYS_TR_NONE,
2112 ESYS_TR_NONE,
f51aec74 2113 sensitive ?: &(TPM2B_SENSITIVE_CREATE) {},
aff853f8
DS
2114 template,
2115 /* outsideInfo= */ NULL,
2116 &(TPML_PCR_SELECTION) {},
2117 &handle->esys_handle,
2118 &public,
2119 /* creationData= */ NULL,
2120 /* creationHash= */ NULL,
2121 /* creationTicket= */ NULL);
2122 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2123 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
aff853f8
DS
2124 "Failed to generate primary key in TPM: %s",
2125 sym_Tss2_RC_Decode(rc));
2126
2127 log_debug("Successfully created primary key on TPM in %s.",
2128 FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
2129
2130 if (ret_public)
2131 *ret_public = TAKE_PTR(public);
2132 if (ret_handle)
2133 *ret_handle = TAKE_PTR(handle);
2134
2135 return 0;
2136}
2137
2138/* Create a TPM object. Do not use this to create primary keys, because some HW TPMs refuse to allow that;
2139 * instead use tpm2_create_primary(). */
2140int tpm2_create(Tpm2Context *c,
e3f1f210
DS
2141 const Tpm2Handle *parent,
2142 const Tpm2Handle *session,
2143 const TPMT_PUBLIC *template,
2144 const TPMS_SENSITIVE_CREATE *sensitive,
2145 TPM2B_PUBLIC **ret_public,
2146 TPM2B_PRIVATE **ret_private) {
2147
2148 usec_t ts;
2149 TSS2_RC rc;
2150
2151 assert(c);
aff853f8 2152 assert(parent);
e3f1f210
DS
2153 assert(template);
2154
2155 log_debug("Creating object on TPM.");
2156
2157 ts = now(CLOCK_MONOTONIC);
2158
2159 TPM2B_PUBLIC tpm2b_public = {
2160 .size = sizeof(*template) - sizeof(template->unique),
2161 .publicArea = *template,
2162 };
2163
2164 /* Zero the unique area. */
2165 zero(tpm2b_public.publicArea.unique);
2166
2167 TPM2B_SENSITIVE_CREATE tpm2b_sensitive;
2168 if (sensitive)
2169 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {
2170 .size = sizeof(*sensitive),
2171 .sensitive = *sensitive,
2172 };
2173 else
2174 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {};
2175
2176 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2177 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
2178 rc = sym_Esys_Create(
2179 c->esys_context,
aff853f8 2180 parent->esys_handle,
e3f1f210
DS
2181 session ? session->esys_handle : ESYS_TR_PASSWORD,
2182 ESYS_TR_NONE,
2183 ESYS_TR_NONE,
2184 &tpm2b_sensitive,
2185 &tpm2b_public,
2186 /* outsideInfo= */ NULL,
2187 &(TPML_PCR_SELECTION) {},
2188 &private,
2189 &public,
2190 /* creationData= */ NULL,
2191 /* creationHash= */ NULL,
2192 /* creationTicket= */ NULL);
2193 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2194 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
e3f1f210
DS
2195 "Failed to generate object in TPM: %s",
2196 sym_Tss2_RC_Decode(rc));
2197
2198 log_debug("Successfully created object on TPM in %s.",
2199 FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
2200
2201 if (ret_public)
2202 *ret_public = TAKE_PTR(public);
2203 if (ret_private)
2204 *ret_private = TAKE_PTR(private);
2205
2206 return 0;
2207}
2208
8f3f9c2b 2209int tpm2_load(
d1d0de73
DS
2210 Tpm2Context *c,
2211 const Tpm2Handle *parent,
2212 const Tpm2Handle *session,
2213 const TPM2B_PUBLIC *public,
2214 const TPM2B_PRIVATE *private,
2215 Tpm2Handle **ret_handle) {
2216
2217 TSS2_RC rc;
2218 int r;
2219
2220 assert(c);
2221 assert(public);
2222 assert(private);
2223 assert(ret_handle);
2224
2225 log_debug("Loading object into TPM.");
2226
2227 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2228 r = tpm2_handle_new(c, &handle);
2229 if (r < 0)
2230 return r;
2231
2232 rc = sym_Esys_Load(
2233 c->esys_context,
2234 parent ? parent->esys_handle : ESYS_TR_RH_OWNER,
2235 session ? session->esys_handle : ESYS_TR_PASSWORD,
2236 ESYS_TR_NONE,
2237 ESYS_TR_NONE,
2238 private,
2239 public,
2240 &handle->esys_handle);
2241 if (rc == TPM2_RC_LOCKOUT)
f9a0ee75 2242 return log_debug_errno(SYNTHETIC_ERRNO(ENOLCK),
d1d0de73
DS
2243 "TPM2 device is in dictionary attack lockout mode.");
2244 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2245 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
d1d0de73
DS
2246 "Failed to load key into TPM: %s", sym_Tss2_RC_Decode(rc));
2247
2248 *ret_handle = TAKE_PTR(handle);
2249
2250 return 0;
2251}
2252
efe153bd
DS
2253static int tpm2_load_external(
2254 Tpm2Context *c,
2255 const Tpm2Handle *session,
2256 const TPM2B_PUBLIC *public,
2257 const TPM2B_SENSITIVE *private,
2258 Tpm2Handle **ret_handle) {
2259
2260 TSS2_RC rc;
2261 int r;
2262
2263 assert(c);
2264 assert(ret_handle);
2265
2266 log_debug("Loading external key into TPM.");
2267
2268 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2269 r = tpm2_handle_new(c, &handle);
2270 if (r < 0)
2271 return r;
2272
2273 rc = sym_Esys_LoadExternal(
2274 c->esys_context,
2275 session ? session->esys_handle : ESYS_TR_NONE,
2276 ESYS_TR_NONE,
2277 ESYS_TR_NONE,
2278 private,
2279 public,
2280#if HAVE_TSS2_ESYS3
2281 /* tpm2-tss >= 3.0.0 requires a ESYS_TR_RH_* constant specifying the requested
2282 * hierarchy, older versions need TPM2_RH_* instead. */
371b5944 2283 private ? ESYS_TR_RH_NULL : ESYS_TR_RH_OWNER,
efe153bd 2284#else
371b5944 2285 private ? TPM2_RH_NULL : TPM2_RH_OWNER,
efe153bd
DS
2286#endif
2287 &handle->esys_handle);
2288 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2289 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
efe153bd
DS
2290 "Failed to load public key into TPM: %s", sym_Tss2_RC_Decode(rc));
2291
2292 *ret_handle = TAKE_PTR(handle);
2293
2294 return 0;
2295}
2296
cea525a9
DS
2297/* This calls TPM2_CreateLoaded() directly, without checking if the TPM supports it. Callers should instead
2298 * use tpm2_create_loaded(). */
2299static int _tpm2_create_loaded(
2300 Tpm2Context *c,
2301 const Tpm2Handle *parent,
2302 const Tpm2Handle *session,
2303 const TPMT_PUBLIC *template,
2304 const TPMS_SENSITIVE_CREATE *sensitive,
2305 TPM2B_PUBLIC **ret_public,
2306 TPM2B_PRIVATE **ret_private,
2307 Tpm2Handle **ret_handle) {
2308
2309 usec_t ts;
2310 TSS2_RC rc;
2311 int r;
2312
2313 assert(c);
aff853f8 2314 assert(parent);
cea525a9
DS
2315 assert(template);
2316
2317 log_debug("Creating loaded object on TPM.");
2318
2319 ts = now(CLOCK_MONOTONIC);
2320
2321 /* Copy the input template and zero the unique area. */
2322 TPMT_PUBLIC template_copy = *template;
2323 zero(template_copy.unique);
2324
2325 TPM2B_TEMPLATE tpm2b_template;
2326 size_t size = 0;
2327 rc = sym_Tss2_MU_TPMT_PUBLIC_Marshal(
2328 &template_copy,
2329 tpm2b_template.buffer,
2330 sizeof(tpm2b_template.buffer),
2331 &size);
2332 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2333 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
cea525a9
DS
2334 "Failed to marshal public key template: %s", sym_Tss2_RC_Decode(rc));
2335 assert(size <= UINT16_MAX);
2336 tpm2b_template.size = size;
2337
2338 TPM2B_SENSITIVE_CREATE tpm2b_sensitive;
2339 if (sensitive)
2340 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {
2341 .size = sizeof(*sensitive),
2342 .sensitive = *sensitive,
2343 };
2344 else
2345 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {};
2346
2347 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2348 r = tpm2_handle_new(c, &handle);
2349 if (r < 0)
2350 return r;
2351
2352 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2353 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
2354 rc = sym_Esys_CreateLoaded(
2355 c->esys_context,
aff853f8 2356 parent->esys_handle,
cea525a9
DS
2357 session ? session->esys_handle : ESYS_TR_PASSWORD,
2358 ESYS_TR_NONE,
2359 ESYS_TR_NONE,
2360 &tpm2b_sensitive,
2361 &tpm2b_template,
2362 &handle->esys_handle,
2363 &private,
2364 &public);
2365 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2366 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
cea525a9
DS
2367 "Failed to generate loaded object in TPM: %s",
2368 sym_Tss2_RC_Decode(rc));
2369
2370 log_debug("Successfully created loaded object on TPM in %s.",
2371 FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
2372
2373 if (ret_public)
2374 *ret_public = TAKE_PTR(public);
2375 if (ret_private)
2376 *ret_private = TAKE_PTR(private);
2377 if (ret_handle)
2378 *ret_handle = TAKE_PTR(handle);
2379
2380 return 0;
2381}
2382
2383/* This calls TPM2_CreateLoaded() if the TPM supports it, otherwise it calls TPM2_Create() and TPM2_Load()
aff853f8
DS
2384 * separately. Do not use this to create primary keys, because some HW TPMs refuse to allow that; instead use
2385 * tpm2_create_primary(). */
2386int tpm2_create_loaded(
cea525a9
DS
2387 Tpm2Context *c,
2388 const Tpm2Handle *parent,
2389 const Tpm2Handle *session,
2390 const TPMT_PUBLIC *template,
2391 const TPMS_SENSITIVE_CREATE *sensitive,
2392 TPM2B_PUBLIC **ret_public,
2393 TPM2B_PRIVATE **ret_private,
2394 Tpm2Handle **ret_handle) {
2395
2396 int r;
2397
2398 if (tpm2_supports_command(c, TPM2_CC_CreateLoaded))
2399 return _tpm2_create_loaded(c, parent, session, template, sensitive, ret_public, ret_private, ret_handle);
2400
2401 /* Unfortunately, this TPM doesn't support CreateLoaded (added at spec revision 130) so we need to
2402 * create and load manually. */
2403 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2404 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
2405 r = tpm2_create(c, parent, session, template, sensitive, &public, &private);
2406 if (r < 0)
2407 return r;
2408
2409 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2410 r = tpm2_load(c, parent, session, public, private, &handle);
2411 if (r < 0)
2412 return r;
2413
2414 if (ret_public)
2415 *ret_public = TAKE_PTR(public);
2416 if (ret_private)
2417 *ret_private = TAKE_PTR(private);
2418 if (ret_handle)
2419 *ret_handle = TAKE_PTR(handle);
2420
2421 return 0;
2422}
2423
40ce7321 2424static int tpm2_marshal_private(const TPM2B_PRIVATE *private, void **ret, size_t *ret_size) {
9fe3b636
LP
2425 size_t max_size = sizeof(*private), blob_size = 0;
2426 _cleanup_free_ void *blob = NULL;
2427 TSS2_RC rc;
2428
2429 assert(private);
2430 assert(ret);
2431 assert(ret_size);
2432
2433 blob = malloc0(max_size);
2434 if (!blob)
2435 return log_oom_debug();
2436
2437 rc = sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, blob, max_size, &blob_size);
2438 if (rc != TSS2_RC_SUCCESS)
2439 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2440 "Failed to marshal private key: %s", sym_Tss2_RC_Decode(rc));
2441
2442 *ret = TAKE_PTR(blob);
2443 *ret_size = blob_size;
2444 return 0;
2445}
2446
40ce7321 2447static int tpm2_unmarshal_private(const void *data, size_t size, TPM2B_PRIVATE *ret_private) {
9fe3b636
LP
2448 TPM2B_PRIVATE private = {};
2449 size_t offset = 0;
2450 TSS2_RC rc;
2451
2452 assert(data || size == 0);
2453 assert(ret_private);
2454
2455 rc = sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal(data, size, &offset, &private);
2456 if (rc != TSS2_RC_SUCCESS)
2457 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2458 "Failed to unmarshal private key: %s", sym_Tss2_RC_Decode(rc));
2459 if (offset != size)
2460 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2461 "Garbage at end of private key marshal data.");
2462
2463 *ret_private = private;
2464 return 0;
2465}
2466
fbe7db47 2467int tpm2_marshal_public(const TPM2B_PUBLIC *public, void **ret, size_t *ret_size) {
9fe3b636
LP
2468 size_t max_size = sizeof(*public), blob_size = 0;
2469 _cleanup_free_ void *blob = NULL;
2470 TSS2_RC rc;
2471
2472 assert(public);
2473 assert(ret);
2474 assert(ret_size);
2475
2476 blob = malloc0(max_size);
2477 if (!blob)
2478 return log_oom_debug();
2479
2480 rc = sym_Tss2_MU_TPM2B_PUBLIC_Marshal(public, blob, max_size, &blob_size);
2481 if (rc != TSS2_RC_SUCCESS)
2482 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2483 "Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
2484
2485 *ret = TAKE_PTR(blob);
2486 *ret_size = blob_size;
2487 return 0;
2488}
2489
40ce7321 2490static int tpm2_unmarshal_public(const void *data, size_t size, TPM2B_PUBLIC *ret_public) {
9fe3b636
LP
2491 TPM2B_PUBLIC public = {};
2492 size_t offset = 0;
2493 TSS2_RC rc;
2494
2495 assert(data || size == 0);
2496 assert(ret_public);
2497
2498 rc = sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal(data, size, &offset, &public);
2499 if (rc != TSS2_RC_SUCCESS)
2500 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2501 "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc));
2502 if (offset != size)
2503 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2504 "Garbage at end of public key marshal data.");
2505
2506 *ret_public = public;
2507 return 0;
2508}
2509
36006209
LP
2510int tpm2_marshal_nv_public(const TPM2B_NV_PUBLIC *nv_public, void **ret, size_t *ret_size) {
2511 size_t max_size = sizeof(*nv_public), blob_size = 0;
2512 _cleanup_free_ void *blob = NULL;
2513 TSS2_RC rc;
2514
2515 assert(nv_public);
2516 assert(ret);
2517 assert(ret_size);
2518
2519 blob = malloc0(max_size);
2520 if (!blob)
2521 return log_oom_debug();
2522
2523 rc = sym_Tss2_MU_TPM2B_NV_PUBLIC_Marshal(nv_public, blob, max_size, &blob_size);
2524 if (rc != TSS2_RC_SUCCESS)
2525 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2526 "Failed to marshal NV public structure: %s", sym_Tss2_RC_Decode(rc));
2527
2528 *ret = TAKE_PTR(blob);
2529 *ret_size = blob_size;
2530 return 0;
2531}
2532
2533int tpm2_unmarshal_nv_public(const void *data, size_t size, TPM2B_NV_PUBLIC *ret_nv_public) {
2534 TPM2B_NV_PUBLIC nv_public = {};
2535 size_t offset = 0;
2536 TSS2_RC rc;
2537
2538 assert(data || size == 0);
2539 assert(ret_nv_public);
2540
2541 rc = sym_Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal(data, size, &offset, &nv_public);
2542 if (rc != TSS2_RC_SUCCESS)
2543 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2544 "Failed to unmarshal NV public structure: %s", sym_Tss2_RC_Decode(rc));
2545 if (offset != size)
2546 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2547 "Garbage at end of NV public structure marshal data.");
2548
2549 *ret_nv_public = nv_public;
2550 return 0;
2551}
2552
0a7874ad
DS
2553static int tpm2_import(
2554 Tpm2Context *c,
2555 const Tpm2Handle *parent,
2556 const Tpm2Handle *session,
2557 const TPM2B_PUBLIC *public,
2558 const TPM2B_PRIVATE *private,
2559 const TPM2B_ENCRYPTED_SECRET *seed,
2560 const TPM2B_DATA *encryption_key,
2561 const TPMT_SYM_DEF_OBJECT *symmetric,
2562 TPM2B_PRIVATE **ret_private) {
2563
2564 TSS2_RC rc;
2565
2566 assert(c);
2567 assert(parent);
2568 assert(!!encryption_key == !!symmetric);
2569 assert(public);
2570 assert(private);
2571 assert(seed);
2572 assert(ret_private);
2573
2574 log_debug("Importing key into TPM.");
2575
2576 rc = sym_Esys_Import(
2577 c->esys_context,
2578 parent->esys_handle,
2579 session ? session->esys_handle : ESYS_TR_PASSWORD,
2580 ESYS_TR_NONE,
2581 ESYS_TR_NONE,
2582 encryption_key,
2583 public,
2584 private,
2585 seed,
2586 symmetric ?: &(TPMT_SYM_DEF_OBJECT){ .algorithm = TPM2_ALG_NULL, },
2587 ret_private);
2588 if (rc != TSS2_RC_SUCCESS)
2589 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2590 "Failed to import key into TPM: %s", sym_Tss2_RC_Decode(rc));
2591
2592 return 0;
2593}
2594
323eb480
DS
2595/* Read hash values from the specified PCR selection. Provides a Tpm2PCRValue array that contains all
2596 * requested PCR values, in the order provided by the TPM. Normally, the provided pcr values will match
2597 * exactly what is in the provided selection, but the TPM may ignore some selected PCRs (for example, if an
2598 * unimplemented PCR index is requested), in which case those PCRs will be absent from the provided pcr
2599 * values. */
b4a6fcd5 2600int tpm2_pcr_read(
c57d8bc8
DS
2601 Tpm2Context *c,
2602 const TPML_PCR_SELECTION *pcr_selection,
323eb480 2603 Tpm2PCRValue **ret_pcr_values,
c648a4b8 2604 size_t *ret_n_pcr_values) {
c57d8bc8 2605
323eb480 2606 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
c648a4b8 2607 size_t n_pcr_values = 0;
c57d8bc8 2608 TSS2_RC rc;
321a9d9e 2609
c57d8bc8
DS
2610 assert(c);
2611 assert(pcr_selection);
323eb480
DS
2612 assert(ret_pcr_values);
2613 assert(ret_n_pcr_values);
321a9d9e 2614
323eb480 2615 TPML_PCR_SELECTION remaining = *pcr_selection;
c57d8bc8
DS
2616 while (!tpm2_tpml_pcr_selection_is_empty(&remaining)) {
2617 _cleanup_(Esys_Freep) TPML_PCR_SELECTION *current_read = NULL;
2618 _cleanup_(Esys_Freep) TPML_DIGEST *current_values = NULL;
321a9d9e 2619
c57d8bc8 2620 tpm2_log_debug_tpml_pcr_selection(&remaining, "Reading PCR selection");
321a9d9e 2621
c57d8bc8
DS
2622 /* Unfortunately, PCR_Read will not return more than 8 values. */
2623 rc = sym_Esys_PCR_Read(
2624 c->esys_context,
2625 ESYS_TR_NONE,
2626 ESYS_TR_NONE,
2627 ESYS_TR_NONE,
2628 &remaining,
2629 NULL,
2630 &current_read,
2631 &current_values);
2632 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2633 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
c57d8bc8 2634 "Failed to read TPM2 PCRs: %s", sym_Tss2_RC_Decode(rc));
321a9d9e 2635
323eb480
DS
2636 tpm2_log_debug_tpml_pcr_selection(current_read, "Read PCR selection");
2637
c57d8bc8 2638 if (tpm2_tpml_pcr_selection_is_empty(current_read)) {
f9a0ee75 2639 log_debug("TPM2 refused to read possibly unimplemented PCRs, ignoring.");
c57d8bc8 2640 break;
321a9d9e
LP
2641 }
2642
323eb480
DS
2643 unsigned i = 0;
2644 FOREACH_PCR_IN_TPML_PCR_SELECTION(index, tpms, current_read) {
2645 assert(i < current_values->count);
2646 Tpm2PCRValue pcr_value = {
2647 .index = index,
2648 .hash = tpms->hash,
2649 .value = current_values->digests[i++],
2650 };
c57d8bc8 2651
323eb480 2652 tpm2_log_debug_pcr_value(&pcr_value, /* msg= */ NULL);
c57d8bc8 2653
323eb480 2654 if (!GREEDY_REALLOC_APPEND(pcr_values, n_pcr_values, &pcr_value, 1))
f9a0ee75 2655 return log_oom_debug();
323eb480
DS
2656 }
2657 assert(i == current_values->count);
c57d8bc8 2658
323eb480
DS
2659 tpm2_tpml_pcr_selection_sub(&remaining, current_read);
2660 }
c57d8bc8 2661
323eb480 2662 tpm2_sort_pcr_values(pcr_values, n_pcr_values);
c57d8bc8 2663
cc1a78d5 2664 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
f9a0ee75 2665 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "PCR values read from TPM are not valid.");
321a9d9e 2666
323eb480
DS
2667 *ret_pcr_values = TAKE_PTR(pcr_values);
2668 *ret_n_pcr_values = n_pcr_values;
c57d8bc8
DS
2669
2670 return 0;
321a9d9e
LP
2671}
2672
b4a6fcd5
DS
2673/* Read the PCR value for each TPM2PCRValue entry in the array that does not have a value set. If all entries
2674 * have an unset hash (i.e. hash == 0), this first detects the "best" PCR bank to use; otherwise, all entries
2675 * must have a valid hash set. All entries must have a valid index. If this cannot read a PCR value for all
2676 * appropriate entries, this returns an error. This does not check the array for validity. */
2677int tpm2_pcr_read_missing_values(Tpm2Context *c, Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
2678 TPMI_ALG_HASH pcr_bank = 0;
2679 int r;
2680
2681 assert(c);
2682 assert(pcr_values || n_pcr_values == 0);
2683
2684 if (n_pcr_values > 0) {
2685 size_t hash_count;
2686 r = tpm2_pcr_values_hash_count(pcr_values, n_pcr_values, &hash_count);
2687 if (r < 0)
f9a0ee75 2688 return log_debug_errno(r, "Could not get hash count from pcr values: %m");
b4a6fcd5
DS
2689
2690 if (hash_count == 1 && pcr_values[0].hash == 0) {
2691 uint32_t mask;
2692 r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, 0, &mask);
2693 if (r < 0)
2694 return r;
2695
2696 r = tpm2_get_best_pcr_bank(c, mask, &pcr_bank);
2697 if (r < 0)
2698 return r;
2699 }
2700 }
2701
193fd573 2702 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
b4a6fcd5
DS
2703 if (v->hash == 0)
2704 v->hash = pcr_bank;
2705
2706 if (v->value.size > 0)
2707 continue;
2708
2709 TPML_PCR_SELECTION selection;
2710 r = tpm2_tpml_pcr_selection_from_pcr_values(v, 1, &selection, NULL, NULL);
2711 if (r < 0)
2712 return r;
2713
2714 _cleanup_free_ Tpm2PCRValue *read_values = NULL;
2715 size_t n_read_values;
2716 r = tpm2_pcr_read(c, &selection, &read_values, &n_read_values);
2717 if (r < 0)
2718 return r;
2719
2720 if (n_read_values == 0)
f9a0ee75 2721 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
b4a6fcd5
DS
2722 "Could not read PCR hash 0x%" PRIu16 " index %u",
2723 v->hash, v->index);
2724
2725 assert(n_read_values == 1);
2726 assert(read_values[0].hash == v->hash);
2727 assert(read_values[0].index == v->index);
2728
2729 v->value = read_values[0].value;
2730 }
2731
2732 return 0;
2733}
2734
321a9d9e 2735static int tpm2_pcr_mask_good(
23e9ccc2 2736 Tpm2Context *c,
321a9d9e
LP
2737 TPMI_ALG_HASH bank,
2738 uint32_t mask) {
2739
321a9d9e 2740 TPML_PCR_SELECTION selection;
c57d8bc8 2741 int r;
321a9d9e
LP
2742
2743 assert(c);
2744
2745 /* So we have the problem that some systems might have working TPM2 chips, but the firmware doesn't
2746 * actually measure into them, or only into a suboptimal bank. If so, the PCRs should be all zero or
2747 * all 0xFF. Detect that, so that we can warn and maybe pick a better bank. */
2748
c69bd0ab 2749 tpm2_tpml_pcr_selection_from_mask(mask, bank, &selection);
321a9d9e 2750
323eb480
DS
2751 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
2752 size_t n_pcr_values;
2753 r = tpm2_pcr_read(c, &selection, &pcr_values, &n_pcr_values);
c57d8bc8
DS
2754 if (r < 0)
2755 return r;
321a9d9e
LP
2756
2757 /* If at least one of the selected PCR values is something other than all 0x00 or all 0xFF we are happy. */
193fd573
DS
2758 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
2759 if (!memeqbyte(0x00, v->value.buffer, v->value.size) &&
2760 !memeqbyte(0xFF, v->value.buffer, v->value.size))
c57d8bc8 2761 return true;
321a9d9e 2762
c57d8bc8 2763 return false;
321a9d9e
LP
2764}
2765
59fafaee
LP
2766static int tpm2_bank_has24(const TPMS_PCR_SELECTION *selection) {
2767
2768 assert(selection);
2769
2770 /* As per https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
2771 * TPM2 on a Client PC must have at least 24 PCRs. If this TPM has less, just skip over it. */
2772 if (selection->sizeofSelect < TPM2_PCRS_MAX/8) {
2773 log_debug("Skipping TPM2 PCR bank %s with fewer than 24 PCRs.",
7bfe0a48 2774 strna(tpm2_hash_alg_to_string(selection->hash)));
59fafaee
LP
2775 return false;
2776 }
2777
2778 assert_cc(TPM2_PCRS_MAX % 8 == 0);
2779
2780 /* It's not enough to check how many PCRs there are, we also need to check that the 24 are
2781 * enabled for this bank. Otherwise this TPM doesn't qualify. */
2782 bool valid = true;
2783 for (size_t j = 0; j < TPM2_PCRS_MAX/8; j++)
2784 if (selection->pcrSelect[j] != 0xFF) {
2785 valid = false;
2786 break;
2787 }
2788
2789 if (!valid)
2790 log_debug("TPM2 PCR bank %s has fewer than 24 PCR bits enabled, ignoring.",
7bfe0a48 2791 strna(tpm2_hash_alg_to_string(selection->hash)));
59fafaee
LP
2792
2793 return valid;
2794}
2795
b4a6fcd5 2796int tpm2_get_best_pcr_bank(
23e9ccc2 2797 Tpm2Context *c,
321a9d9e 2798 uint32_t pcr_mask,
07697bfe
LP
2799 TPMI_ALG_HASH *ret) {
2800
321a9d9e 2801 TPMI_ALG_HASH supported_hash = 0, hash_with_valid_pcr = 0;
59fafaee 2802 int r;
07697bfe 2803
321a9d9e 2804 assert(c);
3a35d6cd 2805 assert(ret);
321a9d9e 2806
3ee5e9d5
LP
2807 if (pcr_mask == 0) {
2808 log_debug("Asked to pick best PCR bank but no PCRs selected we could derive this from. Defaulting to SHA256.");
2809 *ret = TPM2_ALG_SHA256; /* if no PCRs are selected this doesn't matter anyway... */
2810 return 0;
2811 }
2812
9ea0ffe6 2813 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &c->capability_pcrs) {
3a35d6cd 2814 TPMI_ALG_HASH hash = selection->hash;
321a9d9e
LP
2815 int good;
2816
2817 /* For now we are only interested in the SHA1 and SHA256 banks */
3a35d6cd 2818 if (!IN_SET(hash, TPM2_ALG_SHA256, TPM2_ALG_SHA1))
321a9d9e 2819 continue;
07697bfe 2820
3a35d6cd 2821 r = tpm2_bank_has24(selection);
59fafaee
LP
2822 if (r < 0)
2823 return r;
2824 if (!r)
07697bfe 2825 continue;
07697bfe 2826
3a35d6cd 2827 good = tpm2_pcr_mask_good(c, hash, pcr_mask);
321a9d9e
LP
2828 if (good < 0)
2829 return good;
2830
3a35d6cd 2831 if (hash == TPM2_ALG_SHA256) {
321a9d9e
LP
2832 supported_hash = TPM2_ALG_SHA256;
2833 if (good) {
2834 /* Great, SHA256 is supported and has initialized PCR values, we are done. */
2835 hash_with_valid_pcr = TPM2_ALG_SHA256;
2836 break;
2837 }
2838 } else {
3a35d6cd 2839 assert(hash == TPM2_ALG_SHA1);
321a9d9e
LP
2840
2841 if (supported_hash == 0)
2842 supported_hash = TPM2_ALG_SHA1;
07697bfe 2843
321a9d9e
LP
2844 if (good && hash_with_valid_pcr == 0)
2845 hash_with_valid_pcr = TPM2_ALG_SHA1;
2846 }
07697bfe
LP
2847 }
2848
321a9d9e
LP
2849 /* We preferably pick SHA256, but only if its PCRs are initialized or neither the SHA1 nor the SHA256
2850 * PCRs are initialized. If SHA256 is not supported but SHA1 is and its PCRs are too, we prefer
2851 * SHA1.
2852 *
2853 * We log at LOG_NOTICE level whenever we end up using the SHA1 bank or when the PCRs we bind to are
2854 * not initialized. */
2855
2856 if (hash_with_valid_pcr == TPM2_ALG_SHA256) {
2857 assert(supported_hash == TPM2_ALG_SHA256);
2858 log_debug("TPM2 device supports SHA256 PCR bank and SHA256 PCRs are valid, yay!");
2859 *ret = TPM2_ALG_SHA256;
2860 } else if (hash_with_valid_pcr == TPM2_ALG_SHA1) {
2861 if (supported_hash == TPM2_ALG_SHA256)
2862 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.");
2863 else {
2864 assert(supported_hash == TPM2_ALG_SHA1);
2865 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.");
2866 }
2867
2868 *ret = TPM2_ALG_SHA1;
2869 } else if (supported_hash == TPM2_ALG_SHA256) {
2870 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!");
2871 *ret = TPM2_ALG_SHA256;
2872 } else if (supported_hash == TPM2_ALG_SHA1) {
2873 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!");
2874 *ret = TPM2_ALG_SHA1;
2875 } else
f9a0ee75 2876 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
07697bfe
LP
2877 "TPM2 module supports neither SHA1 nor SHA256 PCR banks, cannot operate.");
2878
07697bfe
LP
2879 return 0;
2880}
2881
c5bf1f85 2882int tpm2_get_good_pcr_banks(
23e9ccc2 2883 Tpm2Context *c,
c5bf1f85
LP
2884 uint32_t pcr_mask,
2885 TPMI_ALG_HASH **ret) {
2886
2887 _cleanup_free_ TPMI_ALG_HASH *good_banks = NULL, *fallback_banks = NULL;
c5bf1f85 2888 size_t n_good_banks = 0, n_fallback_banks = 0;
c5bf1f85
LP
2889 int r;
2890
2891 assert(c);
2892 assert(ret);
2893
9ea0ffe6 2894 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &c->capability_pcrs) {
3a35d6cd 2895 TPMI_ALG_HASH hash = selection->hash;
c5bf1f85
LP
2896
2897 /* Let's see if this bank is superficially OK, i.e. has at least 24 enabled registers */
3a35d6cd 2898 r = tpm2_bank_has24(selection);
c5bf1f85
LP
2899 if (r < 0)
2900 return r;
2901 if (!r)
2902 continue;
2903
2904 /* Let's now see if this bank has any of the selected PCRs actually initialized */
3a35d6cd 2905 r = tpm2_pcr_mask_good(c, hash, pcr_mask);
c5bf1f85
LP
2906 if (r < 0)
2907 return r;
2908
2909 if (n_good_banks + n_fallback_banks >= INT_MAX)
f9a0ee75 2910 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "Too many good TPM2 banks?");
c5bf1f85
LP
2911
2912 if (r) {
2913 if (!GREEDY_REALLOC(good_banks, n_good_banks+1))
f9a0ee75 2914 return log_oom_debug();
c5bf1f85 2915
3a35d6cd 2916 good_banks[n_good_banks++] = hash;
c5bf1f85
LP
2917 } else {
2918 if (!GREEDY_REALLOC(fallback_banks, n_fallback_banks+1))
f9a0ee75 2919 return log_oom_debug();
c5bf1f85 2920
3a35d6cd 2921 fallback_banks[n_fallback_banks++] = hash;
c5bf1f85
LP
2922 }
2923 }
2924
2925 /* Preferably, use the good banks (i.e. the ones the PCR values are actually initialized so
2926 * far). Otherwise use the fallback banks (i.e. which exist and are enabled, but so far not used. */
2927 if (n_good_banks > 0) {
2928 log_debug("Found %zu fully initialized TPM2 banks.", n_good_banks);
2929 *ret = TAKE_PTR(good_banks);
2930 return (int) n_good_banks;
2931 }
2932 if (n_fallback_banks > 0) {
2933 log_debug("Found %zu enabled but un-initialized TPM2 banks.", n_fallback_banks);
2934 *ret = TAKE_PTR(fallback_banks);
2935 return (int) n_fallback_banks;
2936 }
2937
2938 /* No suitable banks found. */
2939 *ret = NULL;
2940 return 0;
2941}
2942
e4481cc5 2943int tpm2_get_good_pcr_banks_strv(
23e9ccc2 2944 Tpm2Context *c,
e4481cc5
LP
2945 uint32_t pcr_mask,
2946 char ***ret) {
2947
0d7009d3 2948#if HAVE_OPENSSL
e4481cc5
LP
2949 _cleanup_free_ TPMI_ALG_HASH *algs = NULL;
2950 _cleanup_strv_free_ char **l = NULL;
2951 int n_algs;
2952
2953 assert(c);
2954 assert(ret);
2955
2956 n_algs = tpm2_get_good_pcr_banks(c, pcr_mask, &algs);
2957 if (n_algs < 0)
2958 return n_algs;
2959
193fd573 2960 FOREACH_ARRAY(a, algs, n_algs) {
e4481cc5
LP
2961 _cleanup_free_ char *n = NULL;
2962 const EVP_MD *implementation;
2963 const char *salg;
2964
193fd573 2965 salg = tpm2_hash_alg_to_string(*a);
e4481cc5 2966 if (!salg)
f9a0ee75 2967 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM2 operates with unknown PCR algorithm, can't measure.");
e4481cc5
LP
2968
2969 implementation = EVP_get_digestbyname(salg);
2970 if (!implementation)
f9a0ee75 2971 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM2 operates with unsupported PCR algorithm, can't measure.");
e4481cc5
LP
2972
2973 n = strdup(ASSERT_PTR(EVP_MD_name(implementation)));
2974 if (!n)
f9a0ee75 2975 return log_oom_debug();
e4481cc5
LP
2976
2977 ascii_strlower(n); /* OpenSSL uses uppercase digest names, we prefer them lower case. */
2978
2979 if (strv_consume(&l, TAKE_PTR(n)) < 0)
f9a0ee75 2980 return log_oom_debug();
e4481cc5
LP
2981 }
2982
2983 *ret = TAKE_PTR(l);
2984 return 0;
0d7009d3 2985#else /* HAVE_OPENSSL */
f9a0ee75 2986 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
0d7009d3 2987#endif
e4481cc5
LP
2988}
2989
da92d39a
DS
2990/* Hash data into the digest.
2991 *
2992 * If 'extend' is true, the hashing operation starts with the existing digest hash (and the digest is
2993 * required to have a hash and its size must be correct). If 'extend' is false, the digest size is
2994 * initialized to the correct size for 'alg' and the hashing operation does not include any existing digest
2995 * hash. If 'extend' is false and no data is provided, the digest is initialized to a zero digest.
2996 *
2997 * On success, the digest hash will be updated with the hashing operation result and the digest size will be
2998 * correct for 'alg'.
2999 *
3000 * This currently only provides SHA256, so 'alg' must be TPM2_ALG_SHA256. */
3001int tpm2_digest_many(
3002 TPMI_ALG_HASH alg,
3003 TPM2B_DIGEST *digest,
3004 const struct iovec data[],
3005 size_t n_data,
3006 bool extend) {
3007
3008 struct sha256_ctx ctx;
3009
3010 assert(digest);
3011 assert(data || n_data == 0);
3012
3013 if (alg != TPM2_ALG_SHA256)
f9a0ee75 3014 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
da92d39a
DS
3015 "Hash algorithm not supported: 0x%x", alg);
3016
3017 if (extend && digest->size != SHA256_DIGEST_SIZE)
f9a0ee75 3018 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
da92d39a
DS
3019 "Digest size 0x%x, require 0x%x",
3020 digest->size, (unsigned)SHA256_DIGEST_SIZE);
3021
3022 /* Since we're hardcoding SHA256 (for now), we can check this at compile time. */
3023 assert_cc(sizeof(digest->buffer) >= SHA256_DIGEST_SIZE);
3024
3025 CLEANUP_ERASE(ctx);
3026
3027 sha256_init_ctx(&ctx);
3028
3029 if (extend)
3030 sha256_process_bytes(digest->buffer, digest->size, &ctx);
3031 else {
4af7f27a
LP
3032 *digest = (TPM2B_DIGEST) {
3033 .size = SHA256_DIGEST_SIZE,
3034 };
da92d39a
DS
3035 if (n_data == 0) /* If not extending and no data, return zero hash */
3036 return 0;
3037 }
3038
193fd573
DS
3039 FOREACH_ARRAY(d, data, n_data)
3040 sha256_process_bytes(d->iov_base, d->iov_len, &ctx);
da92d39a
DS
3041
3042 sha256_finish_ctx(&ctx, digest->buffer);
3043
3044 return 0;
3045}
3046
3047/* Same as tpm2_digest_many() but data is contained in TPM2B_DIGEST[]. The digests may be any size digests. */
3048int tpm2_digest_many_digests(
3049 TPMI_ALG_HASH alg,
3050 TPM2B_DIGEST *digest,
3051 const TPM2B_DIGEST data[],
3052 size_t n_data,
3053 bool extend) {
3054
3055 _cleanup_free_ struct iovec *iovecs = NULL;
3056
3057 assert(data || n_data == 0);
3058
3059 iovecs = new(struct iovec, n_data);
3060 if (!iovecs)
f9a0ee75 3061 return log_oom_debug();
da92d39a
DS
3062
3063 for (size_t i = 0; i < n_data; i++)
3064 iovecs[i] = IOVEC_MAKE((void*) data[i].buffer, data[i].size);
3065
3066 return tpm2_digest_many(alg, digest, iovecs, n_data, extend);
3067}
3068
f230572f
DS
3069/* This hashes the provided pin into a digest value, but also verifies that the final byte is not 0, because
3070 * the TPM specification Part 1 ("Architecture") section Authorization Values (subsection "Authorization Size
3071 * Convention") states "Trailing octets of zero are to be removed from any string before it is used as an
3072 * authValue". Since the TPM doesn't know if the auth value is a "string" or just a hash digest, any hash
63477a71
DS
3073 * digest that randomly happens to end in 0 must have the final 0(s) trimmed.
3074 *
3075 * This is required at 2 points. First, when setting the authValue during creation of new sealed objects, in
3076 * tpm2_seal(). This only applies to newly created objects, of course. Second, when using a previously
3077 * created sealed object that has an authValue set, we use the sealed objects as the session bind key. This
3078 * requires calling SetAuth so tpm2-tss can correctly calculate the HMAC to use for the encryption session.
3079 *
3080 * TPM implementations will perform the trimming for any authValue for existing sealed objects, so the
3081 * tpm2-tss library must also perform the trimming before HMAC calculation, but it does not yet; this bug is
3082 * open to add the trimming: https://github.com/tpm2-software/tpm2-tss/issues/2664
3083 *
3084 * Until our minimum tpm2-tss version contains a fix for that bug, we must perform the trimming
3085 * ourselves. Note that since we are trimming, which is exactly what a TPM implementation would do, this will
3086 * work for both existing objects with a authValue ending in 0(s) as well as new sealed objects we create,
3087 * which we will trim the 0(s) from before sending to the TPM.
3088 */
3089static void tpm2_trim_auth_value(TPM2B_AUTH *auth) {
3090 bool trimmed = false;
3091
3092 assert(auth);
3093
3094 while (auth->size > 0 && auth->buffer[auth->size - 1] == 0) {
3095 trimmed = true;
3096 auth->size--;
3097 }
3098
3099 if (trimmed)
3100 log_debug("authValue ends in 0, trimming as required by the TPM2 specification Part 1 section 'HMAC Computation' authValue Note 2.");
3101}
3102
d0f8da98 3103int tpm2_auth_value_from_pin(TPMI_ALG_HASH hash, const char *pin, TPM2B_AUTH *ret_auth) {
f230572f
DS
3104 TPM2B_AUTH auth = {};
3105 int r;
3106
3107 assert(pin);
3108 assert(ret_auth);
3109
3110 r = tpm2_digest_buffer(hash, &auth, pin, strlen(pin), /* extend= */ false);
3111 if (r < 0)
3112 return r;
3113
63477a71 3114 tpm2_trim_auth_value(&auth);
f230572f
DS
3115
3116 *ret_auth = TAKE_STRUCT(auth);
3117
3118 return 0;
3119}
3120
f7be7a24 3121int tpm2_set_auth_binary(Tpm2Context *c, const Tpm2Handle *handle, const TPM2B_AUTH *auth) {
409a65f8 3122 TSS2_RC rc;
f7be7a24
LP
3123
3124 assert(c);
3125 assert(handle);
3126
3127 if (!auth)
3128 return 0;
3129
3130 rc = sym_Esys_TR_SetAuth(c->esys_context, handle->esys_handle, auth);
3131 if (rc != TSS2_RC_SUCCESS)
3132 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3133 "Failed to load PIN in TPM: %s", sym_Tss2_RC_Decode(rc));
3134
3135 return 0;
3136}
3137
3138int tpm2_set_auth(Tpm2Context *c, const Tpm2Handle *handle, const char *pin) {
3139 TPM2B_AUTH auth = {};
409a65f8
DS
3140 int r;
3141
3142 assert(c);
3143 assert(handle);
3144
3145 if (!pin)
3146 return 0;
3147
3148 CLEANUP_ERASE(auth);
3149
d0f8da98 3150 r = tpm2_auth_value_from_pin(TPM2_ALG_SHA256, pin, &auth);
409a65f8
DS
3151 if (r < 0)
3152 return r;
3153
f7be7a24 3154 return tpm2_set_auth_binary(c, handle, &auth);
409a65f8
DS
3155}
3156
e976445d
DS
3157static bool tpm2_is_encryption_session(Tpm2Context *c, const Tpm2Handle *session) {
3158 TPMA_SESSION flags = 0;
3159 TSS2_RC rc;
3160
3161 assert(c);
3162 assert(session);
3163
3164 rc = sym_Esys_TRSess_GetAttributes(c->esys_context, session->esys_handle, &flags);
3165 if (rc != TSS2_RC_SUCCESS)
3166 return false;
3167
3168 return (flags & TPMA_SESSION_DECRYPT) && (flags & TPMA_SESSION_ENCRYPT);
3169}
3170
8f3f9c2b 3171int tpm2_make_encryption_session(
23e9ccc2 3172 Tpm2Context *c,
16e16b8c
DS
3173 const Tpm2Handle *primary,
3174 const Tpm2Handle *bind_key,
16e16b8c 3175 Tpm2Handle **ret_session) {
da29de23 3176
da29de23
GG
3177 const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT |
3178 TPMA_SESSION_CONTINUESESSION;
da29de23 3179 TSS2_RC rc;
16e16b8c 3180 int r;
da29de23
GG
3181
3182 assert(c);
73592a7c 3183 assert(primary);
16e16b8c 3184 assert(ret_session);
da29de23
GG
3185
3186 log_debug("Starting HMAC encryption session.");
3187
3188 /* Start a salted, unbound HMAC session with a well-known key (e.g. primary key) as tpmKey, which
3189 * means that the random salt will be encrypted with the well-known key. That way, only the TPM can
3190 * recover the salt, which is then used for key derivation. */
1dc8f518 3191 _cleanup_(tpm2_handle_freep) Tpm2Handle *session = NULL;
16e16b8c
DS
3192 r = tpm2_handle_new(c, &session);
3193 if (r < 0)
3194 return r;
3195
da29de23 3196 rc = sym_Esys_StartAuthSession(
23e9ccc2 3197 c->esys_context,
16e16b8c 3198 primary->esys_handle,
73592a7c 3199 bind_key ? bind_key->esys_handle : ESYS_TR_NONE,
da29de23
GG
3200 ESYS_TR_NONE,
3201 ESYS_TR_NONE,
3202 ESYS_TR_NONE,
3203 NULL,
3204 TPM2_SE_HMAC,
a47060bb 3205 &SESSION_TEMPLATE_SYM_AES_128_CFB,
da29de23 3206 TPM2_ALG_SHA256,
16e16b8c 3207 &session->esys_handle);
da29de23 3208 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3209 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
da29de23
GG
3210 "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
3211
3212 /* Enable parameter encryption/decryption with AES in CFB mode. Together with HMAC digests (which are
3213 * always used for sessions), this provides confidentiality, integrity and replay protection for
3214 * operations that use this session. */
16e16b8c 3215 rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session->esys_handle, sessionAttributes, 0xff);
da29de23 3216 if (rc != TSS2_RC_SUCCESS)
f9a0ee75
DS
3217 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3218 "Failed to configure TPM session: %s", sym_Tss2_RC_Decode(rc));
da29de23 3219
16e16b8c 3220 *ret_session = TAKE_PTR(session);
da29de23 3221
da29de23
GG
3222 return 0;
3223}
3224
8f3f9c2b 3225int tpm2_make_policy_session(
2cd9d575
DS
3226 Tpm2Context *c,
3227 const Tpm2Handle *primary,
3228 const Tpm2Handle *encryption_session,
2cd9d575
DS
3229 Tpm2Handle **ret_session) {
3230
2cd9d575
DS
3231 TSS2_RC rc;
3232 int r;
3233
3234 assert(c);
3235 assert(primary);
3236 assert(encryption_session);
3237 assert(ret_session);
3238
3239 if (!tpm2_is_encryption_session(c, encryption_session))
f9a0ee75 3240 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
2cd9d575
DS
3241 "Missing encryption session");
3242
3243 log_debug("Starting policy session.");
3244
1dc8f518 3245 _cleanup_(tpm2_handle_freep) Tpm2Handle *session = NULL;
2cd9d575
DS
3246 r = tpm2_handle_new(c, &session);
3247 if (r < 0)
3248 return r;
3249
3250 rc = sym_Esys_StartAuthSession(
3251 c->esys_context,
3252 primary->esys_handle,
3253 ESYS_TR_NONE,
3254 encryption_session->esys_handle,
3255 ESYS_TR_NONE,
3256 ESYS_TR_NONE,
3257 NULL,
4bba26ae 3258 TPM2_SE_POLICY,
a47060bb 3259 &SESSION_TEMPLATE_SYM_AES_128_CFB,
2cd9d575
DS
3260 TPM2_ALG_SHA256,
3261 &session->esys_handle);
3262 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3263 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2cd9d575
DS
3264 "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
3265
3266 *ret_session = TAKE_PTR(session);
3267
3268 return 0;
3269}
3270
d9b5841d
LP
3271static int find_signature(
3272 JsonVariant *v,
95898241
DS
3273 const TPML_PCR_SELECTION *pcr_selection,
3274 const void *fp,
3275 size_t fp_size,
d9b5841d
LP
3276 const void *policy,
3277 size_t policy_size,
3278 void *ret_signature,
3279 size_t *ret_signature_size) {
3280
95898241 3281#if HAVE_OPENSSL
d9b5841d 3282 JsonVariant *b, *i;
d9b5841d
LP
3283 const char *k;
3284 int r;
3285
3286 /* Searches for a signature blob in the specified JSON object. Search keys are PCR bank, PCR mask,
3287 * public key, and policy digest. */
3288
3289 if (!json_variant_is_object(v))
f9a0ee75 3290 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature is not a JSON object.");
d9b5841d 3291
95898241 3292 uint16_t pcr_bank = pcr_selection->pcrSelections[0].hash;
dbaae766 3293 uint32_t pcr_mask = tpm2_tpml_pcr_selection_to_mask(pcr_selection, pcr_bank);
95898241 3294
7bfe0a48 3295 k = tpm2_hash_alg_to_string(pcr_bank);
d9b5841d 3296 if (!k)
f9a0ee75 3297 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Don't know PCR bank %" PRIu16, pcr_bank);
d9b5841d
LP
3298
3299 /* First, find field by bank */
3300 b = json_variant_by_key(v, k);
3301 if (!b)
f9a0ee75 3302 return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Signature lacks data for PCR bank '%s'.", k);
d9b5841d
LP
3303
3304 if (!json_variant_is_array(b))
f9a0ee75 3305 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Bank data is not a JSON array.");
d9b5841d
LP
3306
3307 /* Now iterate through all signatures known for this bank */
3308 JSON_VARIANT_ARRAY_FOREACH(i, b) {
3309 _cleanup_free_ void *fpj_data = NULL, *polj_data = NULL;
3310 JsonVariant *maskj, *fpj, *sigj, *polj;
3311 size_t fpj_size, polj_size;
3312 uint32_t parsed_mask;
3313
3314 if (!json_variant_is_object(i))
f9a0ee75 3315 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Bank data element is not a JSON object");
d9b5841d
LP
3316
3317 /* Check if the PCR mask matches our expectations */
3318 maskj = json_variant_by_key(i, "pcrs");
3319 if (!maskj)
3320 continue;
3321
3322 r = tpm2_parse_pcr_json_array(maskj, &parsed_mask);
3323 if (r < 0)
f9a0ee75 3324 return log_debug_errno(r, "Failed to parse JSON PCR mask");
d9b5841d
LP
3325
3326 if (parsed_mask != pcr_mask)
3327 continue; /* Not for this PCR mask */
3328
3329 /* Then check if this is for the public key we operate with */
3330 fpj = json_variant_by_key(i, "pkfp");
3331 if (!fpj)
3332 continue;
3333
3334 r = json_variant_unhex(fpj, &fpj_data, &fpj_size);
3335 if (r < 0)
f9a0ee75 3336 return log_debug_errno(r, "Failed to decode fingerprint in JSON data: %m");
d9b5841d 3337
d9b5841d
LP
3338 if (memcmp_nn(fp, fp_size, fpj_data, fpj_size) != 0)
3339 continue; /* Not for this public key */
3340
3341 /* Finally, check if this is for the PCR policy we expect this to be */
3342 polj = json_variant_by_key(i, "pol");
3343 if (!polj)
3344 continue;
3345
3346 r = json_variant_unhex(polj, &polj_data, &polj_size);
3347 if (r < 0)
f9a0ee75 3348 return log_debug_errno(r, "Failed to decode policy hash JSON data: %m");
d9b5841d
LP
3349
3350 if (memcmp_nn(policy, policy_size, polj_data, polj_size) != 0)
3351 continue;
3352
3353 /* This entry matches all our expectations, now return the signature included in it */
3354 sigj = json_variant_by_key(i, "sig");
3355 if (!sigj)
3356 continue;
3357
3358 return json_variant_unbase64(sigj, ret_signature, ret_signature_size);
3359 }
3360
f9a0ee75 3361 return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Couldn't find signature for this PCR bank, PCR index and public key.");
95898241 3362#else /* HAVE_OPENSSL */
f9a0ee75 3363 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
395c1d9a 3364#endif
95898241 3365}
d9b5841d 3366
dbae4b95
DS
3367/* Calculates the "name" of a public key.
3368 *
3369 * As specified in TPM2 spec "Part 1: Architecture", a key's "name" is its nameAlg value followed by a hash
3370 * of its TPM2 public area, all properly marshalled. This allows a key's "name" to be dependent not only on
3371 * the key fingerprint, but also on the TPM2-specific fields that associated with the key (i.e. all fields in
3372 * TPMT_PUBLIC). Note that this means an existing key may not change any of its TPMT_PUBLIC fields, since
3373 * that would also change the key name.
3374 *
3375 * Since we (currently) hardcode to always using SHA256 for hashing, this returns an error if the public key
3376 * nameAlg is not TPM2_ALG_SHA256. */
b98c4f1d 3377int tpm2_calculate_pubkey_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name) {
dbae4b95
DS
3378 TSS2_RC rc;
3379 int r;
3380
3381 assert(public);
3382 assert(ret_name);
3383
3384 r = dlopen_tpm2();
3385 if (r < 0)
f9a0ee75 3386 return log_debug_errno(r, "TPM2 support not installed: %m");
dbae4b95
DS
3387
3388 if (public->nameAlg != TPM2_ALG_SHA256)
f9a0ee75 3389 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
dbae4b95
DS
3390 "Unsupported nameAlg: 0x%x",
3391 public->nameAlg);
3392
3393 _cleanup_free_ uint8_t *buf = NULL;
3394 size_t size = 0;
3395
3396 buf = (uint8_t*) new(TPMT_PUBLIC, 1);
3397 if (!buf)
f9a0ee75 3398 return log_oom_debug();
dbae4b95
DS
3399
3400 rc = sym_Tss2_MU_TPMT_PUBLIC_Marshal(public, buf, sizeof(TPMT_PUBLIC), &size);
3401 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3402 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dbae4b95
DS
3403 "Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
3404
3405 TPM2B_DIGEST digest = {};
3406 r = tpm2_digest_buffer(TPM2_ALG_SHA256, &digest, buf, size, /* extend= */ false);
3407 if (r < 0)
3408 return r;
3409
3410 TPMT_HA ha = {
3411 .hashAlg = TPM2_ALG_SHA256,
3412 };
3413 assert(digest.size <= sizeof(ha.digest.sha256));
3414 memcpy_safe(ha.digest.sha256, digest.buffer, digest.size);
3415
3416 TPM2B_NAME name;
3417 size = 0;
3418 rc = sym_Tss2_MU_TPMT_HA_Marshal(&ha, name.name, sizeof(name.name), &size);
3419 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3420 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dbae4b95
DS
3421 "Failed to marshal key name: %s", sym_Tss2_RC_Decode(rc));
3422 name.size = size;
3423
34657b1f 3424 tpm2_log_debug_name(&name, "Calculated public key name");
dbae4b95
DS
3425
3426 *ret_name = name;
3427
3428 return 0;
3429}
3430
3431/* Get the "name" of a key from the TPM.
3432 *
0a7874ad 3433 * The "name" of a key is explained above in tpm2_calculate_pubkey_name().
dbae4b95
DS
3434 *
3435 * The handle must reference a key already present in the TPM. It may be either a public key only, or a
3436 * public/private keypair. */
98ef5f84 3437int tpm2_get_name(
dbae4b95
DS
3438 Tpm2Context *c,
3439 const Tpm2Handle *handle,
3440 TPM2B_NAME **ret_name) {
3441
3442 _cleanup_(Esys_Freep) TPM2B_NAME *name = NULL;
3443 TSS2_RC rc;
3444
3445 assert(c);
3446 assert(handle);
3447 assert(ret_name);
3448
3449 rc = sym_Esys_TR_GetName(c->esys_context, handle->esys_handle, &name);
3450 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3451 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dbae4b95
DS
3452 "Failed to get name of public key from TPM: %s", sym_Tss2_RC_Decode(rc));
3453
3454 tpm2_log_debug_name(name, "Object name");
3455
3456 *ret_name = TAKE_PTR(name);
3457
3458 return 0;
3459}
3460
34657b1f
LP
3461int tpm2_calculate_nv_index_name(const TPMS_NV_PUBLIC *nvpublic, TPM2B_NAME *ret_name) {
3462 TSS2_RC rc;
3463 int r;
3464
3465 assert(nvpublic);
3466 assert(ret_name);
3467
3468 r = dlopen_tpm2();
3469 if (r < 0)
3470 return log_debug_errno(r, "TPM2 support not installed: %m");
3471
3472 if (nvpublic->nameAlg != TPM2_ALG_SHA256)
3473 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
3474 "Unsupported nameAlg: 0x%x",
3475 nvpublic->nameAlg);
3476
3477 _cleanup_free_ uint8_t *buf = NULL;
3478 size_t size = 0;
3479
3480 buf = (uint8_t*) new(TPMS_NV_PUBLIC, 1);
3481 if (!buf)
3482 return log_oom_debug();
3483
3484 rc = sym_Tss2_MU_TPMS_NV_PUBLIC_Marshal(nvpublic, buf, sizeof(TPMS_NV_PUBLIC), &size);
3485 if (rc != TSS2_RC_SUCCESS)
3486 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3487 "Failed to marshal NV index: %s", sym_Tss2_RC_Decode(rc));
3488
3489 TPM2B_DIGEST digest = {};
3490 r = tpm2_digest_buffer(TPM2_ALG_SHA256, &digest, buf, size, /* extend= */ false);
3491 if (r < 0)
3492 return r;
3493
3494 TPMT_HA ha = {
3495 .hashAlg = TPM2_ALG_SHA256,
3496 };
3497 assert(digest.size <= sizeof(ha.digest.sha256));
3498 memcpy_safe(ha.digest.sha256, digest.buffer, digest.size);
3499
3500 TPM2B_NAME name;
3501 size = 0;
3502 rc = sym_Tss2_MU_TPMT_HA_Marshal(&ha, name.name, sizeof(name.name), &size);
3503 if (rc != TSS2_RC_SUCCESS)
3504 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3505 "Failed to marshal NV index name: %s", sym_Tss2_RC_Decode(rc));
3506 name.size = size;
3507
3508 tpm2_log_debug_name(&name, "Calculated NV index name");
3509
3510 *ret_name = name;
3511
3512 return 0;
3513}
3514
8a716354
DS
3515/* Extend 'digest' with the PolicyAuthValue calculated hash. */
3516int tpm2_calculate_policy_auth_value(TPM2B_DIGEST *digest) {
3517 TPM2_CC command = TPM2_CC_PolicyAuthValue;
3518 TSS2_RC rc;
3519 int r;
3520
3521 assert(digest);
3522 assert(digest->size == SHA256_DIGEST_SIZE);
3523
3524 r = dlopen_tpm2();
3525 if (r < 0)
f9a0ee75 3526 return log_debug_errno(r, "TPM2 support not installed: %m");
8a716354
DS
3527
3528 uint8_t buf[sizeof(command)];
3529 size_t offset = 0;
3530
3531 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
3532 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3533 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
8a716354
DS
3534 "Failed to marshal PolicyAuthValue command: %s", sym_Tss2_RC_Decode(rc));
3535
3536 if (offset != sizeof(command))
f9a0ee75 3537 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
8a716354
DS
3538 "Offset 0x%zx wrong after marshalling PolicyAuthValue command", offset);
3539
3540 r = tpm2_digest_buffer(TPM2_ALG_SHA256, digest, buf, offset, /* extend= */ true);
3541 if (r < 0)
3542 return r;
3543
3544 tpm2_log_debug_digest(digest, "PolicyAuthValue calculated digest");
3545
3546 return 0;
3547}
3548
8f3f9c2b 3549int tpm2_policy_auth_value(
8a716354
DS
3550 Tpm2Context *c,
3551 const Tpm2Handle *session,
3552 TPM2B_DIGEST **ret_policy_digest) {
3553
3554 TSS2_RC rc;
3555
3556 assert(c);
3557 assert(session);
3558
2cd8f753 3559 log_debug("Submitting AuthValue policy.");
8a716354
DS
3560
3561 rc = sym_Esys_PolicyAuthValue(
3562 c->esys_context,
3563 session->esys_handle,
3564 ESYS_TR_NONE,
3565 ESYS_TR_NONE,
3566 ESYS_TR_NONE);
3567 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3568 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
8a716354
DS
3569 "Failed to add authValue policy to TPM: %s",
3570 sym_Tss2_RC_Decode(rc));
3571
3572 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3573}
3574
cb835a2e
LP
3575/* Extend 'digest' with the PolicySigned calculated hash. */
3576int tpm2_calculate_policy_signed(TPM2B_DIGEST *digest, const TPM2B_NAME *name) {
3577 TPM2_CC command = TPM2_CC_PolicySigned;
3578 TSS2_RC rc;
3579 int r;
3580
3581 assert(digest);
3582 assert(digest->size == SHA256_DIGEST_SIZE);
3583 assert(name);
3584
3585 r = dlopen_tpm2();
3586 if (r < 0)
3587 return log_debug_errno(r, "TPM2 support not installed: %m");
3588
3589 uint8_t buf[sizeof(command)];
3590 size_t offset = 0;
3591
3592 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
3593 if (rc != TSS2_RC_SUCCESS)
3594 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3595 "Failed to marshal PolicySigned command: %s", sym_Tss2_RC_Decode(rc));
3596
3597 if (offset != sizeof(command))
3598 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3599 "Offset 0x%zx wrong after marshalling PolicySigned command", offset);
3600
3601 struct iovec data[] = {
3602 IOVEC_MAKE(buf, offset),
3603 IOVEC_MAKE(name->name, name->size),
3604 };
3605
3606 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
3607 if (r < 0)
3608 return r;
3609
3610 const TPM2B_NONCE policyRef = {}; /* For now, we do not make use of the policyRef stuff */
3611
3612 r = tpm2_digest_buffer(TPM2_ALG_SHA256, digest, policyRef.buffer, policyRef.size, /* extend= */ true);
3613 if (r < 0)
3614 return r;
3615
3616 tpm2_log_debug_digest(digest, "PolicySigned calculated digest");
3617
3618 return 0;
3619}
3620
3621int tpm2_policy_signed_hmac_sha256(
3622 Tpm2Context *c,
3623 const Tpm2Handle *session,
3624 const Tpm2Handle *hmac_key_handle,
3625 const struct iovec *hmac_key,
3626 TPM2B_DIGEST **ret_policy_digest) {
3627
3628#if HAVE_OPENSSL
3629 TSS2_RC rc;
3630 int r;
3631
3632 assert(c);
3633 assert(session);
3634 assert(hmac_key_handle);
3635 assert(iovec_is_set(hmac_key));
3636
3637 /* This sends a TPM2_PolicySigned command to the tpm. As signature key we use an HMAC-SHA256 key
3638 * specified in the hmac_key parameter. The secret key must be loaded into the TPM already and
3639 * referenced in hmac_key_handle. */
3640
3641 log_debug("Submitting PolicySigned policy for HMAC-SHA256.");
3642
3643 /* Acquire the nonce from the TPM that we shall sign */
3644 _cleanup_(Esys_Freep) TPM2B_NONCE *nonce = NULL;
3645 rc = sym_Esys_TRSess_GetNonceTPM(
3646 c->esys_context,
3647 session->esys_handle,
3648 &nonce);
3649 if (rc != TSS2_RC_SUCCESS)
3650 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3651 "Failed to determine NoneTPM of auth session: %s",
3652 sym_Tss2_RC_Decode(rc));
3653
3654 be32_t expiration = htobe64(0);
3655 const TPM2B_DIGEST cpHashA = {}; /* For now, we do not make use of the cpHashA stuff */
3656 const TPM2B_NONCE policyRef = {}; /* ditto, we do not bother with policyRef */
3657
3658 /* Put together the data to sign, as per TPM2 Spec Part 3, 23.3.1 */
3659 struct iovec data_to_sign[] = {
3660 IOVEC_MAKE(nonce->buffer, nonce->size),
3661 IOVEC_MAKE(&expiration, sizeof(expiration)),
3662 IOVEC_MAKE(cpHashA.buffer, cpHashA.size),
3663 IOVEC_MAKE(policyRef.buffer, policyRef.size),
3664 };
3665
3666 /* Now calculate the digest of the data we put together */
3667 TPM2B_DIGEST digest_to_sign;
3668 r = tpm2_digest_many(TPM2_ALG_SHA256, &digest_to_sign, data_to_sign, ELEMENTSOF(data_to_sign), /* extend= */ false);
3669 if (r < 0)
3670 return r;
3671
3672 unsigned char hmac_signature[SHA256_DIGEST_SIZE];
3673 unsigned hmac_signature_size = sizeof(hmac_signature);
3674
3675 /* And sign this with our key */
3676 if (!HMAC(EVP_sha256(),
3677 hmac_key->iov_base,
3678 hmac_key->iov_len,
3679 digest_to_sign.buffer,
3680 digest_to_sign.size,
3681 hmac_signature,
3682 &hmac_signature_size))
3683 return -ENOTRECOVERABLE;
3684
3685 /* Now bring the signature into a format that the TPM understands */
3686 TPMT_SIGNATURE sig = {
3687 .sigAlg = TPM2_ALG_HMAC,
3688 .signature.hmac.hashAlg = TPM2_ALG_SHA256,
3689 };
3690 assert(hmac_signature_size == sizeof(sig.signature.hmac.digest.sha256));
3691 memcpy(sig.signature.hmac.digest.sha256, hmac_signature, hmac_signature_size);
3692
3693 /* And submit the whole shebang to the TPM */
3694 rc = sym_Esys_PolicySigned(
3695 c->esys_context,
3696 hmac_key_handle->esys_handle,
3697 session->esys_handle,
3698 /* shandle1= */ ESYS_TR_NONE,
3699 /* shandle2= */ ESYS_TR_NONE,
3700 /* shandle3= */ ESYS_TR_NONE,
3701 nonce,
3702 &cpHashA,
3703 &policyRef,
3704 expiration,
3705 &sig,
3706 /* timeout= */ NULL,
3707 /* policyTicket= */ NULL);
3708 if (rc != TSS2_RC_SUCCESS)
3709 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3710 "Failed to add PolicySigned policy to TPM: %s",
3711 sym_Tss2_RC_Decode(rc));
3712
3713 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3714#else /* HAVE_OPENSSL */
3715 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
3716#endif
3717}
3718
2cd8f753
LP
3719int tpm2_calculate_policy_authorize_nv(
3720 const TPM2B_NV_PUBLIC *public_info,
3721 TPM2B_DIGEST *digest) {
3722 TPM2_CC command = TPM2_CC_PolicyAuthorizeNV;
3723 TSS2_RC rc;
3724 int r;
3725
3726 assert(public_info);
3727 assert(digest);
3728 assert(digest->size == SHA256_DIGEST_SIZE);
3729
3730 r = dlopen_tpm2();
3731 if (r < 0)
3732 return log_debug_errno(r, "TPM2 support not installed: %m");
3733
3734 uint8_t buf[sizeof(command)];
3735 size_t offset = 0;
3736
3737 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
3738 if (rc != TSS2_RC_SUCCESS)
3739 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3740 "Failed to marshal PolicyAuthorizeNV command: %s", sym_Tss2_RC_Decode(rc));
3741
3742 if (offset != sizeof(command))
3743 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3744 "Offset 0x%zx wrong after marshalling PolicyAuthorizeNV command", offset);
3745
3746 TPM2B_NV_PUBLIC public_info_copy = *public_info; /* Make a copy, since we must set TPMA_NV_WRITTEN for the calculation */
3747 public_info_copy.nvPublic.attributes |= TPMA_NV_WRITTEN;
3748
3749 TPM2B_NAME name = {};
3750 r = tpm2_calculate_nv_index_name(&public_info_copy.nvPublic, &name);
3751 if (r < 0)
3752 return r;
3753
3754 struct iovec data[] = {
3755 IOVEC_MAKE(buf, offset),
3756 IOVEC_MAKE(name.name, name.size),
3757 };
3758
3759 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
3760 if (r < 0)
3761 return r;
3762
3763 tpm2_log_debug_digest(digest, "PolicyAuthorizeNV calculated digest");
3764
3765 return 0;
3766}
3767
3768int tpm2_policy_authorize_nv(
3769 Tpm2Context *c,
3770 const Tpm2Handle *session,
3771 const Tpm2Handle *nv_handle,
3772 TPM2B_DIGEST **ret_policy_digest) {
3773
3774 TSS2_RC rc;
3775
3776 assert(c);
3777 assert(session);
3778
3779 log_debug("Submitting AuthorizeNV policy.");
3780
3781 rc = sym_Esys_PolicyAuthorizeNV(
3782 c->esys_context,
3783 ESYS_TR_RH_OWNER,
3784 nv_handle->esys_handle,
3785 session->esys_handle,
3786 ESYS_TR_PASSWORD,
3787 ESYS_TR_NONE,
3788 ESYS_TR_NONE);
3789 if (rc != TSS2_RC_SUCCESS)
3790 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3791 "Failed to add AuthorizeNV policy to TPM: %s",
3792 sym_Tss2_RC_Decode(rc));
3793
3794 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3795}
3796
3797int tpm2_policy_or(
3798 Tpm2Context *c,
3799 const Tpm2Handle *session,
3800 const TPM2B_DIGEST *branches, size_t n_branches,
3801 TPM2B_DIGEST **ret_policy_digest) {
3802
3803 TPML_DIGEST hash_list;
3804 TSS2_RC rc;
3805
3806 assert(c);
3807 assert(session);
3808
3809 if (n_branches > ELEMENTSOF(hash_list.digests))
3810 return -EOPNOTSUPP;
3811
3812 log_debug("Submitting OR policy.");
3813
3814 hash_list = (TPML_DIGEST) {
3815 .count = n_branches,
3816 };
3817
3818 memcpy(hash_list.digests, branches, n_branches * sizeof(TPM2B_DIGEST));
3819
3820 if (DEBUG_LOGGING)
3821 for (size_t i = 0; i < hash_list.count; i++) {
3822 _cleanup_free_ char *h = hexmem(hash_list.digests[i].buffer, hash_list.digests[i].size);
3823 log_debug("Submitting OR Branch #%zu: %s", i, h);
3824 }
3825
3826 rc = sym_Esys_PolicyOR(
3827 c->esys_context,
3828 session->esys_handle,
3829 ESYS_TR_NONE,
3830 ESYS_TR_NONE,
3831 ESYS_TR_NONE,
3832 &hash_list);
3833 if (rc != TSS2_RC_SUCCESS)
3834 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3835 "Failed to add OR policy to TPM: %s",
3836 sym_Tss2_RC_Decode(rc));
3837
3838 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3839}
3840
3841/* Extend 'digest' with the PolicyOR calculated hash. */
3842int tpm2_calculate_policy_or(const TPM2B_DIGEST *branches, size_t n_branches, TPM2B_DIGEST *digest) {
3843 TPM2_CC command = TPM2_CC_PolicyOR;
3844 TSS2_RC rc;
3845 int r;
3846
3847 assert(digest);
3848 assert(digest->size == SHA256_DIGEST_SIZE);
3849
3850 if (n_branches == 0)
3851 return -EINVAL;
3852 if (n_branches == 1)
3853 log_warning("PolicyOR with a single branch submitted, this is weird.");
3854 if (n_branches > 8)
3855 return -E2BIG;
3856
3857 r = dlopen_tpm2();
3858 if (r < 0)
3859 return log_error_errno(r, "TPM2 support not installed: %m");
3860
3861 uint8_t buf[sizeof(command)];
3862 size_t offset = 0;
3863
3864 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
3865 if (rc != TSS2_RC_SUCCESS)
3866 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3867 "Failed to marshal PolicyOR command: %s", sym_Tss2_RC_Decode(rc));
3868
3869 if (offset != sizeof(command))
3870 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3871 "Offset 0x%zx wrong after marshalling PolicyOR command", offset);
3872 _cleanup_free_ struct iovec *data = new(struct iovec, 1 + n_branches);
3873 if (!data)
3874 return log_oom();
3875
3876 data[0] = IOVEC_MAKE(buf, offset);
3877 for (size_t i = 0; i < n_branches; i++) {
3878 data[1 + i] = IOVEC_MAKE((void*) branches[i].buffer, branches[i].size);
3879
3880 if (DEBUG_LOGGING) {
3881 _cleanup_free_ char *h = hexmem(branches[i].buffer, branches[i].size);
3882 log_debug("OR Branch #%zu: %s", i, h);
3883 }
3884 }
3885
3886 /* PolicyOR does not use the previous hash value; we must zero and then extend it. */
3887 zero(digest->buffer);
3888
3889 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, 1 + n_branches, /* extend= */ true);
3890 if (r < 0)
3891 return r;
3892
3893 tpm2_log_debug_digest(digest, "PolicyOR calculated digest");
3894
3895 return 0;
3896}
3897
dcbc4674
DS
3898/* Extend 'digest' with the PolicyPCR calculated hash. */
3899int tpm2_calculate_policy_pcr(
6e8fb3ad 3900 const Tpm2PCRValue *pcr_values,
dcbc4674
DS
3901 size_t n_pcr_values,
3902 TPM2B_DIGEST *digest) {
3903
3904 TPM2_CC command = TPM2_CC_PolicyPCR;
3905 TSS2_RC rc;
3906 int r;
3907
dcbc4674
DS
3908 assert(pcr_values || n_pcr_values == 0);
3909 assert(digest);
3910 assert(digest->size == SHA256_DIGEST_SIZE);
3911
3912 r = dlopen_tpm2();
3913 if (r < 0)
f9a0ee75 3914 return log_debug_errno(r, "TPM2 support not installed: %m");
dcbc4674 3915
6e8fb3ad
DS
3916 TPML_PCR_SELECTION pcr_selection;
3917 _cleanup_free_ TPM2B_DIGEST *values = NULL;
3918 size_t n_values;
3919 r = tpm2_tpml_pcr_selection_from_pcr_values(pcr_values, n_pcr_values, &pcr_selection, &values, &n_values);
3920 if (r < 0)
f9a0ee75 3921 return log_debug_errno(r, "Could not convert PCR values to TPML_PCR_SELECTION: %m");
6e8fb3ad 3922
dcbc4674 3923 TPM2B_DIGEST hash = {};
6e8fb3ad 3924 r = tpm2_digest_many_digests(TPM2_ALG_SHA256, &hash, values, n_values, /* extend= */ false);
dcbc4674
DS
3925 if (r < 0)
3926 return r;
3927
3928 _cleanup_free_ uint8_t *buf = NULL;
6e8fb3ad 3929 size_t size = 0, maxsize = sizeof(command) + sizeof(pcr_selection);
dcbc4674
DS
3930
3931 buf = malloc(maxsize);
3932 if (!buf)
f9a0ee75 3933 return log_oom_debug();
dcbc4674
DS
3934
3935 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, maxsize, &size);
3936 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3937 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dcbc4674
DS
3938 "Failed to marshal PolicyPCR command: %s", sym_Tss2_RC_Decode(rc));
3939
6e8fb3ad 3940 rc = sym_Tss2_MU_TPML_PCR_SELECTION_Marshal(&pcr_selection, buf, maxsize, &size);
dcbc4674 3941 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3942 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dcbc4674
DS
3943 "Failed to marshal PCR selection: %s", sym_Tss2_RC_Decode(rc));
3944
3945 struct iovec data[] = {
3946 IOVEC_MAKE(buf, size),
3947 IOVEC_MAKE(hash.buffer, hash.size),
3948 };
3949 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
3950 if (r < 0)
3951 return r;
3952
3953 tpm2_log_debug_digest(digest, "PolicyPCR calculated digest");
3954
3955 return 0;
3956}
3957
8f3f9c2b 3958int tpm2_policy_pcr(
dcbc4674
DS
3959 Tpm2Context *c,
3960 const Tpm2Handle *session,
3961 const TPML_PCR_SELECTION *pcr_selection,
3962 TPM2B_DIGEST **ret_policy_digest) {
3963
3964 TSS2_RC rc;
3965
3966 assert(c);
3967 assert(session);
3968 assert(pcr_selection);
3969
2cd8f753 3970 log_debug("Submitting PCR hash policy.");
dcbc4674
DS
3971
3972 rc = sym_Esys_PolicyPCR(
3973 c->esys_context,
3974 session->esys_handle,
3975 ESYS_TR_NONE,
3976 ESYS_TR_NONE,
3977 ESYS_TR_NONE,
3978 NULL,
3979 pcr_selection);
3980 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3981 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dcbc4674
DS
3982 "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
3983
3984 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3985}
3986
5c7852f7
DS
3987/* Extend 'digest' with the PolicyAuthorize calculated hash. */
3988int tpm2_calculate_policy_authorize(
3989 const TPM2B_PUBLIC *public,
3990 const TPM2B_DIGEST *policy_ref,
3991 TPM2B_DIGEST *digest) {
3992
3993 TPM2_CC command = TPM2_CC_PolicyAuthorize;
3994 TSS2_RC rc;
3995 int r;
3996
3997 assert(public);
3998 assert(digest);
3999 assert(digest->size == SHA256_DIGEST_SIZE);
4000
4001 r = dlopen_tpm2();
4002 if (r < 0)
f9a0ee75 4003 return log_debug_errno(r, "TPM2 support not installed: %m");
5c7852f7
DS
4004
4005 uint8_t buf[sizeof(command)];
4006 size_t offset = 0;
4007
4008 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
4009 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 4010 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
4011 "Failed to marshal PolicyAuthorize command: %s", sym_Tss2_RC_Decode(rc));
4012
4013 if (offset != sizeof(command))
f9a0ee75 4014 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
4015 "Offset 0x%zx wrong after marshalling PolicyAuthorize command", offset);
4016
4017 TPM2B_NAME name = {};
b98c4f1d 4018 r = tpm2_calculate_pubkey_name(&public->publicArea, &name);
5c7852f7
DS
4019 if (r < 0)
4020 return r;
4021
4022 /* PolicyAuthorize does not use the previous hash value; we must zero and then extend it. */
4023 zero(digest->buffer);
4024
4025 struct iovec data[] = {
4026 IOVEC_MAKE(buf, offset),
4027 IOVEC_MAKE(name.name, name.size),
4028 };
4029 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
4030 if (r < 0)
4031 return r;
4032
4033 /* PolicyAuthorize requires hashing twice; this is either an extension or rehashing. */
4034 if (policy_ref)
4035 r = tpm2_digest_many_digests(TPM2_ALG_SHA256, digest, policy_ref, 1, /* extend= */ true);
4036 else
4037 r = tpm2_digest_rehash(TPM2_ALG_SHA256, digest);
4038 if (r < 0)
4039 return r;
4040
4041 tpm2_log_debug_digest(digest, "PolicyAuthorize calculated digest");
4042
4043 return 0;
4044}
4045
4046static int tpm2_policy_authorize(
4047 Tpm2Context *c,
4048 const Tpm2Handle *session,
4049 TPML_PCR_SELECTION *pcr_selection,
4050 const TPM2B_PUBLIC *public,
4051 const void *fp,
4052 size_t fp_size,
4053 JsonVariant *signature_json,
4054 TPM2B_DIGEST **ret_policy_digest) {
4055
4056 TSS2_RC rc;
4057 int r;
4058
4059 assert(c);
4060 assert(session);
4061 assert(pcr_selection);
4062 assert(public);
4063 assert(fp && fp_size > 0);
4064
4065 log_debug("Adding PCR signature policy.");
4066
1dc8f518 4067 _cleanup_(tpm2_handle_freep) Tpm2Handle *pubkey_handle = NULL;
efe153bd 4068 r = tpm2_load_external(c, NULL, public, NULL, &pubkey_handle);
5c7852f7
DS
4069 if (r < 0)
4070 return r;
4071
5c7852f7
DS
4072 /* Acquire the "name" of what we just loaded */
4073 _cleanup_(Esys_Freep) TPM2B_NAME *pubkey_name = NULL;
4074 r = tpm2_get_name(c, pubkey_handle, &pubkey_name);
4075 if (r < 0)
4076 return r;
4077
4078 /* If we have a signature, proceed with verifying the PCR digest */
4079 const TPMT_TK_VERIFIED *check_ticket;
4080 _cleanup_(Esys_Freep) TPMT_TK_VERIFIED *check_ticket_buffer = NULL;
4081 _cleanup_(Esys_Freep) TPM2B_DIGEST *approved_policy = NULL;
4082 if (signature_json) {
4083 r = tpm2_policy_pcr(
4084 c,
4085 session,
4086 pcr_selection,
4087 &approved_policy);
4088 if (r < 0)
4089 return r;
4090
4091 _cleanup_free_ void *signature_raw = NULL;
4092 size_t signature_size;
4093
4094 r = find_signature(
4095 signature_json,
4096 pcr_selection,
4097 fp, fp_size,
4098 approved_policy->buffer,
4099 approved_policy->size,
4100 &signature_raw,
4101 &signature_size);
4102 if (r < 0)
4103 return r;
4104
4105 /* TPM2_VerifySignature() will only verify the RSA part of the RSA+SHA256 signature,
4106 * hence we need to do the SHA256 part ourselves, first */
4107 TPM2B_DIGEST signature_hash = *approved_policy;
4108 r = tpm2_digest_rehash(TPM2_ALG_SHA256, &signature_hash);
4109 if (r < 0)
4110 return r;
4111
53b91e19
DS
4112 r = TPM2B_PUBLIC_KEY_RSA_CHECK_SIZE(signature_size);
4113 if (r < 0)
f9a0ee75 4114 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Signature larger than buffer.");
53b91e19 4115
5c7852f7
DS
4116 TPMT_SIGNATURE policy_signature = {
4117 .sigAlg = TPM2_ALG_RSASSA,
4118 .signature.rsassa = {
4119 .hash = TPM2_ALG_SHA256,
53b91e19 4120 .sig = TPM2B_PUBLIC_KEY_RSA_MAKE(signature_raw, signature_size),
5c7852f7
DS
4121 },
4122 };
5c7852f7
DS
4123
4124 rc = sym_Esys_VerifySignature(
4125 c->esys_context,
4126 pubkey_handle->esys_handle,
4127 ESYS_TR_NONE,
4128 ESYS_TR_NONE,
4129 ESYS_TR_NONE,
4130 &signature_hash,
4131 &policy_signature,
4132 &check_ticket_buffer);
4133 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 4134 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
4135 "Failed to validate signature in TPM: %s", sym_Tss2_RC_Decode(rc));
4136
4137 check_ticket = check_ticket_buffer;
4138 } else {
4139 /* When enrolling, we pass a NULL ticket */
4140 static const TPMT_TK_VERIFIED check_ticket_null = {
4141 .tag = TPM2_ST_VERIFIED,
4142 .hierarchy = TPM2_RH_OWNER,
4143 };
4144
4145 check_ticket = &check_ticket_null;
4146 }
4147
4148 rc = sym_Esys_PolicyAuthorize(
4149 c->esys_context,
4150 session->esys_handle,
4151 ESYS_TR_NONE,
4152 ESYS_TR_NONE,
4153 ESYS_TR_NONE,
4154 approved_policy,
4155 /* policyRef= */ &(const TPM2B_NONCE) {},
4156 pubkey_name,
4157 check_ticket);
4158 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 4159 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
4160 "Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc));
4161
4162 return tpm2_get_policy_digest(c, session, ret_policy_digest);
4163}
4164
d9a1f1a7 4165/* Extend 'digest' with the calculated policy hash. */
9e437994 4166int tpm2_calculate_sealing_policy(
6e8fb3ad
DS
4167 const Tpm2PCRValue *pcr_values,
4168 size_t n_pcr_values,
d9a1f1a7 4169 const TPM2B_PUBLIC *public,
6e8fb3ad 4170 bool use_pin,
a4342701 4171 const Tpm2PCRLockPolicy *pcrlock_policy,
d9a1f1a7
DS
4172 TPM2B_DIGEST *digest) {
4173
4174 int r;
4175
6e8fb3ad 4176 assert(pcr_values || n_pcr_values == 0);
d9a1f1a7
DS
4177 assert(digest);
4178
a4342701
LP
4179 if (public && pcrlock_policy)
4180 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Policies with both signed PCR and pcrlock are currently not supported.");
4181
d9a1f1a7
DS
4182 if (public) {
4183 r = tpm2_calculate_policy_authorize(public, NULL, digest);
4184 if (r < 0)
4185 return r;
4186 }
4187
a4342701
LP
4188 if (pcrlock_policy) {
4189 TPM2B_NV_PUBLIC nv_public;
4190
4191 r = tpm2_unmarshal_nv_public(
4192 pcrlock_policy->nv_public.iov_base,
4193 pcrlock_policy->nv_public.iov_len,
4194 &nv_public);
4195 if (r < 0)
4196 return r;
4197
4198 r = tpm2_calculate_policy_authorize_nv(&nv_public, digest);
4199 if (r < 0)
4200 return r;
4201 }
4202
6e8fb3ad
DS
4203 if (n_pcr_values > 0) {
4204 r = tpm2_calculate_policy_pcr(pcr_values, n_pcr_values, digest);
d9a1f1a7
DS
4205 if (r < 0)
4206 return r;
4207 }
4208
6e8fb3ad 4209 if (use_pin) {
d9a1f1a7
DS
4210 r = tpm2_calculate_policy_auth_value(digest);
4211 if (r < 0)
4212 return r;
4213 }
4214
4215 return 0;
4216}
4217
2cd9d575 4218static int tpm2_build_sealing_policy(
23e9ccc2 4219 Tpm2Context *c,
2cd9d575 4220 const Tpm2Handle *session,
d9b5841d 4221 uint32_t hash_pcr_mask,
2cd9d575 4222 uint16_t pcr_bank,
524cef3f
DS
4223 const TPM2B_PUBLIC *public,
4224 const void *fp,
4225 size_t fp_size,
d9b5841d
LP
4226 uint32_t pubkey_pcr_mask,
4227 JsonVariant *signature_json,
2f5a892a 4228 bool use_pin,
a4342701 4229 const Tpm2PCRLockPolicy *pcrlock_policy,
2cd9d575 4230 TPM2B_DIGEST **ret_policy_digest) {
5e521624 4231
5e521624
LP
4232 int r;
4233
4234 assert(c);
2cd9d575 4235 assert(session);
524cef3f 4236 assert(pubkey_pcr_mask == 0 || public);
5e521624 4237
2cd9d575 4238 log_debug("Building sealing policy.");
251d2ea2 4239
d9b5841d 4240 if ((hash_pcr_mask | pubkey_pcr_mask) != 0) {
2cd9d575
DS
4241 r = tpm2_pcr_mask_good(c, pcr_bank, hash_pcr_mask|pubkey_pcr_mask);
4242 if (r < 0)
4243 return r;
4244 if (r == 0)
f9a0ee75 4245 log_debug("Selected TPM2 PCRs are not initialized on this system.");
d9b5841d 4246 }
321a9d9e 4247
a4342701
LP
4248 if (pubkey_pcr_mask != 0 && pcrlock_policy)
4249 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Policies with both signed PCR and pcrlock are currently not supported.");
4250
d9b5841d 4251 if (pubkey_pcr_mask != 0) {
d9b5841d 4252 TPML_PCR_SELECTION pcr_selection;
c69bd0ab 4253 tpm2_tpml_pcr_selection_from_mask(pubkey_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection);
524cef3f 4254 r = tpm2_policy_authorize(c, session, &pcr_selection, public, fp, fp_size, signature_json, NULL);
23b972d5
DS
4255 if (r < 0)
4256 return r;
d9b5841d
LP
4257 }
4258
a4342701
LP
4259 if (pcrlock_policy) {
4260 _cleanup_(tpm2_handle_freep) Tpm2Handle *nv_handle = NULL;
4261
4262 r = tpm2_policy_super_pcr(
4263 c,
4264 session,
4265 &pcrlock_policy->prediction,
4266 pcrlock_policy->algorithm);
4267 if (r < 0)
4268 return r;
4269
4270 r = tpm2_deserialize(
4271 c,
4272 pcrlock_policy->nv_handle.iov_base,
4273 pcrlock_policy->nv_handle.iov_len,
4274 &nv_handle);
4275 if (r < 0)
4276 return r;
4277
4278 r = tpm2_policy_authorize_nv(
4279 c,
4280 session,
4281 nv_handle,
4282 NULL);
4283 if (r < 0)
4284 return r;
4285 }
4286
d9b5841d 4287 if (hash_pcr_mask != 0) {
d9b5841d 4288 TPML_PCR_SELECTION pcr_selection;
c69bd0ab 4289 tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection);
dcbc4674
DS
4290 r = tpm2_policy_pcr(c, session, &pcr_selection, NULL);
4291 if (r < 0)
4292 return r;
5e521624
LP
4293 }
4294
2f5a892a 4295 if (use_pin) {
8a716354
DS
4296 r = tpm2_policy_auth_value(c, session, NULL);
4297 if (r < 0)
4298 return r;
2f5a892a
GG
4299 }
4300
23b972d5
DS
4301 r = tpm2_get_policy_digest(c, session, ret_policy_digest);
4302 if (r < 0)
4303 return r;
5e521624 4304
16e16b8c 4305 return 0;
5e521624
LP
4306}
4307
e3acb4d2 4308#if HAVE_OPENSSL
6761e135
DS
4309static const struct {
4310 TPM2_ECC_CURVE tpm2_ecc_curve_id;
4311 int openssl_ecc_curve_id;
4312} tpm2_openssl_ecc_curve_table[] = {
4313 { TPM2_ECC_NIST_P192, NID_X9_62_prime192v1, },
4314 { TPM2_ECC_NIST_P224, NID_secp224r1, },
4315 { TPM2_ECC_NIST_P256, NID_X9_62_prime256v1, },
4316 { TPM2_ECC_NIST_P384, NID_secp384r1, },
4317 { TPM2_ECC_NIST_P521, NID_secp521r1, },
4318 { TPM2_ECC_SM2_P256, NID_sm2, },
4319};
4320
4321static int tpm2_ecc_curve_from_openssl_curve_id(int openssl_ecc_curve_id, TPM2_ECC_CURVE *ret) {
e3acb4d2
DS
4322 assert(ret);
4323
85471164 4324 FOREACH_ELEMENT(t, tpm2_openssl_ecc_curve_table)
6761e135
DS
4325 if (t->openssl_ecc_curve_id == openssl_ecc_curve_id) {
4326 *ret = t->tpm2_ecc_curve_id;
4327 return 0;
4328 }
e3acb4d2
DS
4329
4330 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
968d232d 4331 "OpenSSL ECC curve id %d not supported.", openssl_ecc_curve_id);
e3acb4d2
DS
4332}
4333
6761e135 4334static int tpm2_ecc_curve_to_openssl_curve_id(TPM2_ECC_CURVE tpm2_ecc_curve_id, int *ret) {
e3acb4d2
DS
4335 assert(ret);
4336
85471164 4337 FOREACH_ELEMENT(t, tpm2_openssl_ecc_curve_table)
6761e135
DS
4338 if (t->tpm2_ecc_curve_id == tpm2_ecc_curve_id) {
4339 *ret = t->openssl_ecc_curve_id;
4340 return 0;
4341 }
e3acb4d2
DS
4342
4343 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
6761e135 4344 "TPM2 ECC curve %u not supported.", tpm2_ecc_curve_id);
e3acb4d2
DS
4345}
4346
4347#define TPM2_RSA_DEFAULT_EXPONENT UINT32_C(0x10001)
4348
4349int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret) {
4350 int r;
4351
4352 assert(public);
4353 assert(ret);
4354
4355 const TPMT_PUBLIC *p = &public->publicArea;
3f4d5dfd
DS
4356 switch (p->type) {
4357 case TPM2_ALG_ECC: {
e3acb4d2
DS
4358 int curve_id;
4359 r = tpm2_ecc_curve_to_openssl_curve_id(p->parameters.eccDetail.curveID, &curve_id);
4360 if (r < 0)
4361 return r;
4362
4363 const TPMS_ECC_POINT *point = &p->unique.ecc;
4364 return ecc_pkey_from_curve_x_y(
4365 curve_id,
4366 point->x.buffer,
4367 point->x.size,
4368 point->y.buffer,
4369 point->y.size,
4370 ret);
4371 }
3f4d5dfd 4372 case TPM2_ALG_RSA: {
e3acb4d2
DS
4373 /* TPM specification Part 2 ("Structures") section for TPMS_RSA_PARAMS states "An exponent of
4374 * zero indicates that the exponent is the default of 2^16 + 1". */
4375 uint32_t exponent = htobe32(p->parameters.rsaDetail.exponent ?: TPM2_RSA_DEFAULT_EXPONENT);
4376 return rsa_pkey_from_n_e(
4377 p->unique.rsa.buffer,
4378 p->unique.rsa.size,
4379 &exponent,
4380 sizeof(exponent),
4381 ret);
4382 }
3f4d5dfd
DS
4383 default:
4384 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
4385 "TPM2 asymmetric algorithm 0x%" PRIx16 " not supported.", p->type);
4386 }
e3acb4d2
DS
4387}
4388
1242b9ab
DS
4389/* Be careful before changing anything in this function, as the TPM key "name" is calculated using the entire
4390 * TPMT_PUBLIC (after marshalling), and that "name" is used (for example) to calculate the policy hash for
4391 * the Authorize policy. So we must ensure this conversion of a PEM to TPM2B_PUBLIC does not change the
4392 * "name", because it would break unsealing of previously-sealed objects that used (for example)
4393 * tpm2_calculate_policy_authorize(). See bug #30546. */
e3acb4d2
DS
4394int tpm2_tpm2b_public_from_openssl_pkey(const EVP_PKEY *pkey, TPM2B_PUBLIC *ret) {
4395 int key_id, r;
4396
4397 assert(pkey);
4398 assert(ret);
4399
4400 TPMT_PUBLIC public = {
4401 .nameAlg = TPM2_ALG_SHA256,
4402 .objectAttributes = TPMA_OBJECT_DECRYPT | TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_USERWITHAUTH,
4403 .parameters.asymDetail = {
4404 .symmetric.algorithm = TPM2_ALG_NULL,
4405 .scheme.scheme = TPM2_ALG_NULL,
4406 },
4407 };
4408
4409#if OPENSSL_VERSION_MAJOR >= 3
4410 key_id = EVP_PKEY_get_id(pkey);
4411#else
4412 key_id = EVP_PKEY_id(pkey);
4413#endif
4414
3f4d5dfd
DS
4415 switch (key_id) {
4416 case EVP_PKEY_EC: {
e3acb4d2
DS
4417 public.type = TPM2_ALG_ECC;
4418
4419 int curve_id;
4420 _cleanup_free_ void *x = NULL, *y = NULL;
4421 size_t x_size, y_size;
4422 r = ecc_pkey_to_curve_x_y(pkey, &curve_id, &x, &x_size, &y, &y_size);
4423 if (r < 0)
ed35ac31 4424 return log_debug_errno(r, "Could not get ECC key curve/x/y: %m");
e3acb4d2
DS
4425
4426 TPM2_ECC_CURVE curve;
4427 r = tpm2_ecc_curve_from_openssl_curve_id(curve_id, &curve);
4428 if (r < 0)
4429 return r;
4430
4431 public.parameters.eccDetail.curveID = curve;
4432
4433 public.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
4434
4435 r = TPM2B_ECC_PARAMETER_CHECK_SIZE(x_size);
4436 if (r < 0)
ed35ac31 4437 return log_debug_errno(r, "ECC key x size %zu too large.", x_size);
e3acb4d2
DS
4438
4439 public.unique.ecc.x = TPM2B_ECC_PARAMETER_MAKE(x, x_size);
4440
4441 r = TPM2B_ECC_PARAMETER_CHECK_SIZE(y_size);
4442 if (r < 0)
ed35ac31 4443 return log_debug_errno(r, "ECC key y size %zu too large.", y_size);
e3acb4d2
DS
4444
4445 public.unique.ecc.y = TPM2B_ECC_PARAMETER_MAKE(y, y_size);
3f4d5dfd
DS
4446
4447 break;
4448 }
4449 case EVP_PKEY_RSA: {
e3acb4d2
DS
4450 public.type = TPM2_ALG_RSA;
4451
4452 _cleanup_free_ void *n = NULL, *e = NULL;
4453 size_t n_size, e_size;
4454 r = rsa_pkey_to_n_e(pkey, &n, &n_size, &e, &e_size);
4455 if (r < 0)
ed35ac31 4456 return log_debug_errno(r, "Could not get RSA key n/e: %m");
e3acb4d2
DS
4457
4458 r = TPM2B_PUBLIC_KEY_RSA_CHECK_SIZE(n_size);
4459 if (r < 0)
ed35ac31 4460 return log_debug_errno(r, "RSA key n size %zu too large.", n_size);
e3acb4d2
DS
4461
4462 public.unique.rsa = TPM2B_PUBLIC_KEY_RSA_MAKE(n, n_size);
4463 public.parameters.rsaDetail.keyBits = n_size * 8;
4464
4465 if (sizeof(uint32_t) < e_size)
ed35ac31 4466 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
e3acb4d2
DS
4467 "RSA key e size %zu too large.", e_size);
4468
4469 uint32_t exponent = 0;
70cb382d 4470 memcpy(&exponent, e, e_size);
e3acb4d2 4471 exponent = be32toh(exponent) >> (32 - e_size * 8);
1242b9ab
DS
4472
4473 /* TPM specification Part 2 ("Structures") section for TPMS_RSA_PARAMS states "An exponent of
4474 * zero indicates that the exponent is the default of 2^16 + 1". However, we have no reason
4475 * to special case it in our PEM->TPM2B_PUBLIC conversion, and doing so could break backwards
4476 * compatibility, so even if it is the "default" value of 0x10001, we do not set it to 0. */
e3acb4d2 4477 public.parameters.rsaDetail.exponent = exponent;
3f4d5dfd
DS
4478
4479 break;
4480 }
4481 default:
e3acb4d2
DS
4482 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
4483 "EVP_PKEY type %d not supported.", key_id);
3f4d5dfd 4484 }
e3acb4d2
DS
4485
4486 *ret = (TPM2B_PUBLIC) {
4487 .size = sizeof(public),
4488 .publicArea = public,
4489 };
4490
4491 return 0;
4492}
4493#endif
4494
4495int tpm2_tpm2b_public_to_fingerprint(
4496 const TPM2B_PUBLIC *public,
4497 void **ret_fingerprint,
4498 size_t *ret_fingerprint_size) {
4499
4500#if HAVE_OPENSSL
4501 int r;
4502
4503 assert(public);
4504 assert(ret_fingerprint);
4505 assert(ret_fingerprint_size);
4506
4507 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
4508 r = tpm2_tpm2b_public_to_openssl_pkey(public, &pkey);
4509 if (r < 0)
4510 return r;
4511
4512 /* Hardcode fingerprint to SHA256 */
4513 return pubkey_fingerprint(pkey, EVP_sha256(), ret_fingerprint, ret_fingerprint_size);
4514#else
f9a0ee75 4515 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
e3acb4d2
DS
4516#endif
4517}
4518
4519int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret) {
4520#if HAVE_OPENSSL
4521 int r;
4522
4523 assert(pem);
4524 assert(ret);
4525
4526 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
4527 r = openssl_pkey_from_pem(pem, pem_size, &pkey);
4528 if (r < 0)
4529 return r;
4530
4531 return tpm2_tpm2b_public_from_openssl_pkey(pkey, ret);
4532#else
f9a0ee75 4533 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
e3acb4d2
DS
4534#endif
4535}
4536
0a7874ad
DS
4537/* Marshal the public, private, and seed objects into a single nonstandard 'blob'. The public and private
4538 * objects are required, while the seed is optional. This is not a (publicly) standard format, this is
4539 * specific to how we currently store the sealed object. This 'blob' can be unmarshalled by
653c3fe9 4540 * tpm2_unmarshal_blob(). */
65883f6c 4541int tpm2_marshal_blob(
653c3fe9
DS
4542 const TPM2B_PUBLIC *public,
4543 const TPM2B_PRIVATE *private,
0a7874ad 4544 const TPM2B_ENCRYPTED_SECRET *seed,
653c3fe9
DS
4545 void **ret_blob,
4546 size_t *ret_blob_size) {
4547
4548 TSS2_RC rc;
4549
4550 assert(public);
4551 assert(private);
4552 assert(ret_blob);
4553 assert(ret_blob_size);
4554
4555 size_t max_size = sizeof(*private) + sizeof(*public);
0a7874ad
DS
4556 if (seed)
4557 max_size += sizeof(*seed);
653c3fe9
DS
4558
4559 _cleanup_free_ void *blob = malloc(max_size);
4560 if (!blob)
4561 return log_oom_debug();
4562
4563 size_t blob_size = 0;
4564 rc = sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, blob, max_size, &blob_size);
4565 if (rc != TSS2_RC_SUCCESS)
4566 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4567 "Failed to marshal private key: %s", sym_Tss2_RC_Decode(rc));
4568
4569 rc = sym_Tss2_MU_TPM2B_PUBLIC_Marshal(public, blob, max_size, &blob_size);
4570 if (rc != TSS2_RC_SUCCESS)
4571 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4572 "Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
4573
0a7874ad
DS
4574 if (seed) {
4575 rc = sym_Tss2_MU_TPM2B_ENCRYPTED_SECRET_Marshal(seed, blob, max_size, &blob_size);
4576 if (rc != TSS2_RC_SUCCESS)
4577 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4578 "Failed to marshal encrypted seed: %s", sym_Tss2_RC_Decode(rc));
4579 }
4580
653c3fe9
DS
4581 *ret_blob = TAKE_PTR(blob);
4582 *ret_blob_size = blob_size;
4583
4584 return 0;
4585}
4586
0a7874ad
DS
4587/* Unmarshal the 'blob' into public, private, and seed objects. The public and private objects are required
4588 * in the 'blob', while the seed is optional. This is not a (publicly) standard format, this is specific to
4589 * how we currently store the sealed object. This expects the 'blob' to have been created by
653c3fe9 4590 * tpm2_marshal_blob(). */
65883f6c 4591int tpm2_unmarshal_blob(
653c3fe9
DS
4592 const void *blob,
4593 size_t blob_size,
4594 TPM2B_PUBLIC *ret_public,
0a7874ad
DS
4595 TPM2B_PRIVATE *ret_private,
4596 TPM2B_ENCRYPTED_SECRET *ret_seed) {
653c3fe9
DS
4597
4598 TSS2_RC rc;
4599
4600 assert(blob);
4601 assert(ret_public);
4602 assert(ret_private);
0a7874ad 4603 assert(ret_seed);
653c3fe9
DS
4604
4605 TPM2B_PRIVATE private = {};
4606 size_t offset = 0;
4607 rc = sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal(blob, blob_size, &offset, &private);
4608 if (rc != TSS2_RC_SUCCESS)
4609 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4610 "Failed to unmarshal private key: %s", sym_Tss2_RC_Decode(rc));
4611
4612 TPM2B_PUBLIC public = {};
4613 rc = sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal(blob, blob_size, &offset, &public);
4614 if (rc != TSS2_RC_SUCCESS)
4615 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4616 "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc));
4617
0a7874ad
DS
4618 TPM2B_ENCRYPTED_SECRET seed = {};
4619 if (blob_size > offset) {
4620 rc = sym_Tss2_MU_TPM2B_ENCRYPTED_SECRET_Unmarshal(blob, blob_size, &offset, &seed);
4621 if (rc != TSS2_RC_SUCCESS)
4622 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4623 "Failed to unmarshal encrypted seed: %s", sym_Tss2_RC_Decode(rc));
4624 }
4625
653c3fe9
DS
4626 *ret_public = public;
4627 *ret_private = private;
0a7874ad
DS
4628 *ret_seed = seed;
4629
4630 return 0;
4631}
4632
4633/* Calculate a serialized handle. Once the upstream tpm2-tss library provides an api to do this, we can
4634 * remove this function. The addition of this functionality in tpm2-tss may be tracked here:
4635 * https://github.com/tpm2-software/tpm2-tss/issues/2575 */
4636int tpm2_calculate_serialize(
4637 TPM2_HANDLE handle,
4638 const TPM2B_NAME *name,
4639 const TPM2B_PUBLIC *public,
4640 void **ret_serialized,
4641 size_t *ret_serialized_size) {
4642
4643 TSS2_RC rc;
4644
4645 assert(name);
4646 assert(public);
4647 assert(ret_serialized);
4648 assert(ret_serialized_size);
4649
4650 size_t max_size = sizeof(TPM2_HANDLE) + sizeof(TPM2B_NAME) + sizeof(uint32_t) + sizeof(TPM2B_PUBLIC);
4651 _cleanup_free_ void *serialized = malloc(max_size);
4652 if (!serialized)
4653 return log_oom_debug();
4654
4655 size_t serialized_size = 0;
4656 rc = sym_Tss2_MU_TPM2_HANDLE_Marshal(handle, serialized, max_size, &serialized_size);
4657 if (rc != TSS2_RC_SUCCESS)
4658 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4659 "Failed to marshal tpm handle: %s", sym_Tss2_RC_Decode(rc));
4660
4661 rc = sym_Tss2_MU_TPM2B_NAME_Marshal(name, serialized, max_size, &serialized_size);
4662 if (rc != TSS2_RC_SUCCESS)
4663 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4664 "Failed to marshal name: %s", sym_Tss2_RC_Decode(rc));
4665
4666 /* This is defined (non-publicly) in the tpm2-tss source as IESYSC_KEY_RSRC, to a value of "1". */
4667 rc = sym_Tss2_MU_UINT32_Marshal(UINT32_C(1), serialized, max_size, &serialized_size);
4668 if (rc != TSS2_RC_SUCCESS)
4669 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4670 "Failed to marshal esys resource id: %s", sym_Tss2_RC_Decode(rc));
4671
4672 rc = sym_Tss2_MU_TPM2B_PUBLIC_Marshal(public, serialized, max_size, &serialized_size);
4673 if (rc != TSS2_RC_SUCCESS)
4674 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4675 "Failed to marshal public: %s", sym_Tss2_RC_Decode(rc));
4676
4677 *ret_serialized = TAKE_PTR(serialized);
4678 *ret_serialized_size = serialized_size;
653c3fe9
DS
4679
4680 return 0;
4681}
4682
1eff4242
DS
4683/* Serialize a handle. This produces a binary object that can be later deserialized (by the same TPM), even
4684 * across restarts of the TPM or reboots (assuming the handle is persistent). */
8f3f9c2b 4685int tpm2_serialize(
1eff4242
DS
4686 Tpm2Context *c,
4687 const Tpm2Handle *handle,
4688 void **ret_serialized,
4689 size_t *ret_serialized_size) {
4690
4691 TSS2_RC rc;
4692
4693 assert(c);
4694 assert(handle);
4695 assert(ret_serialized);
4696 assert(ret_serialized_size);
4697
4698 _cleanup_(Esys_Freep) unsigned char *serialized = NULL;
4699 size_t size = 0;
4700 rc = sym_Esys_TR_Serialize(c->esys_context, handle->esys_handle, &serialized, &size);
4701 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 4702 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1eff4242
DS
4703 "Failed to serialize: %s", sym_Tss2_RC_Decode(rc));
4704
4705 *ret_serialized = TAKE_PTR(serialized);
4706 *ret_serialized_size = size;
4707
4708 return 0;
4709}
4710
8f3f9c2b 4711int tpm2_deserialize(
1eff4242
DS
4712 Tpm2Context *c,
4713 const void *serialized,
4714 size_t serialized_size,
4715 Tpm2Handle **ret_handle) {
4716
4717 TSS2_RC rc;
4718 int r;
4719
4720 assert(c);
4721 assert(serialized);
4722 assert(ret_handle);
4723
4724 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
4725 r = tpm2_handle_new(c, &handle);
4726 if (r < 0)
4727 return r;
4728
4729 /* Since this is an existing handle in the TPM we should not implicitly flush it. */
4730 handle->flush = false;
4731
4732 rc = sym_Esys_TR_Deserialize(c->esys_context, serialized, serialized_size, &handle->esys_handle);
4733 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 4734 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1eff4242
DS
4735 "Failed to deserialize: %s", sym_Tss2_RC_Decode(rc));
4736
4737 *ret_handle = TAKE_PTR(handle);
4738
4739 return 0;
4740}
4741
0a7874ad
DS
4742#if HAVE_OPENSSL
4743
4744/* KDFa() as defined by the TPM spec. */
4745static int tpm2_kdfa(
4746 TPMI_ALG_HASH hash_alg,
4747 const void *key,
4748 size_t key_len,
4749 const char *label,
4750 const void *context,
4751 size_t context_len,
4752 size_t bits,
4753 void **ret_key,
4754 size_t *ret_key_len) {
4755
4756 int r;
4757
4758 assert(key);
4759 assert(label);
4760 assert(context || context_len == 0);
4761 assert(bits > 0);
4762 assert(bits <= SIZE_MAX - 7);
4763 assert(ret_key);
4764 assert(ret_key_len);
4765
4766 log_debug("Calculating KDFa().");
4767
4768 size_t len = DIV_ROUND_UP(bits, 8);
4769
4770 const char *hash_alg_name = tpm2_hash_alg_to_string(hash_alg);
4771 if (!hash_alg_name)
4772 return -EOPNOTSUPP;
4773
4774 _cleanup_free_ void *buf = NULL;
4775 r = kdf_kb_hmac_derive(
4776 "COUNTER",
4777 hash_alg_name,
4778 key,
4779 key_len,
4780 label,
4781 strlen(label),
4782 context,
4783 context_len,
4784 /* seed= */ NULL,
4785 /* seed_len= */ 0,
4786 len,
4787 &buf);
4788 if (r < 0)
4789 return r;
4790
4791 /* If the number of bits results in a partial byte, the TPM spec requires we zero the unrequested
4792 * bits in the MSB (i.e. at index 0). From the spec Part 1 ("Architecture") section on Key
4793 * Derivation Function, specifically KDFa():
4794 *
4795 * "The implied return from this function is a sequence of octets with a length equal to (bits + 7) /
4796 * 8. If bits is not an even multiple of 8, then the returned value occupies the least significant
4797 * bits of the returned octet array, and the additional, high-order bits in the 0th octet are
4798 * CLEAR. The unused bits of the most significant octet (MSO) are masked off and not shifted." */
4799 size_t partial = bits % 8;
4800 if (partial > 0)
4801 ((uint8_t*) buf)[0] &= 0xffu >> (8 - partial);
4802
4803 *ret_key = TAKE_PTR(buf);
4804 *ret_key_len = len;
4805
4806 return 0;
4807}
4808
4809/* KDFe() as defined by the TPM spec. */
4810static int tpm2_kdfe(
4811 TPMI_ALG_HASH hash_alg,
4812 const void *shared_secret,
4813 size_t shared_secret_len,
4814 const char *label,
4815 const void *context_u,
4816 size_t context_u_size,
4817 const void *context_v,
4818 size_t context_v_size,
4819 size_t bits,
4820 void **ret_key,
4821 size_t *ret_key_len) {
4822
4823 int r;
4824
4825 assert(shared_secret);
4826 assert(label);
4827 assert(context_u);
4828 assert(context_v);
4829 assert(bits > 0);
4830 assert(bits <= SIZE_MAX - 7);
4831 assert(ret_key);
4832 assert(ret_key_len);
4833
4834 log_debug("Calculating KDFe().");
4835
4836 size_t len = DIV_ROUND_UP(bits, 8);
4837
4838 const char *hash_alg_name = tpm2_hash_alg_to_string(hash_alg);
4839 if (!hash_alg_name)
4840 return -EOPNOTSUPP;
4841
4842 size_t info_len = strlen(label) + 1 + context_u_size + context_v_size;
4843 _cleanup_free_ void *info = malloc(info_len);
4844 if (!info)
4845 return log_oom_debug();
4846
4847 void *end = mempcpy(mempcpy(stpcpy(info, label) + 1, context_u, context_u_size), context_v, context_v_size);
4848 /* assert we copied exactly the right amount that we allocated */
4849 assert(end > info && (uintptr_t) end - (uintptr_t) info == info_len);
4850
4851 _cleanup_free_ void *buf = NULL;
4852 r = kdf_ss_derive(
4853 hash_alg_name,
4854 shared_secret,
4855 shared_secret_len,
4856 /* salt= */ NULL,
4857 /* salt_size= */ 0,
4858 info,
4859 info_len,
4860 len,
4861 &buf);
4862 if (r < 0)
4863 return r;
4864
4865 *ret_key = TAKE_PTR(buf);
4866 *ret_key_len = len;
4867
4868 return 0;
4869}
4870
4871static int tpm2_calculate_seal_public(
4872 const TPM2B_PUBLIC *parent,
4873 const TPMA_OBJECT *attributes,
4874 const TPM2B_DIGEST *policy,
4875 const TPM2B_DIGEST *seed,
4876 const void *secret,
4877 size_t secret_size,
4878 TPM2B_PUBLIC *ret) {
4879
4880 int r;
4881
4882 assert(parent);
4883 assert(seed);
4884 assert(secret);
4885 assert(ret);
4886
4887 log_debug("Calculating public part of sealed object.");
4888
4889 struct iovec data[] = {
4890 IOVEC_MAKE((void*) seed->buffer, seed->size),
4891 IOVEC_MAKE((void*) secret, secret_size),
4892 };
4893 TPM2B_DIGEST unique;
4894 r = tpm2_digest_many(
4895 parent->publicArea.nameAlg,
4896 &unique,
4897 data,
4898 ELEMENTSOF(data),
4899 /* extend= */ false);
4900 if (r < 0)
4901 return r;
4902
4903 *ret = (TPM2B_PUBLIC) {
4904 .size = sizeof(TPMT_PUBLIC),
4905 .publicArea = {
4906 .type = TPM2_ALG_KEYEDHASH,
4907 .nameAlg = parent->publicArea.nameAlg,
4908 .objectAttributes = attributes ? *attributes : 0,
4909 .authPolicy = policy ? *policy : TPM2B_DIGEST_MAKE(NULL, unique.size),
4910 .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
4911 .unique.keyedHash = unique,
4912 },
4913 };
4914
4915 return 0;
4916}
4917
4918static int tpm2_calculate_seal_private(
4919 const TPM2B_PUBLIC *parent,
4920 const TPM2B_NAME *name,
4921 const char *pin,
4922 const TPM2B_DIGEST *seed,
4923 const void *secret,
4924 size_t secret_size,
4925 TPM2B_PRIVATE *ret) {
4926
4927 TSS2_RC rc;
4928 int r;
4929
4930 assert(parent);
4931 assert(name);
4932 assert(seed);
4933 assert(secret);
4934 assert(ret);
4935
4936 log_debug("Calculating private part of sealed object.");
4937
4938 _cleanup_free_ void *storage_key = NULL;
4939 size_t storage_key_size;
4940 r = tpm2_kdfa(parent->publicArea.nameAlg,
4941 seed->buffer,
4942 seed->size,
4943 "STORAGE",
4944 name->name,
4945 name->size,
4946 (size_t) parent->publicArea.parameters.asymDetail.symmetric.keyBits.sym,
4947 &storage_key,
4948 &storage_key_size);
4949 if (r < 0)
4950 return log_debug_errno(r, "Could not calculate storage key KDFa: %m");
4951
4952 r = tpm2_hash_alg_to_size(parent->publicArea.nameAlg);
4953 if (r < 0)
4954 return -EOPNOTSUPP;
4955
4956 size_t bits = (size_t) r * 8;
4957
4958 _cleanup_free_ void *integrity_key = NULL;
4959 size_t integrity_key_size;
4960 r = tpm2_kdfa(parent->publicArea.nameAlg,
4961 seed->buffer,
4962 seed->size,
4963 "INTEGRITY",
4964 /* context= */ NULL,
4965 /* n_context= */ 0,
4966 bits,
4967 &integrity_key,
4968 &integrity_key_size);
4969 if (r < 0)
4970 return log_debug_errno(r, "Could not calculate integrity key KDFa: %m");
4971
4972 TPM2B_AUTH auth = {};
4973 if (pin) {
d0f8da98 4974 r = tpm2_auth_value_from_pin(parent->publicArea.nameAlg, pin, &auth);
0a7874ad
DS
4975 if (r < 0)
4976 return r;
4977 }
4978
4979 TPM2B_SENSITIVE sensitive = {
4980 .size = sizeof(TPMT_SENSITIVE),
4981 .sensitiveArea = {
4982 .sensitiveType = TPM2_ALG_KEYEDHASH,
4983 .authValue = auth,
4984 .seedValue = *seed,
4985 .sensitive.bits = TPM2B_SENSITIVE_DATA_MAKE(secret, secret_size),
4986 },
4987 };
4988
4989 _cleanup_free_ void *marshalled_sensitive = malloc(sizeof(sensitive));
4990 if (!marshalled_sensitive)
4991 return log_oom_debug();
4992
4993 size_t marshalled_sensitive_size = 0;
4994 rc = sym_Tss2_MU_TPM2B_SENSITIVE_Marshal(
4995 &sensitive,
4996 marshalled_sensitive,
4997 sizeof(sensitive),
4998 &marshalled_sensitive_size);
4999 if (rc != TSS2_RC_SUCCESS)
5000 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5001 "Failed to marshal sensitive: %s", sym_Tss2_RC_Decode(rc));
5002
5003 const char *sym_alg = tpm2_sym_alg_to_string(parent->publicArea.parameters.asymDetail.symmetric.algorithm);
5004 if (!sym_alg)
5005 return -EOPNOTSUPP;
5006
5007 const char *sym_mode = tpm2_sym_mode_to_string(parent->publicArea.parameters.asymDetail.symmetric.mode.sym);
5008 if (!sym_mode)
5009 return -EOPNOTSUPP;
5010
5011 _cleanup_free_ void *encrypted_sensitive = NULL;
5012 size_t encrypted_sensitive_size;
5013 r = openssl_cipher(
5014 sym_alg,
5015 parent->publicArea.parameters.asymDetail.symmetric.keyBits.sym,
5016 sym_mode,
5017 storage_key, storage_key_size,
5018 /* iv= */ NULL, /* n_iv= */ 0,
5019 marshalled_sensitive, marshalled_sensitive_size,
5020 &encrypted_sensitive, &encrypted_sensitive_size);
5021 if (r < 0)
5022 return r;
5023
5024 const char *hash_alg_name = tpm2_hash_alg_to_string(parent->publicArea.nameAlg);
5025 if (!hash_alg_name)
5026 return -EOPNOTSUPP;
5027
5028 _cleanup_free_ void *hmac_buffer = NULL;
5029 size_t hmac_size = 0;
5030 struct iovec hmac_data[] = {
5031 IOVEC_MAKE((void*) encrypted_sensitive, encrypted_sensitive_size),
5032 IOVEC_MAKE((void*) name->name, name->size),
5033 };
5034 r = openssl_hmac_many(
5035 hash_alg_name,
5036 integrity_key,
5037 integrity_key_size,
5038 hmac_data,
5039 ELEMENTSOF(hmac_data),
5040 &hmac_buffer,
5041 &hmac_size);
5042 if (r < 0)
5043 return r;
5044
5045 TPM2B_DIGEST outer_hmac = TPM2B_DIGEST_MAKE(hmac_buffer, hmac_size);
5046
5047 TPM2B_PRIVATE private = {};
5048 size_t private_size = 0;
5049 rc = sym_Tss2_MU_TPM2B_DIGEST_Marshal(
5050 &outer_hmac,
5051 private.buffer,
5052 sizeof(private.buffer),
5053 &private_size);
5054 if (rc != TSS2_RC_SUCCESS)
5055 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5056 "Failed to marshal digest: %s", sym_Tss2_RC_Decode(rc));
5057 private.size = private_size;
5058
5059 assert(sizeof(private.buffer) - private.size >= encrypted_sensitive_size);
5060 memcpy_safe(&private.buffer[private.size], encrypted_sensitive, encrypted_sensitive_size);
5061 private.size += encrypted_sensitive_size;
5062
5063 *ret = private;
5064
5065 return 0;
5066}
5067
5068static int tpm2_calculate_seal_rsa_seed(
5069 const TPM2B_PUBLIC *parent,
5070 void **ret_seed,
5071 size_t *ret_seed_size,
5072 void **ret_encrypted_seed,
5073 size_t *ret_encrypted_seed_size) {
5074
5075 int r;
5076
5077 assert(parent);
5078 assert(ret_seed);
5079 assert(ret_seed_size);
5080 assert(ret_encrypted_seed);
5081 assert(ret_encrypted_seed_size);
5082
5083 log_debug("Calculating encrypted seed for RSA sealed object.");
5084
5085 _cleanup_(EVP_PKEY_freep) EVP_PKEY *parent_pkey = NULL;
5086 r = tpm2_tpm2b_public_to_openssl_pkey(parent, &parent_pkey);
5087 if (r < 0)
968d232d 5088 return log_debug_errno(r, "Could not convert TPM2B_PUBLIC to OpenSSL PKEY: %m");
0a7874ad
DS
5089
5090 r = tpm2_hash_alg_to_size(parent->publicArea.nameAlg);
5091 if (r < 0)
5092 return -EOPNOTSUPP;
5093
5094 size_t seed_size = (size_t) r;
5095
5096 _cleanup_free_ void *seed = malloc(seed_size);
5097 if (!seed)
5098 return log_oom_debug();
5099
5100 r = crypto_random_bytes(seed, seed_size);
5101 if (r < 0)
5102 return log_debug_errno(r, "Failed to generate random seed: %m");
5103
5104 const char *hash_alg_name = tpm2_hash_alg_to_string(parent->publicArea.nameAlg);
5105 if (!hash_alg_name)
5106 return -EOPNOTSUPP;
5107
5108 _cleanup_free_ void *encrypted_seed = NULL;
5109 size_t encrypted_seed_size;
5110 r = rsa_oaep_encrypt_bytes(
5111 parent_pkey,
5112 hash_alg_name,
5113 "DUPLICATE",
5114 seed,
5115 seed_size,
5116 &encrypted_seed,
5117 &encrypted_seed_size);
5118 if (r < 0)
5119 return log_debug_errno(r, "Could not RSA-OAEP encrypt random seed: %m");
5120
5121 *ret_seed = TAKE_PTR(seed);
5122 *ret_seed_size = seed_size;
5123 *ret_encrypted_seed = TAKE_PTR(encrypted_seed);
5124 *ret_encrypted_seed_size = encrypted_seed_size;
5125
5126 return 0;
5127}
5128
5129static int tpm2_calculate_seal_ecc_seed(
5130 const TPM2B_PUBLIC *parent,
5131 void **ret_seed,
5132 size_t *ret_seed_size,
5133 void **ret_encrypted_seed,
5134 size_t *ret_encrypted_seed_size) {
5135
5136 TSS2_RC rc;
5137 int r;
5138
5139 assert(parent);
5140 assert(ret_seed);
5141 assert(ret_seed_size);
5142 assert(ret_encrypted_seed);
5143 assert(ret_encrypted_seed_size);
5144
5145 log_debug("Calculating encrypted seed for ECC sealed object.");
5146
5147 _cleanup_(EVP_PKEY_freep) EVP_PKEY *parent_pkey = NULL;
5148 r = tpm2_tpm2b_public_to_openssl_pkey(parent, &parent_pkey);
5149 if (r < 0)
968d232d 5150 return log_debug_errno(r, "Could not convert TPM2B_PUBLIC to OpenSSL PKEY: %m");
0a7874ad
DS
5151
5152 int curve_id;
5153 r = ecc_pkey_to_curve_x_y(
5154 parent_pkey,
5155 &curve_id,
5156 /* ret_x= */ NULL, /* ret_x_size= */ 0,
5157 /* ret_y= */ NULL, /* ret_y_size= */ 0);
5158 if (r < 0)
5159 return r;
5160
5161 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
5162 r = ecc_pkey_new(curve_id, &pkey);
5163 if (r < 0)
5164 return r;
5165
5166 _cleanup_free_ void *shared_secret = NULL;
5167 size_t shared_secret_size;
5168 r = ecc_ecdh(pkey, parent_pkey, &shared_secret, &shared_secret_size);
5169 if (r < 0)
5170 return log_debug_errno(r, "Could not generate ECC shared secret: %m");
5171
5172 _cleanup_free_ void *x = NULL, *y = NULL;
5173 size_t x_size, y_size;
5174 r = ecc_pkey_to_curve_x_y(pkey, /* curve_id= */ NULL, &x, &x_size, &y, &y_size);
5175 if (r < 0)
5176 return log_debug_errno(r, "Could not get ECC get x/y: %m");
5177
5178 r = TPM2B_ECC_PARAMETER_CHECK_SIZE(x_size);
5179 if (r < 0)
5180 return log_debug_errno(r, "ECC point x size %zu is too large: %m", x_size);
5181
5182 r = TPM2B_ECC_PARAMETER_CHECK_SIZE(y_size);
5183 if (r < 0)
5184 return log_debug_errno(r, "ECC point y size %zu is too large: %m", y_size);
5185
5186 TPMS_ECC_POINT point = {
5187 .x = TPM2B_ECC_PARAMETER_MAKE(x, x_size),
5188 .y = TPM2B_ECC_PARAMETER_MAKE(y, y_size),
5189 };
5190
5191 _cleanup_free_ void *encrypted_seed = malloc(sizeof(point));
5192 if (!encrypted_seed)
5193 return log_oom_debug();
5194
5195 size_t encrypted_seed_size = 0;
5196 rc = sym_Tss2_MU_TPMS_ECC_POINT_Marshal(&point, encrypted_seed, sizeof(point), &encrypted_seed_size);
5197 if (rc != TPM2_RC_SUCCESS)
5198 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5199 "Failed to marshal ECC point: %s", sym_Tss2_RC_Decode(rc));
5200
5201 r = tpm2_hash_alg_to_size(parent->publicArea.nameAlg);
5202 if (r < 0)
5203 return -EOPNOTSUPP;
5204
5205 size_t bits = (size_t) r * 8;
5206
5207 _cleanup_free_ void *seed = NULL;
0a87b834 5208 size_t seed_size = 0; /* Explicit initialization to appease gcc */
0a7874ad
DS
5209 r = tpm2_kdfe(parent->publicArea.nameAlg,
5210 shared_secret,
5211 shared_secret_size,
5212 "DUPLICATE",
5213 x,
5214 x_size,
5215 parent->publicArea.unique.ecc.x.buffer,
5216 parent->publicArea.unique.ecc.x.size,
5217 bits,
5218 &seed,
5219 &seed_size);
5220 if (r < 0)
5221 return log_debug_errno(r, "Could not calculate KDFe: %m");
5222
5223 *ret_seed = TAKE_PTR(seed);
5224 *ret_seed_size = seed_size;
5225 *ret_encrypted_seed = TAKE_PTR(encrypted_seed);
5226 *ret_encrypted_seed_size = encrypted_seed_size;
5227
5228 return 0;
5229}
5230
5231static int tpm2_calculate_seal_seed(
5232 const TPM2B_PUBLIC *parent,
5233 TPM2B_DIGEST *ret_seed,
5234 TPM2B_ENCRYPTED_SECRET *ret_encrypted_seed) {
5235
5236 int r;
5237
5238 assert(parent);
5239 assert(ret_seed);
5240 assert(ret_encrypted_seed);
5241
5242 log_debug("Calculating encrypted seed for sealed object.");
5243
5244 _cleanup_free_ void *seed = NULL, *encrypted_seed = NULL;
0a87b834 5245 size_t seed_size = 0, encrypted_seed_size = 0; /* Explicit initialization to appease gcc */
0a7874ad
DS
5246 if (parent->publicArea.type == TPM2_ALG_RSA)
5247 r = tpm2_calculate_seal_rsa_seed(parent, &seed, &seed_size, &encrypted_seed, &encrypted_seed_size);
5248 else if (parent->publicArea.type == TPM2_ALG_ECC)
5249 r = tpm2_calculate_seal_ecc_seed(parent, &seed, &seed_size, &encrypted_seed, &encrypted_seed_size);
5250 else
5251 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
5252 "Unsupported parent key type 0x%" PRIx16, parent->publicArea.type);
5253 if (r < 0)
5254 return log_debug_errno(r, "Could not calculate encrypted seed: %m");
5255
5256 *ret_seed = TPM2B_DIGEST_MAKE(seed, seed_size);
5257 *ret_encrypted_seed = TPM2B_ENCRYPTED_SECRET_MAKE(encrypted_seed, encrypted_seed_size);
5258
5259 return 0;
5260}
5261
5262#endif /* HAVE_OPENSSL */
5263
5264int tpm2_calculate_seal(
5265 TPM2_HANDLE parent_handle,
5266 const TPM2B_PUBLIC *parent_public,
5267 const TPMA_OBJECT *attributes,
8d042bc4 5268 const struct iovec *secret,
0a7874ad
DS
5269 const TPM2B_DIGEST *policy,
5270 const char *pin,
8d042bc4
LP
5271 struct iovec *ret_secret,
5272 struct iovec *ret_blob,
5273 struct iovec *ret_serialized_parent) {
0a7874ad
DS
5274
5275#if HAVE_OPENSSL
5276 int r;
5277
5278 assert(parent_public);
8d042bc4 5279 assert(iovec_is_valid(secret));
0a7874ad
DS
5280 assert(secret || ret_secret);
5281 assert(!(secret && ret_secret)); /* Either provide a secret, or we create one, but not both */
5282 assert(ret_blob);
0a7874ad 5283 assert(ret_serialized_parent);
0a7874ad
DS
5284
5285 log_debug("Calculating sealed object.");
5286
5287 /* Default to the SRK. */
5288 if (parent_handle == 0)
5289 parent_handle = TPM2_SRK_HANDLE;
5290
5291 switch (TPM2_HANDLE_TYPE(parent_handle)) {
5292 case TPM2_HT_PERSISTENT:
5293 case TPM2_HT_NV_INDEX:
5294 break;
5295 case TPM2_HT_TRANSIENT:
5296 log_warning("Handle is transient, sealed secret may not be recoverable.");
5297 break;
5298 default:
5299 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
5300 "Handle 0x%" PRIx32 " not persistent, transient, or NV.",
5301 parent_handle);
5302 }
5303
8d042bc4 5304 _cleanup_(iovec_done_erase) struct iovec generated_secret = {};
0a7874ad
DS
5305 if (!secret) {
5306 /* No secret provided, generate a random secret. We use SHA256 digest length, though it can
5307 * be up to TPM2_MAX_SEALED_DATA. The secret length is not limited to the nameAlg hash
5308 * size. */
8d042bc4
LP
5309 generated_secret.iov_len = TPM2_SHA256_DIGEST_SIZE;
5310 generated_secret.iov_base = malloc(generated_secret.iov_len);
5311 if (!generated_secret.iov_base)
0a7874ad
DS
5312 return log_oom_debug();
5313
8d042bc4 5314 r = crypto_random_bytes(generated_secret.iov_base, generated_secret.iov_len);
0a7874ad
DS
5315 if (r < 0)
5316 return log_debug_errno(r, "Failed to generate secret key: %m");
5317
8d042bc4 5318 secret = &generated_secret;
0a7874ad
DS
5319 }
5320
8d042bc4 5321 if (secret->iov_len > TPM2_MAX_SEALED_DATA)
0a7874ad
DS
5322 return log_debug_errno(SYNTHETIC_ERRNO(EOVERFLOW),
5323 "Secret size %zu too large, limit is %d bytes.",
8d042bc4 5324 secret->iov_len, TPM2_MAX_SEALED_DATA);
0a7874ad
DS
5325
5326 TPM2B_DIGEST random_seed;
5327 TPM2B_ENCRYPTED_SECRET seed;
5328 r = tpm2_calculate_seal_seed(parent_public, &random_seed, &seed);
5329 if (r < 0)
5330 return r;
5331
5332 TPM2B_PUBLIC public;
8d042bc4 5333 r = tpm2_calculate_seal_public(parent_public, attributes, policy, &random_seed, secret->iov_base, secret->iov_len, &public);
0a7874ad
DS
5334 if (r < 0)
5335 return r;
5336
5337 TPM2B_NAME name;
5338 r = tpm2_calculate_pubkey_name(&public.publicArea, &name);
5339 if (r < 0)
5340 return r;
5341
5342 TPM2B_PRIVATE private;
8d042bc4 5343 r = tpm2_calculate_seal_private(parent_public, &name, pin, &random_seed, secret->iov_base, secret->iov_len, &private);
0a7874ad
DS
5344 if (r < 0)
5345 return r;
5346
8d042bc4
LP
5347 _cleanup_(iovec_done) struct iovec blob = {};
5348 r = tpm2_marshal_blob(&public, &private, &seed, &blob.iov_base, &blob.iov_len);
0a7874ad
DS
5349 if (r < 0)
5350 return log_debug_errno(r, "Could not create sealed blob: %m");
5351
5352 TPM2B_NAME parent_name;
5353 r = tpm2_calculate_pubkey_name(&parent_public->publicArea, &parent_name);
5354 if (r < 0)
5355 return r;
5356
8d042bc4 5357 _cleanup_(iovec_done) struct iovec serialized_parent = {};
0a7874ad
DS
5358 r = tpm2_calculate_serialize(
5359 parent_handle,
5360 &parent_name,
5361 parent_public,
8d042bc4
LP
5362 &serialized_parent.iov_base,
5363 &serialized_parent.iov_len);
0a7874ad
DS
5364 if (r < 0)
5365 return r;
5366
5367 if (ret_secret)
8d042bc4
LP
5368 *ret_secret = TAKE_STRUCT(generated_secret);
5369 *ret_blob = TAKE_STRUCT(blob);
5370 *ret_serialized_parent = TAKE_STRUCT(serialized_parent);
0a7874ad
DS
5371
5372 return 0;
5373#else /* HAVE_OPENSSL */
5374 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
5375#endif
5376}
5377
9e437994 5378int tpm2_seal(Tpm2Context *c,
382bfd90 5379 uint32_t seal_key_handle,
9e437994 5380 const TPM2B_DIGEST *policy,
d9b5841d 5381 const char *pin,
8d042bc4
LP
5382 struct iovec *ret_secret,
5383 struct iovec *ret_blob,
acbb504e 5384 uint16_t *ret_primary_alg,
8d042bc4 5385 struct iovec *ret_srk) {
5e521624 5386
9e437994 5387 uint16_t primary_alg = 0;
5e521624
LP
5388 int r;
5389
5390 assert(ret_secret);
5e521624 5391 assert(ret_blob);
5e521624
LP
5392
5393 /* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
5394 * is randomized when the TPM2 is first initialized or reset and remains stable across boots. We
2b92a672
LP
5395 * generate a "primary" key pair derived from that (ECC if possible, RSA as fallback). Given the seed
5396 * remains fixed this will result in the same key pair whenever we specify the exact same parameters
5397 * for it. We then create a PCR-bound policy session, which calculates a hash on the current PCR
5398 * values of the indexes we specify. We then generate a randomized key on the host (which is the key
5399 * we actually enroll in the LUKS2 keyslots), which we upload into the TPM2, where it is encrypted
5400 * with the "primary" key, taking the PCR policy session into account. We then download the encrypted
5401 * key from the TPM2 ("sealing") and marshall it into binary form, which is ultimately placed in the
5402 * LUKS2 JSON header.
5e521624
LP
5403 *
5404 * The TPM2 "seed" key and "primary" keys never leave the TPM2 chip (and cannot be extracted at
5405 * all). The random key we enroll in LUKS2 we generate on the host using the Linux random device. It
5406 * is stored in the LUKS2 JSON only in encrypted form with the "primary" key of the TPM2 chip, thus
5407 * binding the unlocking to the TPM2 chip. */
5408
ee6a8713 5409 usec_t start = now(CLOCK_MONOTONIC);
692597c8 5410
9bf91584
GAP
5411 TPMA_OBJECT hmac_attributes =
5412 TPMA_OBJECT_FIXEDTPM |
5413 TPMA_OBJECT_FIXEDPARENT;
5414
5415 /* If protected by PIN, a user-selected low-entropy password, enable DA protection.
5416 Without a PIN, the key's left protected only by a PCR policy, which does not benefit
5417 from DA protection. */
5418 hmac_attributes |= pin ? 0 : TPMA_OBJECT_NODA;
5419
5e521624
LP
5420 /* We use a keyed hash object (i.e. HMAC) to store the secret key we want to use for unlocking the
5421 * LUKS2 volume with. We don't ever use for HMAC/keyed hash operations however, we just use it
5422 * because it's a key type that is universally supported and suitable for symmetric binary blobs. */
e3f1f210
DS
5423 TPMT_PUBLIC hmac_template = {
5424 .type = TPM2_ALG_KEYEDHASH,
5425 .nameAlg = TPM2_ALG_SHA256,
9bf91584 5426 .objectAttributes = hmac_attributes,
e3f1f210
DS
5427 .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
5428 .unique.keyedHash.size = SHA256_DIGEST_SIZE,
9e437994 5429 .authPolicy = policy ? *policy : TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE),
5e521624
LP
5430 };
5431
e3f1f210
DS
5432 TPMS_SENSITIVE_CREATE hmac_sensitive = {
5433 .data.size = hmac_template.unique.keyedHash.size,
5e521624 5434 };
ee6a8713
DS
5435
5436 CLEANUP_ERASE(hmac_sensitive);
5437
94a4ff2d 5438 if (pin) {
d0f8da98 5439 r = tpm2_auth_value_from_pin(TPM2_ALG_SHA256, pin, &hmac_sensitive.userAuth);
94a4ff2d
DS
5440 if (r < 0)
5441 return r;
5442 }
0e15c14f 5443
e3f1f210 5444 assert(sizeof(hmac_sensitive.data.buffer) >= hmac_sensitive.data.size);
5e521624 5445
23e9ccc2 5446 (void) tpm2_credit_random(c);
5e521624
LP
5447
5448 log_debug("Generating secret key data.");
5449
e3f1f210 5450 r = crypto_random_bytes(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
16e16b8c 5451 if (r < 0)
f9a0ee75 5452 return log_debug_errno(r, "Failed to generate secret key: %m");
5e521624 5453
1dc8f518 5454 _cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
8d042bc4 5455 if (ret_srk) {
9e437994 5456 _cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
382bfd90
DS
5457
5458 if (IN_SET(seal_key_handle, 0, TPM2_SRK_HANDLE)) {
5459 r = tpm2_get_or_create_srk(
5460 c,
5461 /* session= */ NULL,
5462 &primary_public,
5463 /* ret_name= */ NULL,
5464 /* ret_qname= */ NULL,
5465 &primary_handle);
5466 if (r < 0)
5467 return r;
5468 } else if (IN_SET(TPM2_HANDLE_TYPE(seal_key_handle), TPM2_HT_TRANSIENT, TPM2_HT_PERSISTENT)) {
5469 r = tpm2_index_to_handle(
5470 c,
5471 seal_key_handle,
5472 /* session= */ NULL,
5473 &primary_public,
5474 /* ret_name= */ NULL,
5475 /* ret_qname= */ NULL,
5476 &primary_handle);
5477 if (r < 0)
5478 return r;
5479 if (r == 0)
5480 /* We do NOT automatically create anything other than the SRK */
5481 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
5482 "No handle found at index 0x%" PRIx32, seal_key_handle);
5483 } else
5484 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
5485 "Seal key handle 0x%" PRIx32 " is neither transient nor persistent.",
5486 seal_key_handle);
9e437994
DS
5487
5488 primary_alg = primary_public->publicArea.type;
cea525a9 5489 } else {
382bfd90
DS
5490 if (seal_key_handle != 0)
5491 log_debug("Using primary alg sealing, but seal key handle also provided; ignoring seal key handle.");
5492
8d042bc4 5493 /* TODO: force all callers to provide ret_srk, so we can stop sealing with the legacy templates. */
9e437994
DS
5494 primary_alg = TPM2_ALG_ECC;
5495
f7ad4376
LP
5496 TPM2B_PUBLIC template = {
5497 .size = sizeof(TPMT_PUBLIC),
5498 };
9e437994 5499 r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
cea525a9 5500 if (r < 0)
f9a0ee75 5501 return log_debug_errno(r, "Could not get legacy ECC template: %m");
cea525a9 5502
aff853f8 5503 if (!tpm2_supports_tpmt_public(c, &template.publicArea)) {
9e437994
DS
5504 primary_alg = TPM2_ALG_RSA;
5505
5506 r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
cea525a9 5507 if (r < 0)
f9a0ee75 5508 return log_debug_errno(r, "Could not get legacy RSA template: %m");
cea525a9 5509
aff853f8 5510 if (!tpm2_supports_tpmt_public(c, &template.publicArea))
f9a0ee75 5511 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
cea525a9
DS
5512 "TPM does not support either ECC or RSA legacy template.");
5513 }
5514
aff853f8 5515 r = tpm2_create_primary(
cea525a9 5516 c,
cea525a9
DS
5517 /* session= */ NULL,
5518 &template,
5519 /* sensitive= */ NULL,
9e437994 5520 /* ret_public= */ NULL,
cea525a9
DS
5521 &primary_handle);
5522 if (r < 0)
5523 return r;
5524 }
d9a1f1a7 5525
1dc8f518 5526 _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
73592a7c 5527 r = tpm2_make_encryption_session(c, primary_handle, /* bind_key= */ NULL, &encryption_session);
d9a1f1a7
DS
5528 if (r < 0)
5529 return r;
5530
ee6a8713
DS
5531 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
5532 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
e3f1f210
DS
5533 r = tpm2_create(c, primary_handle, encryption_session, &hmac_template, &hmac_sensitive, &public, &private);
5534 if (r < 0)
5535 return r;
5e521624 5536
8d042bc4
LP
5537 _cleanup_(iovec_done_erase) struct iovec secret = {};
5538 secret.iov_base = memdup(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
5539 if (!secret.iov_base)
f9a0ee75 5540 return log_oom_debug();
8d042bc4 5541 secret.iov_len = hmac_sensitive.data.size;
5e521624
LP
5542
5543 log_debug("Marshalling private and public part of HMAC key.");
5544
8d042bc4
LP
5545 _cleanup_(iovec_done) struct iovec blob = {};
5546 r = tpm2_marshal_blob(public, private, /* seed= */ NULL, &blob.iov_base, &blob.iov_len);
653c3fe9 5547 if (r < 0)
f9a0ee75 5548 return log_debug_errno(r, "Could not create sealed blob: %m");
5e521624 5549
5291f26d
ZJS
5550 if (DEBUG_LOGGING)
5551 log_debug("Completed TPM2 key sealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
5e521624 5552
8d042bc4
LP
5553 if (ret_srk) {
5554 _cleanup_(iovec_done) struct iovec srk = {};
1eff4242 5555 _cleanup_(Esys_Freep) void *tmp = NULL;
8d042bc4
LP
5556 size_t tmp_size;
5557
5558 r = tpm2_serialize(c, primary_handle, &tmp, &tmp_size);
1eff4242
DS
5559 if (r < 0)
5560 return r;
5561
acbb504e
WR
5562 /*
5563 * make a copy since we don't want the caller to understand that
5564 * ESYS allocated the pointer. It would make tracking what deallocator
8d042bc4 5565 * to use for srk in which context a PITA.
acbb504e 5566 */
8d042bc4
LP
5567 srk.iov_base = memdup(tmp, tmp_size);
5568 if (!srk.iov_base)
f9a0ee75 5569 return log_oom_debug();
8d042bc4 5570 srk.iov_len = tmp_size;
acbb504e 5571
8d042bc4 5572 *ret_srk = TAKE_STRUCT(srk);
acbb504e
WR
5573 }
5574
8d042bc4
LP
5575 *ret_secret = TAKE_STRUCT(secret);
5576 *ret_blob = TAKE_STRUCT(blob);
9e437994
DS
5577
5578 if (ret_primary_alg)
5579 *ret_primary_alg = primary_alg;
5e521624 5580
16e16b8c 5581 return 0;
5e521624
LP
5582}
5583
0254e4d6
AAF
5584#define RETRY_UNSEAL_MAX 30u
5585
db7fdf15 5586int tpm2_unseal(Tpm2Context *c,
d9b5841d 5587 uint32_t hash_pcr_mask,
07697bfe 5588 uint16_t pcr_bank,
8d042bc4 5589 const struct iovec *pubkey,
d9b5841d
LP
5590 uint32_t pubkey_pcr_mask,
5591 JsonVariant *signature,
5592 const char *pin,
a4342701 5593 const Tpm2PCRLockPolicy *pcrlock_policy,
2b92a672 5594 uint16_t primary_alg,
8d042bc4
LP
5595 const struct iovec *blob,
5596 const struct iovec *known_policy_hash,
5597 const struct iovec *srk,
5598 struct iovec *ret_secret) {
5e521624 5599
5e521624 5600 TSS2_RC rc;
5e521624
LP
5601 int r;
5602
8d042bc4
LP
5603 assert(iovec_is_set(blob));
5604 assert(iovec_is_valid(known_policy_hash));
5605 assert(iovec_is_valid(pubkey));
5e521624 5606 assert(ret_secret);
5e521624 5607
d9b5841d
LP
5608 assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
5609 assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));
5e521624
LP
5610
5611 /* So here's what we do here: We connect to the TPM2 chip. As we do when sealing we generate a
dc176813
ZJS
5612 * "primary" key on the TPM2 chip, with the same parameters as well as a PCR-bound policy session.
5613 * Given we pass the same parameters, this will result in the same "primary" key, and same policy
5614 * hash (the latter of course, only if the PCR values didn't change in between). We unmarshal the
5615 * encrypted key we stored in the LUKS2 JSON token header and upload it into the TPM2, where it is
5616 * decrypted if the seed and the PCR policy were right ("unsealing"). We then download the result,
5e521624
LP
5617 * and use it to unlock the LUKS2 volume. */
5618
98497426 5619 usec_t start = now(CLOCK_MONOTONIC);
5e521624 5620
653c3fe9
DS
5621 TPM2B_PUBLIC public;
5622 TPM2B_PRIVATE private;
0a7874ad 5623 TPM2B_ENCRYPTED_SECRET seed = {};
8d042bc4 5624 r = tpm2_unmarshal_blob(blob->iov_base, blob->iov_len, &public, &private, &seed);
653c3fe9 5625 if (r < 0)
f9a0ee75 5626 return log_debug_errno(r, "Could not extract parts from blob: %m");
5e521624 5627
730d6ab9
DS
5628 /* Older code did not save the pcr_bank, and unsealing needed to detect the best pcr bank to use,
5629 * so we need to handle that legacy situation. */
5630 if (pcr_bank == UINT16_MAX) {
5631 r = tpm2_get_best_pcr_bank(c, hash_pcr_mask|pubkey_pcr_mask, &pcr_bank);
5632 if (r < 0)
5633 return r;
5634 }
5635
20988602 5636 _cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
8d042bc4
LP
5637 if (iovec_is_set(srk)) {
5638 r = tpm2_deserialize(c, srk->iov_base, srk->iov_len, &primary_handle);
acbb504e
WR
5639 if (r < 0)
5640 return r;
20988602 5641 } else if (primary_alg != 0) {
4af7f27a
LP
5642 TPM2B_PUBLIC template = {
5643 .size = sizeof(TPMT_PUBLIC),
5644 };
aff853f8 5645 r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
20988602 5646 if (r < 0)
f9a0ee75 5647 return log_debug_errno(r, "Could not get legacy template: %m");
20988602 5648
aff853f8 5649 r = tpm2_create_primary(
20988602 5650 c,
20988602
DS
5651 /* session= */ NULL,
5652 &template,
5653 /* sensitive= */ NULL,
5654 /* ret_public= */ NULL,
20988602 5655 &primary_handle);
acbb504e
WR
5656 if (r < 0)
5657 return r;
20988602 5658 } else
f9a0ee75 5659 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
20988602 5660 "No SRK or primary alg provided.");
da29de23 5661
0a7874ad
DS
5662 if (seed.size > 0) {
5663 /* This is a calculated (or duplicated) sealed object, and must be imported. */
5664 _cleanup_free_ TPM2B_PRIVATE *imported_private = NULL;
5665 r = tpm2_import(c,
5666 primary_handle,
5667 /* session= */ NULL,
5668 &public,
5669 &private,
5670 &seed,
5671 /* encryption_key= */ NULL,
5672 /* symmetric= */ NULL,
5673 &imported_private);
5674 if (r < 0)
5675 return r;
5676
5677 private = *imported_private;
5678 }
5679
5e521624
LP
5680 log_debug("Loading HMAC key into TPM.");
5681
0e15c14f
WR
5682 /*
5683 * Nothing sensitive on the bus, no need for encryption. Even if an attacker
acbb504e
WR
5684 * gives you back a different key, the session initiation will fail. In the
5685 * SRK model, the tpmKey is verified. In the non-srk model, with pin, the bindKey
5686 * provides protections.
0e15c14f 5687 */
1dc8f518 5688 _cleanup_(tpm2_handle_freep) Tpm2Handle *hmac_key = NULL;
20988602 5689 r = tpm2_load(c, primary_handle, NULL, &public, &private, &hmac_key);
16e16b8c
DS
5690 if (r < 0)
5691 return r;
5692
e3acb4d2 5693 TPM2B_PUBLIC pubkey_tpm2b;
8d042bc4
LP
5694 _cleanup_(iovec_done) struct iovec fp = {};
5695 if (iovec_is_set(pubkey)) {
5696 r = tpm2_tpm2b_public_from_pem(pubkey->iov_base, pubkey->iov_len, &pubkey_tpm2b);
524cef3f 5697 if (r < 0)
f9a0ee75 5698 return log_debug_errno(r, "Could not create TPMT_PUBLIC: %m");
e3acb4d2 5699
8d042bc4 5700 r = tpm2_tpm2b_public_to_fingerprint(&pubkey_tpm2b, &fp.iov_base, &fp.iov_len);
e3acb4d2 5701 if (r < 0)
f9a0ee75 5702 return log_debug_errno(r, "Could not get key fingerprint: %m");
524cef3f
DS
5703 }
5704
409a65f8
DS
5705 /*
5706 * if a pin is set for the seal object, use it to bind the session
5707 * key to that object. This prevents active bus interposers from
5708 * faking a TPM and seeing the unsealed value. An active interposer
5709 * could fake a TPM, satisfying the encrypted session, and just
5710 * forward everything to the *real* TPM.
5711 */
5712 r = tpm2_set_auth(c, hmac_key, pin);
5713 if (r < 0)
5714 return r;
5715
98497426 5716 _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL;
0254e4d6 5717 for (unsigned i = RETRY_UNSEAL_MAX;; i--) {
1923e213
GAP
5718 _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
5719 r = tpm2_make_encryption_session(c, primary_handle, hmac_key, &encryption_session);
5720 if (r < 0)
5721 return r;
5722
1dc8f518 5723 _cleanup_(tpm2_handle_freep) Tpm2Handle *policy_session = NULL;
23b972d5 5724 _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
0254e4d6 5725 r = tpm2_make_policy_session(
23e9ccc2 5726 c,
20988602 5727 primary_handle,
2cd9d575 5728 encryption_session,
2cd9d575
DS
5729 &policy_session);
5730 if (r < 0)
5731 return r;
5732
5733 r = tpm2_build_sealing_policy(
5734 c,
5735 policy_session,
0254e4d6
AAF
5736 hash_pcr_mask,
5737 pcr_bank,
8d042bc4
LP
5738 iovec_is_set(pubkey) ? &pubkey_tpm2b : NULL,
5739 fp.iov_base, fp.iov_len,
0254e4d6
AAF
5740 pubkey_pcr_mask,
5741 signature,
5742 !!pin,
a4342701 5743 pcrlock_policy,
2cd9d575 5744 &policy_digest);
0254e4d6 5745 if (r < 0)
16e16b8c 5746 return r;
2f5a892a 5747
0254e4d6
AAF
5748 /* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not
5749 * wait until the TPM2 tells us to go away. */
fda3e844
DS
5750 if (iovec_is_set(known_policy_hash) && memcmp_nn(policy_digest->buffer,
5751 policy_digest->size,
5752 known_policy_hash->iov_base,
5753 known_policy_hash->iov_len) != 0) {
5754#if HAVE_OPENSSL
5755 if (iovec_is_set(pubkey) &&
5756 pubkey_tpm2b.publicArea.type == TPM2_ALG_RSA &&
5757 pubkey_tpm2b.publicArea.parameters.rsaDetail.exponent == TPM2_RSA_DEFAULT_EXPONENT) {
5758 /* Due to bug #30546, if using RSA pubkey with the default exponent, we may
5759 * need to set the exponent to the TPM special-case value of 0 and retry. */
5760 log_debug("Policy hash mismatch, retrying with RSA pubkey exponent set to 0.");
5761 pubkey_tpm2b.publicArea.parameters.rsaDetail.exponent = 0;
5762 continue;
5763 } else
5764#endif
f9a0ee75 5765 return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
0254e4d6
AAF
5766 "Current policy digest does not match stored policy digest, cancelling "
5767 "TPM2 authentication attempt.");
fda3e844 5768 }
2f5a892a 5769
0254e4d6 5770 log_debug("Unsealing HMAC key.");
5e521624 5771
0254e4d6 5772 rc = sym_Esys_Unseal(
68d084ce 5773 c->esys_context,
16e16b8c
DS
5774 hmac_key->esys_handle,
5775 policy_session->esys_handle,
2cd9d575 5776 encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
0254e4d6
AAF
5777 ESYS_TR_NONE,
5778 &unsealed);
16e16b8c
DS
5779 if (rc == TSS2_RC_SUCCESS)
5780 break;
5781 if (rc != TPM2_RC_PCR_CHANGED || i == 0)
f9a0ee75 5782 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
16e16b8c
DS
5783 "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
5784 log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
5e521624
LP
5785 }
5786
8d042bc4
LP
5787 _cleanup_(iovec_done_erase) struct iovec secret = {};
5788 secret.iov_base = memdup(unsealed->buffer, unsealed->size);
5e521624 5789 explicit_bzero_safe(unsealed->buffer, unsealed->size);
8d042bc4 5790 if (!secret.iov_base)
f9a0ee75 5791 return log_oom_debug();
8d042bc4 5792 secret.iov_len = unsealed->size;
5e521624 5793
5291f26d
ZJS
5794 if (DEBUG_LOGGING)
5795 log_debug("Completed TPM2 key unsealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
5e521624 5796
8d042bc4 5797 *ret_secret = TAKE_STRUCT(secret);
5e521624 5798
16e16b8c 5799 return 0;
5e521624
LP
5800}
5801
48d06056
LP
5802static TPM2_HANDLE generate_random_nv_index(void) {
5803 return TPM2_NV_INDEX_FIRST + (TPM2_HANDLE) random_u64_range(TPM2_NV_INDEX_LAST - TPM2_NV_INDEX_FIRST + 1);
5804}
5805
5806int tpm2_define_policy_nv_index(
5807 Tpm2Context *c,
5808 const Tpm2Handle *session,
5809 TPM2_HANDLE requested_nv_index,
5810 const TPM2B_DIGEST *write_policy,
48d06056
LP
5811 TPM2_HANDLE *ret_nv_index,
5812 Tpm2Handle **ret_nv_handle,
5813 TPM2B_NV_PUBLIC *ret_nv_public) {
5814
5815 _cleanup_(tpm2_handle_freep) Tpm2Handle *new_handle = NULL;
5816 TSS2_RC rc;
5817 int r;
5818
5819 assert(c);
48d06056 5820
19d82e1b
LP
5821 /* Allocates an nvindex to store a policy for use in PolicyAuthorizeNV in. This is where pcrlock then
5822 * stores its predicted PCR policies in. If 'requested_nv_index' will try to allocate the specified
5823 * nvindex, otherwise will find a free one, and use that. */
48d06056
LP
5824
5825 r = tpm2_handle_new(c, &new_handle);
5826 if (r < 0)
5827 return r;
5828
5829 new_handle->flush = false; /* This is a persistent NV index, don't flush hence */
5830
48d06056
LP
5831 for (unsigned try = 0; try < 25U; try++) {
5832 TPM2_HANDLE nv_index;
5833
5834 if (requested_nv_index != 0)
5835 nv_index = requested_nv_index;
5836 else
5837 nv_index = generate_random_nv_index();
5838
5839 TPM2B_NV_PUBLIC public_info = {
5840 .size = sizeof_field(TPM2B_NV_PUBLIC, nvPublic),
5841 .nvPublic = {
5842 .nvIndex = nv_index,
5843 .nameAlg = TPM2_ALG_SHA256,
5844 .attributes = TPM2_NT_ORDINARY | TPMA_NV_WRITEALL | TPMA_NV_POLICYWRITE | TPMA_NV_OWNERREAD,
5845 .dataSize = offsetof(TPMT_HA, digest) + tpm2_hash_alg_to_size(TPM2_ALG_SHA256),
5846 },
5847 };
5848
5849 if (write_policy)
5850 public_info.nvPublic.authPolicy = *write_policy;
5851
5852 rc = sym_Esys_NV_DefineSpace(
5853 c->esys_context,
5854 /* authHandle= */ ESYS_TR_RH_OWNER,
5855 /* shandle1= */ session ? session->esys_handle : ESYS_TR_PASSWORD,
5856 /* shandle2= */ ESYS_TR_NONE,
5857 /* shandle3= */ ESYS_TR_NONE,
d10d4a37 5858 /* auth= */ NULL,
48d06056
LP
5859 &public_info,
5860 &new_handle->esys_handle);
5861
5862 if (rc == TSS2_RC_SUCCESS) {
5863 log_debug("NV Index 0x%" PRIx32 " successfully allocated.", nv_index);
5864
5865 if (ret_nv_index)
5866 *ret_nv_index = nv_index;
5867
5868 if (ret_nv_handle)
5869 *ret_nv_handle = TAKE_PTR(new_handle);
5870
5871 if (ret_nv_public)
5872 *ret_nv_public = public_info;
5873
5874 return 0;
5875 }
5876 if (rc != TPM2_RC_NV_DEFINED)
5877 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5878 "Failed to allocate NV index: %s", sym_Tss2_RC_Decode(rc));
5879
5880 if (requested_nv_index != 0) {
5881 assert(nv_index == requested_nv_index);
5882 return log_debug_errno(SYNTHETIC_ERRNO(EEXIST),
5883 "Requested NV index 0x%" PRIx32 " already taken.", requested_nv_index);
5884 }
5885
5886 log_debug("NV index 0x%" PRIu32 " already taken, trying another one (%u tries left)", nv_index, try);
5887 }
5888
5889 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5890 "Too many attempts trying to allocate NV index: %s", sym_Tss2_RC_Decode(rc));
5891}
5892
5893int tpm2_write_policy_nv_index(
5894 Tpm2Context *c,
5895 const Tpm2Handle *policy_session,
5896 TPM2_HANDLE nv_index,
5897 const Tpm2Handle *nv_handle,
5898 const TPM2B_DIGEST *policy_digest) {
5899
5900 TSS2_RC rc;
5901
5902 assert(c);
5903 assert(policy_session);
5904 assert(nv_handle);
5905 assert(policy_digest);
5906
5907 if (policy_digest->size != tpm2_hash_alg_to_size(TPM2_ALG_SHA256))
5908 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Policy to store in NV index has wrong size.");
5909
5910 TPMT_HA ha = {
5911 .hashAlg = TPM2_ALG_SHA256,
5912 };
5913 assert(policy_digest->size <= sizeof_field(TPMT_HA, digest));
5914 memcpy_safe(&ha.digest, policy_digest->buffer, policy_digest->size);
5915
5916 TPM2B_MAX_NV_BUFFER buffer = {};
5917 size_t written = 0;
5918 rc = sym_Tss2_MU_TPMT_HA_Marshal(&ha, buffer.buffer, sizeof(buffer.buffer), &written);
5919 if (rc != TSS2_RC_SUCCESS)
5920 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5921 "Failed to marshal policy digest.");
5922
5923 buffer.size = written;
5924
5925 rc = sym_Esys_NV_Write(
5926 c->esys_context,
5927 /* authHandle= */ nv_handle->esys_handle,
5928 /* nvIndex= */ nv_handle->esys_handle,
5929 /* shandle1= */ policy_session->esys_handle,
5930 /* shandle2= */ ESYS_TR_NONE,
5931 /* shandle3= */ ESYS_TR_NONE,
5932 &buffer,
5933 /* offset= */ 0);
5934 if (rc != TSS2_RC_SUCCESS)
5935 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5936 "Failed to write NV index: %s", sym_Tss2_RC_Decode(rc));
5937
5938 if (DEBUG_LOGGING) {
5939 _cleanup_free_ char *h = NULL;
5940 h = hexmem(policy_digest->buffer, policy_digest->size);
5941 log_debug("Written policy digest %s to NV index 0x%x", strnull(h), nv_index);
5942 }
5943
5944 return 0;
5945}
5946
5947int tpm2_undefine_policy_nv_index(
5948 Tpm2Context *c,
5949 const Tpm2Handle *session,
5950 TPM2_HANDLE nv_index,
5951 const Tpm2Handle *nv_handle) {
5952
5953 TSS2_RC rc;
5954
5955 assert(c);
5956 assert(nv_handle);
5957
5958 rc = sym_Esys_NV_UndefineSpace(
5959 c->esys_context,
5960 /* authHandle= */ ESYS_TR_RH_OWNER,
5961 /* nvIndex= */ nv_handle->esys_handle,
5962 /* shandle1= */ session ? session->esys_handle : ESYS_TR_NONE,
5963 /* shandle2= */ ESYS_TR_NONE,
5964 /* shandle3= */ ESYS_TR_NONE);
5965 if (rc != TSS2_RC_SUCCESS)
5966 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5967 "Failed to undefine NV index: %s", sym_Tss2_RC_Decode(rc));
5968
5969 log_debug("Undefined NV index 0x%x", nv_index);
5970 return 0;
5971}
ce80da02
LP
5972
5973int tpm2_seal_data(
5974 Tpm2Context *c,
5975 const struct iovec *data,
5976 const Tpm2Handle *primary_handle,
5977 const Tpm2Handle *encryption_session,
5978 const TPM2B_DIGEST *policy,
5979 struct iovec *ret_public,
5980 struct iovec *ret_private) {
5981
5982 int r;
5983
5984 assert(c);
5985 assert(data);
5986 assert(primary_handle);
5987
5988 /* This is a generic version of tpm2_seal(), that doesn't imply any policy or any specific
5989 * combination of the two keypairs in their marshalling. tpm2_seal() is somewhat specific to the FDE
5990 * usecase. We probably should migrate tpm2_seal() to use tpm2_seal_data() eventually. */
5991
5992 if (data->iov_len >= sizeof_field(TPMS_SENSITIVE_CREATE, data.buffer))
5993 return -E2BIG;
5994
5995 TPMT_PUBLIC hmac_template = {
5996 .type = TPM2_ALG_KEYEDHASH,
5997 .nameAlg = TPM2_ALG_SHA256,
5998 .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
5999 .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
6000 .unique.keyedHash.size = data->iov_len,
6001 .authPolicy = policy ? *policy : TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE),
6002 };
6003
6004 TPMS_SENSITIVE_CREATE hmac_sensitive = {
6005 .data.size = hmac_template.unique.keyedHash.size,
6006 };
6007
6008 CLEANUP_ERASE(hmac_sensitive);
6009
6010 memcpy_safe(hmac_sensitive.data.buffer, data->iov_base, data->iov_len);
6011
6012 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
6013 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
6014 r = tpm2_create(c, primary_handle, encryption_session, &hmac_template, &hmac_sensitive, &public, &private);
6015 if (r < 0)
6016 return r;
6017
6018 _cleanup_(iovec_done) struct iovec public_blob = {}, private_blob = {};
6019
6020 r = tpm2_marshal_private(private, &private_blob.iov_base, &private_blob.iov_len);
6021 if (r < 0)
6022 return r;
6023
6024 r = tpm2_marshal_public(public, &public_blob.iov_base, &public_blob.iov_len);
6025 if (r < 0)
6026 return r;
6027
6028 if (ret_public)
6029 *ret_public = TAKE_STRUCT(public_blob);
6030 if (ret_private)
6031 *ret_private = TAKE_STRUCT(private_blob);
6032
6033 return 0;
6034}
6035
6036int tpm2_unseal_data(
6037 Tpm2Context *c,
6038 const struct iovec *public_blob,
6039 const struct iovec *private_blob,
6040 const Tpm2Handle *primary_handle,
6041 const Tpm2Handle *policy_session,
6042 const Tpm2Handle *encryption_session,
6043 struct iovec *ret_data) {
6044
6045 TSS2_RC rc;
6046 int r;
6047
6048 assert(c);
6049 assert(public_blob);
6050 assert(private_blob);
6051 assert(primary_handle);
6052
6053 TPM2B_PUBLIC public;
6054 r = tpm2_unmarshal_public(public_blob->iov_base, public_blob->iov_len, &public);
6055 if (r < 0)
6056 return r;
6057
6058 TPM2B_PRIVATE private;
6059 r = tpm2_unmarshal_private(private_blob->iov_base, private_blob->iov_len, &private);
6060 if (r < 0)
6061 return r;
6062
6063 _cleanup_(tpm2_handle_freep) Tpm2Handle *what = NULL;
6064 r = tpm2_load(c, primary_handle, NULL, &public, &private, &what);
6065 if (r < 0)
6066 return r;
6067
6068 _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL;
6069 rc = sym_Esys_Unseal(
6070 c->esys_context,
6071 what->esys_handle,
6072 policy_session ? policy_session->esys_handle : ESYS_TR_NONE,
6073 encryption_session ? encryption_session->esys_handle : ESYS_TR_NONE,
6074 ESYS_TR_NONE,
6075 &unsealed);
6076 if (rc == TPM2_RC_PCR_CHANGED)
6077 return log_debug_errno(SYNTHETIC_ERRNO(ESTALE),
6078 "PCR changed while unsealing.");
6079 if (rc != TSS2_RC_SUCCESS)
6080 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
6081 "Failed to unseal data: %s", sym_Tss2_RC_Decode(rc));
6082
6083 _cleanup_(iovec_done) struct iovec d = {};
c490b6dd 6084 d = IOVEC_MAKE(memdup(unsealed->buffer, unsealed->size), unsealed->size);
ce80da02
LP
6085
6086 explicit_bzero_safe(unsealed->buffer, unsealed->size);
6087
6088 if (!d.iov_base)
6089 return log_oom_debug();
6090
6091 *ret_data = TAKE_STRUCT(d);
6092 return 0;
6093}
48d06056 6094#endif /* HAVE_TPM2 */
5e521624
LP
6095
6096int tpm2_list_devices(void) {
6097#if HAVE_TPM2
6098 _cleanup_(table_unrefp) Table *t = NULL;
5d2a48da 6099 _cleanup_closedir_ DIR *d = NULL;
5e521624
LP
6100 int r;
6101
6102 r = dlopen_tpm2();
6103 if (r < 0)
6104 return log_error_errno(r, "TPM2 support is not installed.");
6105
6106 t = table_new("path", "device", "driver");
6107 if (!t)
6108 return log_oom();
6109
6110 d = opendir("/sys/class/tpmrm");
6111 if (!d) {
6112 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open /sys/class/tpmrm: %m");
6113 if (errno != ENOENT)
6114 return -errno;
6115 } else {
6116 for (;;) {
6117 _cleanup_free_ char *device_path = NULL, *device = NULL, *driver_path = NULL, *driver = NULL, *node = NULL;
6118 struct dirent *de;
6119
6120 de = readdir_no_dot(d);
6121 if (!de)
6122 break;
6123
6124 device_path = path_join("/sys/class/tpmrm", de->d_name, "device");
6125 if (!device_path)
6126 return log_oom();
6127
6128 r = readlink_malloc(device_path, &device);
6129 if (r < 0)
6130 log_debug_errno(r, "Failed to read device symlink %s, ignoring: %m", device_path);
6131 else {
6132 driver_path = path_join(device_path, "driver");
6133 if (!driver_path)
6134 return log_oom();
6135
6136 r = readlink_malloc(driver_path, &driver);
6137 if (r < 0)
6138 log_debug_errno(r, "Failed to read driver symlink %s, ignoring: %m", driver_path);
6139 }
6140
6141 node = path_join("/dev", de->d_name);
6142 if (!node)
6143 return log_oom();
6144
6145 r = table_add_many(
6146 t,
6147 TABLE_PATH, node,
6148 TABLE_STRING, device ? last_path_component(device) : NULL,
6149 TABLE_STRING, driver ? last_path_component(driver) : NULL);
6150 if (r < 0)
6151 return table_log_add_error(r);
6152 }
6153 }
6154
2413a0fa 6155 if (table_isempty(t)) {
5e521624
LP
6156 log_info("No suitable TPM2 devices found.");
6157 return 0;
6158 }
6159
6160 r = table_print(t, stdout);
6161 if (r < 0)
6162 return log_error_errno(r, "Failed to show device table: %m");
6163
6164 return 0;
6165#else
6166 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
6167 "TPM2 not supported on this build.");
6168#endif
6169}
6170
f9a0ee75 6171int tpm2_find_device_auto(char **ret) {
5e521624 6172#if HAVE_TPM2
5d2a48da 6173 _cleanup_closedir_ DIR *d = NULL;
5e521624
LP
6174 int r;
6175
6176 r = dlopen_tpm2();
6177 if (r < 0)
f9a0ee75 6178 return log_debug_errno(r, "TPM2 support is not installed.");
5e521624
LP
6179
6180 d = opendir("/sys/class/tpmrm");
6181 if (!d) {
f9a0ee75 6182 log_debug_errno(errno, "Failed to open /sys/class/tpmrm: %m");
5e521624
LP
6183 if (errno != ENOENT)
6184 return -errno;
6185 } else {
6186 _cleanup_free_ char *node = NULL;
6187
6188 for (;;) {
6189 struct dirent *de;
6190
6191 de = readdir_no_dot(d);
6192 if (!de)
6193 break;
6194
6195 if (node)
f9a0ee75 6196 return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
5e521624
LP
6197 "More than one TPM2 (tpmrm) device found.");
6198
6199 node = path_join("/dev", de->d_name);
6200 if (!node)
f9a0ee75 6201 return log_oom_debug();
5e521624
LP
6202 }
6203
6204 if (node) {
6205 *ret = TAKE_PTR(node);
6206 return 0;
6207 }
6208 }
6209
f9a0ee75 6210 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "No TPM2 (tpmrm) device found.");
5e521624 6211#else
f9a0ee75 6212 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
5e521624
LP
6213 "TPM2 not supported on this build.");
6214#endif
6215}
6216
15c591d1 6217#if HAVE_TPM2
cb19bdae
LP
6218static const char* tpm2_userspace_event_type_table[_TPM2_USERSPACE_EVENT_TYPE_MAX] = {
6219 [TPM2_EVENT_PHASE] = "phase",
6220 [TPM2_EVENT_FILESYSTEM] = "filesystem",
6221 [TPM2_EVENT_VOLUME_KEY] = "volume-key",
6222 [TPM2_EVENT_MACHINE_ID] = "machine-id",
6223};
6224
6225DEFINE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);
6226
6227const char *tpm2_userspace_log_path(void) {
9551aa70 6228 return secure_getenv("SYSTEMD_MEASURE_LOG_USERSPACE") ?: "/run/log/systemd/tpm2-measure.log";
cb19bdae
LP
6229}
6230
f88f9294
LP
6231const char *tpm2_firmware_log_path(void) {
6232 return secure_getenv("SYSTEMD_MEASURE_LOG_FIRMWARE") ?: "/sys/kernel/security/tpm0/binary_bios_measurements";
6233}
6234
5629d4e2 6235#if HAVE_OPENSSL
cb19bdae
LP
6236static int tpm2_userspace_log_open(void) {
6237 _cleanup_close_ int fd = -EBADF;
6238 struct stat st;
6239 const char *e;
6240 int r;
6241
6242 e = tpm2_userspace_log_path();
6243 (void) mkdir_parents(e, 0755);
6244
6245 /* We use access mode 0600 here (even though the measurements should not strictly be confidential),
6246 * because we use BSD file locking on it, and if anyone but root can access the file they can also
6247 * lock it, which we want to avoid. */
6248 fd = open(e, O_CREAT|O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
6249 if (fd < 0)
f9a0ee75 6250 return log_debug_errno(errno, "Failed to open TPM log file '%s' for writing, ignoring: %m", e);
cb19bdae
LP
6251
6252 if (flock(fd, LOCK_EX) < 0)
f9a0ee75 6253 return log_debug_errno(errno, "Failed to lock TPM log file '%s', ignoring: %m", e);
cb19bdae
LP
6254
6255 if (fstat(fd, &st) < 0)
f9a0ee75 6256 return log_debug_errno(errno, "Failed to fstat TPM log file '%s', ignoring: %m", e);
cb19bdae
LP
6257
6258 r = stat_verify_regular(&st);
6259 if (r < 0)
f9a0ee75 6260 return log_debug_errno(r, "TPM log file '%s' is not regular, ignoring: %m", e);
cb19bdae
LP
6261
6262 /* We set the sticky bit when we are about to append to the log file. We'll unset it afterwards
6263 * again. If we manage to take a lock on a file that has it set we know we didn't write it fully and
6264 * it is corrupted. Ideally we'd like to use user xattrs for this, but unfortunately tmpfs (which is
6265 * our assumed backend fs) doesn't know user xattrs. */
6266 if (st.st_mode & S_ISVTX)
f9a0ee75 6267 return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "TPM log file '%s' aborted, ignoring.", e);
cb19bdae
LP
6268
6269 if (fchmod(fd, 0600 | S_ISVTX) < 0)
f9a0ee75 6270 return log_debug_errno(errno, "Failed to chmod() TPM log file '%s', ignoring: %m", e);
cb19bdae
LP
6271
6272 return TAKE_FD(fd);
6273}
6274
6275static int tpm2_userspace_log(
6276 int fd,
6277 unsigned pcr_index,
6278 const TPML_DIGEST_VALUES *values,
6279 Tpm2UserspaceEventType event_type,
6280 const char *description) {
6281
6282 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *array = NULL;
6283 _cleanup_free_ char *f = NULL;
6284 sd_id128_t boot_id;
6285 int r;
6286
6287 assert(values);
6288 assert(values->count > 0);
6289
6290 /* We maintain a local PCR measurement log. This implements a subset of the TCG Canonical Event Log
6291 * Format – the JSON flavour –
6292 * (https://trustedcomputinggroup.org/resource/canonical-event-log-format/), but departs in certain
6293 * ways from it, specifically:
6294 *
6295 * - We don't write out a recnum. It's a bit too vaguely defined which means we'd have to read
6296 * through the whole logs (include firmware logs) before knowing what the next value is we should
6297 * use. Hence we simply don't write this out as append-time, and instead expect a consumer to add
6298 * it in when it uses the data.
6299 *
6300 * - We write this out in RFC 7464 application/json-seq rather than as a JSON array. Writing this as
6301 * JSON array would mean that for each appending we'd have to read the whole log file fully into
6302 * memory before writing it out again. We prefer a strictly append-only write pattern however. (RFC
6303 * 7464 is what jq --seq eats.) Conversion into a proper JSON array is trivial.
6304 *
6305 * It should be possible to convert this format in a relatively straight-forward way into the
6306 * official TCG Canonical Event Log Format on read, by simply adding in a few more fields that can be
6307 * determined from the full dataset.
6308 *
6309 * We set the 'content_type' field to "systemd" to make clear this data is generated by us, and
6310 * include various interesting fields in the 'content' subobject, including a CLOCK_BOOTTIME
6311 * timestamp which can be used to order this measurement against possibly other measurements
6312 * independently done by other subsystems on the system.
6313 */
6314
6315 if (fd < 0) /* Apparently tpm2_local_log_open() failed earlier, let's not complain again */
6316 return 0;
6317
6318 for (size_t i = 0; i < values->count; i++) {
6319 const EVP_MD *implementation;
6320 const char *a;
6321
6322 assert_se(a = tpm2_hash_alg_to_string(values->digests[i].hashAlg));
6323 assert_se(implementation = EVP_get_digestbyname(a));
6324
6325 r = json_variant_append_arrayb(
6326 &array, JSON_BUILD_OBJECT(
6327 JSON_BUILD_PAIR_STRING("hashAlg", a),
6328 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(&values->digests[i].digest, EVP_MD_size(implementation)))));
6329 if (r < 0)
f9a0ee75 6330 return log_debug_errno(r, "Failed to append digest object to JSON array: %m");
cb19bdae
LP
6331 }
6332
6333 assert(array);
6334
6335 r = sd_id128_get_boot(&boot_id);
6336 if (r < 0)
f9a0ee75 6337 return log_debug_errno(r, "Failed to acquire boot ID: %m");
cb19bdae
LP
6338
6339 r = json_build(&v, JSON_BUILD_OBJECT(
6340 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(pcr_index)),
6341 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(array)),
6342 JSON_BUILD_PAIR("content_type", JSON_BUILD_STRING("systemd")),
6343 JSON_BUILD_PAIR("content", JSON_BUILD_OBJECT(
6344 JSON_BUILD_PAIR_CONDITION(description, "string", JSON_BUILD_STRING(description)),
6345 JSON_BUILD_PAIR("bootId", JSON_BUILD_ID128(boot_id)),
6346 JSON_BUILD_PAIR("timestamp", JSON_BUILD_UNSIGNED(now(CLOCK_BOOTTIME))),
6347 JSON_BUILD_PAIR_CONDITION(event_type >= 0, "eventType", JSON_BUILD_STRING(tpm2_userspace_event_type_to_string(event_type)))))));
6348 if (r < 0)
f9a0ee75 6349 return log_debug_errno(r, "Failed to build log record JSON: %m");
cb19bdae
LP
6350
6351 r = json_variant_format(v, JSON_FORMAT_SEQ, &f);
6352 if (r < 0)
f9a0ee75 6353 return log_debug_errno(r, "Failed to format JSON: %m");
cb19bdae 6354
86cbbc6d 6355 if (lseek(fd, 0, SEEK_END) < 0)
f9a0ee75 6356 return log_debug_errno(errno, "Failed to seek to end of JSON log: %m");
cb19bdae 6357
e22c60a9 6358 r = loop_write(fd, f, SIZE_MAX);
cb19bdae 6359 if (r < 0)
f9a0ee75 6360 return log_debug_errno(r, "Failed to write JSON data to log: %m");
cb19bdae
LP
6361
6362 if (fsync(fd) < 0)
f9a0ee75 6363 return log_debug_errno(errno, "Failed to sync JSON data: %m");
cb19bdae
LP
6364
6365 /* Unset S_ISVTX again */
6366 if (fchmod(fd, 0600) < 0)
f9a0ee75 6367 return log_debug_errno(errno, "Failed to chmod() TPM log file, ignoring: %m");
cb19bdae
LP
6368
6369 r = fsync_full(fd);
6370 if (r < 0)
f9a0ee75 6371 return log_debug_errno(r, "Failed to sync JSON log: %m");
cb19bdae
LP
6372
6373 return 1;
6374}
5629d4e2 6375#endif
cb19bdae 6376
15c591d1 6377int tpm2_extend_bytes(
23e9ccc2 6378 Tpm2Context *c,
15c591d1
LP
6379 char **banks,
6380 unsigned pcr_index,
6381 const void *data,
9885c874
LP
6382 size_t data_size,
6383 const void *secret,
cb19bdae
LP
6384 size_t secret_size,
6385 Tpm2UserspaceEventType event_type,
6386 const char *description) {
15c591d1
LP
6387
6388#if HAVE_OPENSSL
cb19bdae 6389 _cleanup_close_ int log_fd = -EBADF;
15c591d1
LP
6390 TPML_DIGEST_VALUES values = {};
6391 TSS2_RC rc;
6392
6393 assert(c);
9885c874
LP
6394 assert(data || data_size == 0);
6395 assert(secret || secret_size == 0);
6396
6397 if (data_size == SIZE_MAX)
6398 data_size = strlen(data);
6399 if (secret_size == SIZE_MAX)
6400 secret_size = strlen(secret);
15c591d1
LP
6401
6402 if (pcr_index >= TPM2_PCRS_MAX)
f9a0ee75 6403 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Can't measure into unsupported PCR %u, refusing.", pcr_index);
15c591d1
LP
6404
6405 if (strv_isempty(banks))
6406 return 0;
6407
6408 STRV_FOREACH(bank, banks) {
6409 const EVP_MD *implementation;
6410 int id;
6411
6412 assert_se(implementation = EVP_get_digestbyname(*bank));
6413
6414 if (values.count >= ELEMENTSOF(values.digests))
f9a0ee75 6415 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "Too many banks selected.");
15c591d1
LP
6416
6417 if ((size_t) EVP_MD_size(implementation) > sizeof(values.digests[values.count].digest))
f9a0ee75 6418 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "Hash result too large for TPM2.");
15c591d1 6419
7bfe0a48 6420 id = tpm2_hash_alg_from_string(EVP_MD_name(implementation));
15c591d1 6421 if (id < 0)
f9a0ee75 6422 return log_debug_errno(id, "Can't map hash name to TPM2.");
15c591d1
LP
6423
6424 values.digests[values.count].hashAlg = id;
6425
9885c874
LP
6426 /* So here's a twist: sometimes we want to measure secrets (e.g. root file system volume
6427 * key), but we'd rather not leak a literal hash of the secret to the TPM (given that the
6428 * wire is unprotected, and some other subsystem might use the simple, literal hash of the
6429 * secret for other purposes, maybe because it needs a shorter secret derived from it for
6430 * some unrelated purpose, who knows). Hence we instead measure an HMAC signature of a
6431 * private non-secret string instead. */
6432 if (secret_size > 0) {
6433 if (!HMAC(implementation, secret, secret_size, data, data_size, (unsigned char*) &values.digests[values.count].digest, NULL))
f9a0ee75 6434 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to calculate HMAC of data to measure.");
9885c874 6435 } else if (EVP_Digest(data, data_size, (unsigned char*) &values.digests[values.count].digest, NULL, implementation, NULL) != 1)
f9a0ee75 6436 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash data to measure.");
15c591d1
LP
6437
6438 values.count++;
6439 }
6440
fcdd21ec 6441 /* Open + lock the log file *before* we start measuring, so that no one else can come between our log
cb19bdae
LP
6442 * and our measurement and change either */
6443 log_fd = tpm2_userspace_log_open();
6444
15c591d1 6445 rc = sym_Esys_PCR_Extend(
23e9ccc2 6446 c->esys_context,
15c591d1
LP
6447 ESYS_TR_PCR0 + pcr_index,
6448 ESYS_TR_PASSWORD,
6449 ESYS_TR_NONE,
6450 ESYS_TR_NONE,
6451 &values);
6452 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 6453 return log_debug_errno(
15c591d1
LP
6454 SYNTHETIC_ERRNO(ENOTRECOVERABLE),
6455 "Failed to measure into PCR %u: %s",
6456 pcr_index,
6457 sym_Tss2_RC_Decode(rc));
6458
cb19bdae
LP
6459 /* Now, write what we just extended to the log, too. */
6460 (void) tpm2_userspace_log(log_fd, pcr_index, &values, event_type, description);
6461
15c591d1 6462 return 0;
0d7009d3 6463#else /* HAVE_OPENSSL */
f9a0ee75 6464 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
15c591d1
LP
6465#endif
6466}
15c591d1 6467
b52e9505
LP
6468const uint16_t tpm2_hash_algorithms[] = {
6469 TPM2_ALG_SHA1,
6470 TPM2_ALG_SHA256,
6471 TPM2_ALG_SHA384,
6472 TPM2_ALG_SHA512,
6473 0,
6474};
6475
6476assert_cc(ELEMENTSOF(tpm2_hash_algorithms) == TPM2_N_HASH_ALGORITHMS + 1);
6477
a4342701
LP
6478static size_t tpm2_hash_algorithm_index(uint16_t algorithm) {
6479 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++)
6480 if (tpm2_hash_algorithms[i] == algorithm)
6481 return i;
6482
6483 return SIZE_MAX;
6484}
6485
6486TPM2B_DIGEST *tpm2_pcr_prediction_result_get_hash(Tpm2PCRPredictionResult *result, uint16_t alg) {
6487 size_t alg_idx;
6488
6489 assert(result);
6490
6491 alg_idx = tpm2_hash_algorithm_index(alg);
6492 if (alg_idx == SIZE_MAX) /* Algorithm not known? */
6493 return NULL;
6494
6495 if (result->hash[alg_idx].size <= 0) /* No hash value for this algorithm? */
6496 return NULL;
6497
6498 return result->hash + alg_idx;
6499}
6500
6501void tpm2_pcr_prediction_done(Tpm2PCRPrediction *p) {
6502 assert(p);
6503
6504 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++)
6505 ordered_set_free(p->results[pcr]);
6506}
6507
6508static void tpm2_pcr_prediction_result_hash_func(const Tpm2PCRPredictionResult *banks, struct siphash *state) {
6509 assert(banks);
6510
6511 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++)
6512 siphash24_compress_safe(banks->hash[i].buffer, banks->hash[i].size, state);
6513}
6514
6515static int tpm2_pcr_prediction_result_compare_func(const Tpm2PCRPredictionResult *a, const Tpm2PCRPredictionResult *b) {
6516 int r;
6517
6518 assert(a);
6519 assert(b);
6520
6521 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
6522 r = memcmp_nn(a->hash[i].buffer, a->hash[i].size,
6523 b->hash[i].buffer, b->hash[i].size);
6524 if (r != 0)
6525 return r;
6526 }
6527
6528 return 0;
6529}
6530
6531DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
6532 tpm2_pcr_prediction_result_hash_ops,
6533 Tpm2PCRPredictionResult,
6534 tpm2_pcr_prediction_result_hash_func,
6535 tpm2_pcr_prediction_result_compare_func,
6536 Tpm2PCRPredictionResult,
6537 free);
6538
6539static Tpm2PCRPredictionResult *find_prediction_result_by_algorithm(OrderedSet *set, Tpm2PCRPredictionResult *result, size_t alg_idx) {
6540 Tpm2PCRPredictionResult *f;
6541
6542 assert(result);
6543 assert(alg_idx != SIZE_MAX);
6544
6545 f = ordered_set_get(set, result); /* Full match? */
6546 if (f)
6547 return f;
6548
6549 /* If this doesn't match full, then see if there an entry that at least matches by the relevant
6550 * algorithm (we are fine if predictions are "incomplete" in some algorithms) */
6551
6552 ORDERED_SET_FOREACH(f, set)
6553 if (memcmp_nn(result->hash[alg_idx].buffer, result->hash[alg_idx].size,
6554 f->hash[alg_idx].buffer, f->hash[alg_idx].size) == 0)
6555 return f;
6556
6557 return NULL;
6558}
6559
6560bool tpm2_pcr_prediction_equal(
6561 Tpm2PCRPrediction *a,
6562 Tpm2PCRPrediction *b,
6563 uint16_t algorithm) {
6564
6565 if (a == b)
6566 return true;
6567 if (!a || !b)
6568 return false;
6569
6570 if (a->pcrs != b->pcrs)
6571 return false;
6572
6573 size_t alg_idx = tpm2_hash_algorithm_index(algorithm);
6574 if (alg_idx == SIZE_MAX)
6575 return false;
6576
6577 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
6578 Tpm2PCRPredictionResult *banks;
6579
6580 ORDERED_SET_FOREACH(banks, a->results[pcr])
6581 if (!find_prediction_result_by_algorithm(b->results[pcr], banks, alg_idx))
6582 return false;
6583
6584 ORDERED_SET_FOREACH(banks, b->results[pcr])
6585 if (!find_prediction_result_by_algorithm(a->results[pcr], banks, alg_idx))
6586 return false;
6587 }
6588
6589 return true;
6590}
6591
6592int tpm2_pcr_prediction_to_json(
6593 const Tpm2PCRPrediction *prediction,
6594 uint16_t algorithm,
6595 JsonVariant **ret) {
6596
6597 _cleanup_(json_variant_unrefp) JsonVariant *aj = NULL;
6598 int r;
6599
6600 assert(prediction);
6601 assert(ret);
6602
6603 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
6604 _cleanup_(json_variant_unrefp) JsonVariant *vj = NULL;
6605 Tpm2PCRPredictionResult *banks;
6606
6607 if (!FLAGS_SET(prediction->pcrs, UINT32_C(1) << pcr))
6608 continue;
6609
6610 ORDERED_SET_FOREACH(banks, prediction->results[pcr]) {
6611
6612 TPM2B_DIGEST *hash = tpm2_pcr_prediction_result_get_hash(banks, algorithm);
6613 if (!hash)
6614 continue;
6615
6616 r = json_variant_append_arrayb(
6617 &vj,
6618 JSON_BUILD_HEX(hash->buffer, hash->size));
6619 if (r < 0)
6620 return log_error_errno(r, "Failed to append hash variant to JSON array: %m");
6621 }
6622
6623 if (!vj)
6624 continue;
6625
6626 r = json_variant_append_arrayb(
6627 &aj,
6628 JSON_BUILD_OBJECT(
6629 JSON_BUILD_PAIR_INTEGER("pcr", pcr),
6630 JSON_BUILD_PAIR_VARIANT("values", vj)));
6631 if (r < 0)
6632 return log_error_errno(r, "Failed to append PCR variants to JSON array: %m");
6633 }
6634
6635 if (!aj) {
6636 r = json_variant_new_array(&aj, NULL, 0);
6637 if (r < 0)
6638 return r;
6639 }
6640
6641 *ret = TAKE_PTR(aj);
6642 return 0;
6643}
6644
6645int tpm2_pcr_prediction_from_json(
6646 Tpm2PCRPrediction *prediction,
6647 uint16_t algorithm,
6648 JsonVariant *aj) {
6649
6650 int r;
6651
6652 assert(prediction);
6653
6654 size_t alg_index = tpm2_hash_algorithm_index(algorithm);
6655 assert(alg_index < TPM2_N_HASH_ALGORITHMS);
6656
6657 if (!json_variant_is_array(aj))
6658 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PCR variant array is not an array.");
6659
6660 JsonVariant *pcr;
6661 JSON_VARIANT_ARRAY_FOREACH(pcr, aj) {
6662 JsonVariant *nr, *values;
6663
6664 nr = json_variant_by_key(pcr, "pcr");
6665 if (!nr)
6666 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PCR array entry lacks PCR index field");
6667
6668 if (!json_variant_is_unsigned(nr) ||
6669 json_variant_unsigned(nr) >= TPM2_PCRS_MAX)
6670 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PCR array entry PCR index is not an integer in the range 0…23");
6671
6672 values = json_variant_by_key(pcr, "values");
6673 if (!values)
6674 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PCR array entry lacks values field");
6675
6676 if (!json_variant_is_array(values))
6677 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PCR array entry values field is not an array");
6678
6679 prediction->pcrs |= UINT32_C(1) << json_variant_unsigned(nr);
6680
6681 JsonVariant *v;
6682 JSON_VARIANT_ARRAY_FOREACH(v, values) {
6683 _cleanup_free_ void *buffer = NULL;
6684 size_t size;
6685
6686 r = json_variant_unhex(v, &buffer, &size);
6687 if (r < 0)
6688 return log_error_errno(r, "Failed to decode PCR policy array hash value");
6689
6690 if (size <= 0)
6691 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PCR policy array hash value is zero.");
6692
6693 if (size > sizeof_field(TPM2B_DIGEST, buffer))
6694 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PCR policy array hash value is too large.");
6695
6696 _cleanup_free_ Tpm2PCRPredictionResult *banks = new0(Tpm2PCRPredictionResult, 1);
6697 if (!banks)
6698 return log_oom();
6699
6700 memcpy(banks->hash[alg_index].buffer, buffer, size);
6701 banks->hash[alg_index].size = size;
6702
6703 r = ordered_set_ensure_put(prediction->results + json_variant_unsigned(nr), &tpm2_pcr_prediction_result_hash_ops, banks);
6704 if (r == -EEXIST) /* Let's allow duplicates */
6705 continue;
6706 if (r < 0)
6707 return log_error_errno(r, "Failed to insert result into set: %m");
6708
6709 TAKE_PTR(banks);
6710 }
6711 }
6712
6713 return 0;
6714}
6715
6716int tpm2_calculate_policy_super_pcr(
6717 Tpm2PCRPrediction *prediction,
6718 uint16_t algorithm,
6719 TPM2B_DIGEST *pcr_policy) {
6720
6721 int r;
6722
6723 assert_se(prediction);
6724 assert_se(pcr_policy);
6725
e423b40d 6726 /* Start with a zero policy if not specified otherwise. */
a4342701
LP
6727 TPM2B_DIGEST super_pcr_policy_digest = *pcr_policy;
6728
6729 /* First we look for all PCRs that have exactly one allowed hash value, and generate a single PolicyPCR policy from them */
6730 _cleanup_free_ Tpm2PCRValue *single_values = NULL;
6731 size_t n_single_values = 0;
6732 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
6733 if (!FLAGS_SET(prediction->pcrs, UINT32_C(1) << pcr))
6734 continue;
6735
6736 if (ordered_set_size(prediction->results[pcr]) != 1)
6737 continue;
6738
6739 log_debug("Including PCR %" PRIu32 " in single value PolicyPCR expression", pcr);
6740
6741 Tpm2PCRPredictionResult *banks = ASSERT_PTR(ordered_set_first(prediction->results[pcr]));
6742
6743 TPM2B_DIGEST *hash = tpm2_pcr_prediction_result_get_hash(banks, algorithm);
6744 if (!hash)
6745 continue;
6746
6747 if (!GREEDY_REALLOC(single_values, n_single_values + 1))
6748 return -ENOMEM;
6749
6750 single_values[n_single_values++] = TPM2_PCR_VALUE_MAKE(pcr, algorithm, *hash);
6751 }
6752
6753 if (n_single_values > 0) {
6754 /* Evolve policy based on the expected PCR value for what we found. */
6755 r = tpm2_calculate_policy_pcr(
6756 single_values,
6757 n_single_values,
6758 &super_pcr_policy_digest);
6759 if (r < 0)
6760 return r;
6761 }
6762
6763 /* Now deal with the PCRs for which we have variants, i.e. more than one allowed values */
6764 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
6765 _cleanup_free_ TPM2B_DIGEST *pcr_policy_digest_variants = NULL;
6766 size_t n_pcr_policy_digest_variants = 0;
6767 Tpm2PCRPredictionResult *banks;
6768
6769 if (!FLAGS_SET(prediction->pcrs, UINT32_C(1) << pcr))
6770 continue;
6771
6772 if (ordered_set_size(prediction->results[pcr]) <= 1) /* We only care for PCRs with 2 or more variants in this loop */
6773 continue;
6774
6775 if (ordered_set_size(prediction->results[pcr]) > 8)
6776 return log_error_errno(SYNTHETIC_ERRNO(E2BIG), "PCR policies with more than 8 alternatives per PCR are currently not supported.");
6777
6778 ORDERED_SET_FOREACH(banks, prediction->results[pcr]) {
6779 /* Start from the super PCR policy from the previous PCR we looked at so far. */
6780 TPM2B_DIGEST pcr_policy_digest = super_pcr_policy_digest;
6781
6782 TPM2B_DIGEST *hash = tpm2_pcr_prediction_result_get_hash(banks, algorithm);
6783 if (!hash)
6784 continue;
6785
6786 /* Evolve it based on the expected PCR value for this PCR */
6787 r = tpm2_calculate_policy_pcr(
6788 &TPM2_PCR_VALUE_MAKE(
6789 pcr,
6790 algorithm,
6791 *hash),
6792 /* n_pcr_values= */ 1,
6793 &pcr_policy_digest);
6794 if (r < 0)
6795 return r;
6796
6797 /* Store away this new variant */
6798 if (!GREEDY_REALLOC(pcr_policy_digest_variants, n_pcr_policy_digest_variants + 1))
6799 return log_oom();
6800
6801 pcr_policy_digest_variants[n_pcr_policy_digest_variants++] = pcr_policy_digest;
6802
6803 log_debug("Calculated PCR policy variant %zu for PCR %" PRIu32, n_pcr_policy_digest_variants, pcr);
6804 }
6805
6806 assert_se(n_pcr_policy_digest_variants >= 2);
6807 assert_se(n_pcr_policy_digest_variants <= 8);
6808
6809 /* Now combine all our variant into one OR policy */
6810 r = tpm2_calculate_policy_or(
6811 pcr_policy_digest_variants,
6812 n_pcr_policy_digest_variants,
6813 &super_pcr_policy_digest);
6814 if (r < 0)
6815 return r;
6816
6817 log_debug("Combined %zu variants in OR policy.", n_pcr_policy_digest_variants);
6818 }
6819
6820 *pcr_policy = super_pcr_policy_digest;
6821 return 0;
6822}
6823
6824int tpm2_policy_super_pcr(
6825 Tpm2Context *c,
6826 const Tpm2Handle *session,
6827 const Tpm2PCRPrediction *prediction,
6828 uint16_t algorithm) {
6829
6830 int r;
6831
6832 assert_se(c);
6833 assert_se(session);
6834 assert_se(prediction);
6835
6836 TPM2B_DIGEST previous_policy_digest = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
6837
6838 uint32_t single_value_pcrs = 0;
6839
6840 /* Look for all PCRs that have only a singled allowed hash value, and synthesize a single PolicyPCR policy item for them */
6841 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
6842 if (!FLAGS_SET(prediction->pcrs, UINT32_C(1) << pcr))
6843 continue;
6844
6845 if (ordered_set_size(prediction->results[pcr]) != 1)
6846 continue;
6847
6848 log_debug("Including PCR %" PRIu32 " in single value PolicyPCR expression", pcr);
6849
6850 single_value_pcrs |= UINT32_C(1) << pcr;
6851 }
6852
6853 if (single_value_pcrs != 0) {
6854 TPML_PCR_SELECTION pcr_selection;
6855 tpm2_tpml_pcr_selection_from_mask(single_value_pcrs, algorithm, &pcr_selection);
6856
6857 _cleanup_free_ TPM2B_DIGEST *current_policy_digest = NULL;
6858 r = tpm2_policy_pcr(
6859 c,
6860 session,
6861 &pcr_selection,
6862 &current_policy_digest);
6863 if (r < 0)
6864 return r;
6865
6866 previous_policy_digest = *current_policy_digest;
6867 }
6868
6869 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
6870 size_t n_branches;
6871
6872 if (!FLAGS_SET(prediction->pcrs, UINT32_C(1) << pcr))
6873 continue;
6874
6875 n_branches = ordered_set_size(prediction->results[pcr]);
6876 if (n_branches < 1 || n_branches > 8)
6877 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Number of variants per PCR not in range 1…8");
6878
6879 if (n_branches == 1) /* Single choice PCRs are already covered by the loop above */
6880 continue;
6881
6882 log_debug("Submitting PCR/OR policy for PCR %" PRIu32, pcr);
6883
6884 TPML_PCR_SELECTION pcr_selection;
6885 tpm2_tpml_pcr_selection_from_mask(UINT32_C(1) << pcr, algorithm, &pcr_selection);
6886
6887 _cleanup_free_ TPM2B_DIGEST *current_policy_digest = NULL;
6888 r = tpm2_policy_pcr(
6889 c,
6890 session,
6891 &pcr_selection,
6892 &current_policy_digest);
6893 if (r < 0)
6894 return r;
6895
6896 _cleanup_free_ TPM2B_DIGEST *branches = NULL;
6897 branches = new0(TPM2B_DIGEST, n_branches);
6898 if (!branches)
6899 return log_oom();
6900
6901 Tpm2PCRPredictionResult *banks;
6902 size_t i = 0;
6903 ORDERED_SET_FOREACH(banks, prediction->results[pcr]) {
6904 TPM2B_DIGEST pcr_policy_digest = previous_policy_digest;
6905
6906 TPM2B_DIGEST *hash = tpm2_pcr_prediction_result_get_hash(banks, algorithm);
6907 if (!hash)
6908 continue;
6909
6910 /* Evolve it based on the expected PCR value for this PCR */
6911 r = tpm2_calculate_policy_pcr(
6912 &TPM2_PCR_VALUE_MAKE(
6913 pcr,
6914 algorithm,
6915 *hash),
6916 /* n_pcr_values= */ 1,
6917 &pcr_policy_digest);
6918 if (r < 0)
6919 return r;
6920
6921 branches[i++] = pcr_policy_digest;
6922 }
6923
6924 assert_se(i == n_branches);
6925
6926 current_policy_digest = mfree(current_policy_digest);
6927 r = tpm2_policy_or(
6928 c,
6929 session,
6930 branches,
6931 n_branches,
6932 &current_policy_digest);
6933 if (r < 0)
6934 return r;
6935
6936 previous_policy_digest = *current_policy_digest;
6937 }
6938
6939 return 0;
6940}
6941
6942void tpm2_pcrlock_policy_done(Tpm2PCRLockPolicy *data) {
6943 assert(data);
6944
6945 data->prediction_json = json_variant_unref(data->prediction_json);
6946 tpm2_pcr_prediction_done(&data->prediction);
6947 iovec_done(&data->nv_handle);
6948 iovec_done(&data->nv_public);
6949 iovec_done(&data->srk_handle);
6950 iovec_done(&data->pin_public);
6951 iovec_done(&data->pin_private);
6952}
6953
6954static int json_dispatch_tpm2_algorithm(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
6955 uint16_t *algorithm = ASSERT_PTR(userdata);
6956 int r;
6957
6958 r = tpm2_hash_alg_from_string(json_variant_string(variant));
6959 if (r < 0 || tpm2_hash_algorithm_index(r) == SIZE_MAX)
6960 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid hash algorithm: %s", json_variant_string(variant));
6961
6962 *algorithm = r;
6963 return 0;
6964}
6965
6966int tpm2_pcrlock_search_file(const char *path, FILE **ret_file, char **ret_path) {
6967 static const char search[] =
6968 "/run/systemd\0"
6969 "/var/lib/systemd\0";
6970
6971 int r;
6972
6973 if (!path)
6974 path = "pcrlock.json";
6975
6976 r = search_and_fopen_nulstr(path, ret_file ? "re" : NULL, NULL, search, ret_file, ret_path);
6977 if (r < 0)
6978 return log_debug_errno(r, "Failed to find TPM2 pcrlock policy file '%s': %m", path);
6979
6980 return 0;
6981}
6982
d37c312b
LP
6983int tpm2_pcrlock_policy_from_json(
6984 JsonVariant *v,
6985 Tpm2PCRLockPolicy *ret_policy) {
6986
6987 /* We use a type check of _JSON_VARIANT_TYPE_INVALID for the integer fields to allow
6988 * json_dispatch_uint32() to parse strings as integers to work around the integer type weakness of
6989 * JSON's design. */
6990 JsonDispatch policy_dispatch[] = {
6991 { "pcrBank", JSON_VARIANT_STRING, json_dispatch_tpm2_algorithm, offsetof(Tpm2PCRLockPolicy, algorithm), JSON_MANDATORY },
6992 { "pcrValues", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(Tpm2PCRLockPolicy, prediction_json), JSON_MANDATORY },
6993 { "nvIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(Tpm2PCRLockPolicy, nv_index), JSON_MANDATORY },
6994 { "nvHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_handle), JSON_MANDATORY },
6995 { "nvPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, nv_public), JSON_MANDATORY },
6996 { "srkHandle", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, srk_handle), JSON_MANDATORY },
6997 { "pinPublic", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_public), JSON_MANDATORY },
6998 { "pinPrivate", JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(Tpm2PCRLockPolicy, pin_private), JSON_MANDATORY },
6999 {}
7000 };
7001
7002 _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
7003 int r;
7004
7005 assert(v);
7006 assert(ret_policy);
7007
7008 r = json_dispatch(v, policy_dispatch, JSON_LOG, &policy);
7009 if (r < 0)
7010 return r;
7011
7012 r = tpm2_pcr_prediction_from_json(&policy.prediction, policy.algorithm, policy.prediction_json);
7013 if (r < 0)
7014 return r;
7015
7016 *ret_policy = TAKE_STRUCT(policy);
7017 return 1;
7018}
7019
a4342701
LP
7020int tpm2_pcrlock_policy_load(
7021 const char *path,
7022 Tpm2PCRLockPolicy *ret_policy) {
7023
7024 _cleanup_free_ char *discovered_path = NULL;
7025 _cleanup_fclose_ FILE *f = NULL;
7026 int r;
7027
7028 r = tpm2_pcrlock_search_file(path, &f, &discovered_path);
7029 if (r == -ENOENT) {
7030 *ret_policy = (Tpm2PCRLockPolicy) {};
7031 return 0;
7032 }
7033 if (r < 0)
7034 return log_error_errno(r, "Failed to load TPM2 pcrlock policy file: %m");
7035
d37c312b 7036 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
a4342701
LP
7037 r = json_parse_file(
7038 f,
7039 discovered_path,
7040 /* flags = */ 0,
d37c312b 7041 &v,
a4342701
LP
7042 /* ret_line= */ NULL,
7043 /* ret_column= */ NULL);
7044 if (r < 0)
7045 return log_error_errno(r, "Failed to parse existing pcrlock policy file '%s': %m", discovered_path);
7046
d37c312b
LP
7047 return tpm2_pcrlock_policy_from_json(v, ret_policy);
7048}
a4342701 7049
d37c312b
LP
7050static int pcrlock_policy_load_credential(
7051 const char *name,
7052 const struct iovec *data,
7053 Tpm2PCRLockPolicy *ret) {
a4342701 7054
d37c312b
LP
7055 _cleanup_free_ char *c = NULL;
7056 int r;
7057
7058 assert(name);
7059
7060 c = strdup(name);
7061 if (!c)
7062 return log_oom();
7063
7064 ascii_strlower(c); /* Lowercase, to match what we did at encryption time */
7065
7066 _cleanup_(iovec_done) struct iovec decoded = {};
7067 r = decrypt_credential_and_warn(
7068 c,
7069 now(CLOCK_REALTIME),
7070 /* tpm2_device= */ NULL,
7071 /* tpm2_signature_path= */ NULL,
48d67957 7072 UID_INVALID,
d37c312b
LP
7073 data,
7074 CREDENTIAL_ALLOW_NULL,
7075 &decoded);
a4342701
LP
7076 if (r < 0)
7077 return r;
7078
d37c312b
LP
7079 if (memchr(decoded.iov_base, 0, decoded.iov_len))
7080 return log_error_errno(r, "Credential '%s' contains embedded NUL byte, refusing.", name);
7081
7082 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
7083 r = json_parse(decoded.iov_base,
7084 /* flags= */ 0,
7085 &v,
7086 /* ret_line= */ NULL,
7087 /* ret_column= */ NULL);
7088 if (r < 0)
7089 return log_error_errno(r, "Failed to parse pcrlock policy: %m");
7090
7091 r = tpm2_pcrlock_policy_from_json(v, ret);
a4342701
LP
7092 if (r < 0)
7093 return r;
7094
d37c312b
LP
7095 return 0;
7096}
7097
7098int tpm2_pcrlock_policy_from_credentials(
7099 const struct iovec *srk,
7100 const struct iovec *nv,
7101 Tpm2PCRLockPolicy *ret) {
7102
7103 _cleanup_close_ int dfd = -EBADF;
7104 int r;
7105
7106 /* During boot we'll not have access to the pcrlock.json file in /var/. In order to support
7107 * pcrlock-bound root file systems we'll store a copy of the JSON data, wrapped in an (plaintext)
7108 * credential in the ESP or XBOOTLDR partition. There might be multiple of those however (because of
7109 * multi-boot), hence we use the SRK and NV data from the LUKS2 header as search key, and parse all
7110 * such JSON policies until we find a matching one. */
7111
7112 const char *cp = secure_getenv("SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY") ?: ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY;
7113
7114 dfd = open(cp, O_CLOEXEC|O_DIRECTORY);
7115 if (dfd < 0) {
7116 if (errno == ENOENT) {
7117 log_debug("No encrypted system credentials passed.");
7118 return 0;
7119 }
7120
77924eab 7121 return log_error_errno(errno, "Failed to open system credentials directory.");
d37c312b
LP
7122 }
7123
7124 _cleanup_free_ DirectoryEntries *de = NULL;
7125 r = readdir_all(dfd, RECURSE_DIR_IGNORE_DOT, &de);
7126 if (r < 0)
7127 return log_error_errno(r, "Failed to enumerate system credentials: %m");
7128
7129 FOREACH_ARRAY(i, de->entries, de->n_entries) {
7130 _cleanup_(iovec_done) struct iovec data = {};
7131 struct dirent *d = *i;
7132
7133 if (!startswith_no_case(d->d_name, "pcrlock.")) /* VFAT is case-insensitive, hence don't be too strict here */
7134 continue;
7135
7136 r = read_full_file_full(
7137 dfd, d->d_name,
7138 /* offset= */ UINT64_MAX,
7139 /* size= */ CREDENTIAL_ENCRYPTED_SIZE_MAX,
7140 READ_FULL_FILE_UNBASE64|READ_FULL_FILE_FAIL_WHEN_LARGER,
7141 /* bind_name= */ NULL,
7142 (char**) &data.iov_base,
7143 &data.iov_len);
7144 if (r == -ENOENT)
7145 continue;
7146 if (r < 0) {
7147 log_warning_errno(r, "Failed to read credentials file %s/%s, skipping: %m", ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, d->d_name);
7148 continue;
7149 }
7150
7151 _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy loaded_policy = {};
7152 r = pcrlock_policy_load_credential(
7153 d->d_name,
7154 &data,
7155 &loaded_policy);
7156 if (r < 0) {
7157 log_warning_errno(r, "Loading of pcrlock policy from credential '%s/%s' failed, skipping.", ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, d->d_name);
7158 continue;
7159 }
7160
7161 if ((!srk || iovec_memcmp(srk, &loaded_policy.srk_handle) == 0) &&
7162 (!nv || iovec_memcmp(nv, &loaded_policy.nv_handle) == 0)) {
7163 *ret = TAKE_STRUCT(loaded_policy);
7164 return 1;
7165 }
7166 }
7167
7168 log_info("No pcrlock policy found among system credentials.");
7169 *ret = (Tpm2PCRLockPolicy) {};
7170 return 0;
a4342701 7171}
a8d8d34b
LP
7172
7173int tpm2_load_public_key_file(const char *path, TPM2B_PUBLIC *ret) {
7174 _cleanup_free_ char *device_key_buffer = NULL;
7175 TPM2B_PUBLIC device_key_public = {};
7176 size_t device_key_buffer_size;
7177 TSS2_RC rc;
7178 int r;
7179
7180 assert(path);
7181 assert(ret);
7182
7183 r = dlopen_tpm2();
7184 if (r < 0)
7185 return log_debug_errno(r, "TPM2 support not installed: %m");
7186
7187 r = read_full_file(path, &device_key_buffer, &device_key_buffer_size);
7188 if (r < 0)
7189 return log_error_errno(r, "Failed to read device key from file '%s': %m", path);
7190
7191 size_t offset = 0;
7192 rc = sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal(
7193 (uint8_t*) device_key_buffer,
7194 device_key_buffer_size,
7195 &offset,
7196 &device_key_public);
7197 if (rc != TSS2_RC_SUCCESS)
7198 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
7199 "Could not unmarshal public key from file.");
7200
7201 assert(offset <= device_key_buffer_size);
7202 if (offset != device_key_buffer_size)
7203 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
7204 "Found %zu bytes of trailing garbage in public key file.",
7205 device_key_buffer_size - offset);
7206
7207 *ret = device_key_public;
7208 return 0;
7209}
cb835a2e
LP
7210
7211int tpm2_hmac_key_from_pin(Tpm2Context *c, const Tpm2Handle *session, const TPM2B_AUTH *pin, Tpm2Handle **ret) {
7212 int r;
7213
7214 assert(c);
7215 assert(pin);
7216 assert(ret);
7217
7218 log_debug("Converting PIN into TPM2 HMAC-SHA256 object.");
7219
7220 /* Load the PIN (which we have stored in the "auth" TPM2B_AUTH) into the TPM as an HMAC key so that
7221 * we can use it in a TPM2_PolicySigned() to write to the nvindex. For that we'll prep a pair of
7222 * TPM2B_PUBLIC and TPM2B_SENSITIVE that defines an HMAC-SHA256 keyed hash function, and initialize
c309b9e9 7223 * it based on the provided PIN data. */
cb835a2e
LP
7224
7225 TPM2B_PUBLIC auth_hmac_public = {
7226 .publicArea = {
7227 .type = TPM2_ALG_KEYEDHASH,
7228 .nameAlg = TPM2_ALG_SHA256,
7229 .objectAttributes = TPMA_OBJECT_SIGN_ENCRYPT,
7230 .parameters.keyedHashDetail.scheme = {
7231 .scheme = TPM2_ALG_HMAC,
7232 .details.hmac.hashAlg = TPM2_ALG_SHA256,
7233 },
7234 .unique.keyedHash.size = SHA256_DIGEST_SIZE,
7235 },
7236 };
7237
7238 TPM2B_SENSITIVE auth_hmac_private = {
7239 .sensitiveArea = {
7240 .sensitiveType = TPM2_ALG_KEYEDHASH,
7241 .sensitive.bits.size = pin->size,
7242 .seedValue.size = SHA256_DIGEST_SIZE,
7243 },
7244 };
7245
7246 /* Copy in the key data */
7247 memcpy_safe(auth_hmac_private.sensitiveArea.sensitive.bits.buffer, pin->buffer, pin->size);
7248
7249 /* NB: We initialize the seed of the TPMT_SENSITIVE structure to all zeroes, since we want a stable
7250 * "name" of the PIN object */
7251
7252 /* Now calculate the "unique" field for the public area, based on the sensitive data, according to
7253 * the algorithm in the TPM2 spec, part 1, Section 27.5.3.2 */
7254 struct iovec sensitive_data[] = {
7255 IOVEC_MAKE(auth_hmac_private.sensitiveArea.seedValue.buffer, auth_hmac_private.sensitiveArea.seedValue.size),
7256 IOVEC_MAKE(auth_hmac_private.sensitiveArea.sensitive.bits.buffer, auth_hmac_private.sensitiveArea.sensitive.bits.size),
7257 };
7258 r = tpm2_digest_many(
7259 auth_hmac_public.publicArea.nameAlg,
7260 &auth_hmac_public.publicArea.unique.keyedHash,
7261 sensitive_data,
7262 ELEMENTSOF(sensitive_data),
7263 /* extend= */ false);
7264 if (r < 0)
7265 return r;
7266
7267 /* And now load the public/private parts into the TPM and get a handle back */
7268 r = tpm2_load_external(
7269 c,
7270 session,
7271 &auth_hmac_public,
7272 &auth_hmac_private,
7273 ret);
7274 if (r < 0)
7275 return log_error_errno(r, "Failed to load PIN into TPM2: %m");
7276
7277 return 0;
7278}
a4342701
LP
7279#endif
7280
c69bd0ab
DS
7281char *tpm2_pcr_mask_to_string(uint32_t mask) {
7282 _cleanup_free_ char *s = NULL;
7283
7284 FOREACH_PCR_IN_MASK(n, mask)
7285 if (strextendf_with_separator(&s, "+", "%d", n) < 0)
7286 return NULL;
7287
7288 if (!s)
7289 return strdup("");
7290
7291 return TAKE_PTR(s);
7292}
7293
4436081e
LP
7294int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret) {
7295 _cleanup_(json_variant_unrefp) JsonVariant *a = NULL;
4436081e
LP
7296 int r;
7297
c22dcd67
YW
7298 assert(ret);
7299
7300 for (size_t i = 0; i < TPM2_PCRS_MAX; i++) {
7301 _cleanup_(json_variant_unrefp) JsonVariant *e = NULL;
7302
4436081e
LP
7303 if ((pcr_mask & (UINT32_C(1) << i)) == 0)
7304 continue;
7305
c22dcd67 7306 r = json_variant_new_integer(&e, i);
4436081e 7307 if (r < 0)
c22dcd67 7308 return r;
4436081e 7309
c22dcd67
YW
7310 r = json_variant_append_array(&a, e);
7311 if (r < 0)
7312 return r;
4436081e
LP
7313 }
7314
c22dcd67
YW
7315 if (!a)
7316 return json_variant_new_array(ret, NULL, 0);
4436081e 7317
c22dcd67
YW
7318 *ret = TAKE_PTR(a);
7319 return 0;
4436081e 7320}
8de8ec88
LP
7321
7322int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret) {
7323 JsonVariant *e;
7324 uint32_t mask = 0;
7325
7326 if (!json_variant_is_array(v))
7327 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR array is not a JSON array.");
7328
7329 JSON_VARIANT_ARRAY_FOREACH(e, v) {
7330 uint64_t u;
7331
7332 if (!json_variant_is_unsigned(e))
7333 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR is not an unsigned integer.");
7334
7335 u = json_variant_unsigned(e);
7336 if (u >= TPM2_PCRS_MAX)
7337 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR number out of range: %" PRIu64, u);
7338
7339 mask |= UINT32_C(1) << u;
7340 }
7341
7342 if (ret)
7343 *ret = mask;
7344
7345 return 0;
7346}
4436081e 7347
5e521624
LP
7348int tpm2_make_luks2_json(
7349 int keyslot,
f0f4fcae 7350 uint32_t hash_pcr_mask,
07697bfe 7351 uint16_t pcr_bank,
8d042bc4 7352 const struct iovec *pubkey,
f0f4fcae 7353 uint32_t pubkey_pcr_mask,
2b92a672 7354 uint16_t primary_alg,
8d042bc4
LP
7355 const struct iovec *blob,
7356 const struct iovec *policy_hash,
7357 const struct iovec *salt,
7358 const struct iovec *srk,
d37c312b 7359 const struct iovec *pcrlock_nv,
6c7a1681 7360 TPM2Flags flags,
5e521624
LP
7361 JsonVariant **ret) {
7362
f0f4fcae 7363 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *hmj = NULL, *pkmj = NULL;
5e521624 7364 _cleanup_free_ char *keyslot_as_string = NULL;
5e521624
LP
7365 int r;
7366
8d042bc4
LP
7367 assert(iovec_is_valid(pubkey));
7368 assert(iovec_is_valid(blob));
7369 assert(iovec_is_valid(policy_hash));
5e521624
LP
7370
7371 if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
7372 return -ENOMEM;
7373
f0f4fcae 7374 r = tpm2_make_pcr_json_array(hash_pcr_mask, &hmj);
5e521624 7375 if (r < 0)
4436081e 7376 return r;
5e521624 7377
f0f4fcae
LP
7378 if (pubkey_pcr_mask != 0) {
7379 r = tpm2_make_pcr_json_array(pubkey_pcr_mask, &pkmj);
7380 if (r < 0)
7381 return r;
7382 }
7383
7384 /* Note: We made the mistake of using "-" in the field names, which isn't particular compatible with
7385 * other programming languages. Let's not make things worse though, i.e. future additions to the JSON
7386 * object should use "_" rather than "-" in field names. */
7387
5e521624
LP
7388 r = json_build(&v,
7389 JSON_BUILD_OBJECT(
0cdf6b14 7390 JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-tpm2")),
5e521624 7391 JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
8d042bc4 7392 JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_IOVEC_BASE64(blob)),
f0f4fcae 7393 JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(hmj)),
360198ef
LP
7394 JSON_BUILD_PAIR_CONDITION(pcr_bank != 0 && tpm2_hash_alg_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_hash_alg_to_string(pcr_bank))),
7395 JSON_BUILD_PAIR_CONDITION(primary_alg != 0 && tpm2_asym_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_asym_alg_to_string(primary_alg))),
8d042bc4 7396 JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_IOVEC_HEX(policy_hash)),
f0f4fcae 7397 JSON_BUILD_PAIR("tpm2-pin", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PIN)),
07e89d50 7398 JSON_BUILD_PAIR("tpm2_pcrlock", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PCRLOCK)),
f0f4fcae 7399 JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey_pcrs", JSON_BUILD_VARIANT(pkmj)),
3f240217 7400 JSON_BUILD_PAIR_CONDITION(iovec_is_set(pubkey), "tpm2_pubkey", JSON_BUILD_IOVEC_BASE64(pubkey)),
8d042bc4 7401 JSON_BUILD_PAIR_CONDITION(iovec_is_set(salt), "tpm2_salt", JSON_BUILD_IOVEC_BASE64(salt)),
d37c312b
LP
7402 JSON_BUILD_PAIR_CONDITION(iovec_is_set(srk), "tpm2_srk", JSON_BUILD_IOVEC_BASE64(srk)),
7403 JSON_BUILD_PAIR_CONDITION(iovec_is_set(pcrlock_nv), "tpm2_pcrlock_nv", JSON_BUILD_IOVEC_BASE64(pcrlock_nv))));
5e521624
LP
7404 if (r < 0)
7405 return r;
7406
7407 if (ret)
7408 *ret = TAKE_PTR(v);
7409
7410 return keyslot;
7411}
07697bfe 7412
fdf6c27c
LP
7413int tpm2_parse_luks2_json(
7414 JsonVariant *v,
7415 int *ret_keyslot,
7416 uint32_t *ret_hash_pcr_mask,
7417 uint16_t *ret_pcr_bank,
8d042bc4 7418 struct iovec *ret_pubkey,
fdf6c27c
LP
7419 uint32_t *ret_pubkey_pcr_mask,
7420 uint16_t *ret_primary_alg,
8d042bc4
LP
7421 struct iovec *ret_blob,
7422 struct iovec *ret_policy_hash,
7423 struct iovec *ret_salt,
7424 struct iovec *ret_srk,
d37c312b 7425 struct iovec *ret_pcrlock_nv,
fdf6c27c
LP
7426 TPM2Flags *ret_flags) {
7427
d37c312b 7428 _cleanup_(iovec_done) struct iovec blob = {}, policy_hash = {}, pubkey = {}, salt = {}, srk = {}, pcrlock_nv = {};
fdf6c27c
LP
7429 uint32_t hash_pcr_mask = 0, pubkey_pcr_mask = 0;
7430 uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */
7431 uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
7432 int r, keyslot = -1;
7433 TPM2Flags flags = 0;
7434 JsonVariant *w;
7435
7436 assert(v);
7437
7438 if (ret_keyslot) {
7439 keyslot = cryptsetup_get_keyslot_from_token(v);
7440 if (keyslot < 0) {
7441 /* Return a recognizable error when parsing this field, so that callers can handle parsing
7442 * errors of the keyslots field gracefully, since it's not 'owned' by us, but by the LUKS2
7443 * spec */
7444 log_debug_errno(keyslot, "Failed to extract keyslot index from TPM2 JSON data token, skipping: %m");
7445 return -EUCLEAN;
7446 }
7447 }
7448
7449 w = json_variant_by_key(v, "tpm2-pcrs");
7450 if (!w)
7451 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-pcrs' field.");
7452
7453 r = tpm2_parse_pcr_json_array(w, &hash_pcr_mask);
7454 if (r < 0)
7455 return log_debug_errno(r, "Failed to parse TPM2 PCR mask: %m");
7456
7457 /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded
7458 * to SHA256. */
7459 w = json_variant_by_key(v, "tpm2-pcr-bank");
7460 if (w) {
7461 /* The PCR bank field is optional */
7462
7463 if (!json_variant_is_string(w))
7464 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR bank is not a string.");
7465
7bfe0a48 7466 r = tpm2_hash_alg_from_string(json_variant_string(w));
fdf6c27c
LP
7467 if (r < 0)
7468 return log_debug_errno(r, "TPM2 PCR bank invalid or not supported: %s", json_variant_string(w));
7469
7470 pcr_bank = r;
7471 }
7472
7473 /* The primary key algorithm field is optional, since it was also added in systemd 250 only. Before
7474 * the algorithm was hardcoded to ECC. */
7475 w = json_variant_by_key(v, "tpm2-primary-alg");
7476 if (w) {
7477 /* The primary key algorithm is optional */
7478
7479 if (!json_variant_is_string(w))
7480 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 primary key algorithm is not a string.");
7481
7bfe0a48 7482 r = tpm2_asym_alg_from_string(json_variant_string(w));
fdf6c27c 7483 if (r < 0)
7bfe0a48 7484 return log_debug_errno(r, "TPM2 asymmetric algorithm invalid or not supported: %s", json_variant_string(w));
fdf6c27c
LP
7485
7486 primary_alg = r;
7487 }
7488
7489 w = json_variant_by_key(v, "tpm2-blob");
7490 if (!w)
7491 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-blob' field.");
7492
8d042bc4 7493 r = json_variant_unbase64_iovec(w, &blob);
fdf6c27c
LP
7494 if (r < 0)
7495 return log_debug_errno(r, "Invalid base64 data in 'tpm2-blob' field.");
7496
7497 w = json_variant_by_key(v, "tpm2-policy-hash");
7498 if (!w)
7499 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-policy-hash' field.");
7500
8d042bc4 7501 r = json_variant_unhex_iovec(w, &policy_hash);
fdf6c27c
LP
7502 if (r < 0)
7503 return log_debug_errno(r, "Invalid base64 data in 'tpm2-policy-hash' field.");
7504
7505 w = json_variant_by_key(v, "tpm2-pin");
7506 if (w) {
7507 if (!json_variant_is_boolean(w))
7508 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PIN policy is not a boolean.");
7509
7510 SET_FLAG(flags, TPM2_FLAGS_USE_PIN, json_variant_boolean(w));
7511 }
7512
07e89d50 7513 w = json_variant_by_key(v, "tpm2_pcrlock");
a4342701
LP
7514 if (w) {
7515 if (!json_variant_is_boolean(w))
7516 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 pclock policy is not a boolean.");
7517
7518 SET_FLAG(flags, TPM2_FLAGS_USE_PCRLOCK, json_variant_boolean(w));
7519 }
7520
aae6eb96
WR
7521 w = json_variant_by_key(v, "tpm2_salt");
7522 if (w) {
8d042bc4 7523 r = json_variant_unbase64_iovec(w, &salt);
aae6eb96
WR
7524 if (r < 0)
7525 return log_debug_errno(r, "Invalid base64 data in 'tpm2_salt' field.");
7526 }
7527
fdf6c27c
LP
7528 w = json_variant_by_key(v, "tpm2_pubkey_pcrs");
7529 if (w) {
7530 r = tpm2_parse_pcr_json_array(w, &pubkey_pcr_mask);
7531 if (r < 0)
7532 return r;
7533 }
7534
7535 w = json_variant_by_key(v, "tpm2_pubkey");
7536 if (w) {
8d042bc4 7537 r = json_variant_unbase64_iovec(w, &pubkey);
fdf6c27c
LP
7538 if (r < 0)
7539 return log_debug_errno(r, "Failed to decode PCR public key.");
7540 } else if (pubkey_pcr_mask != 0)
7541 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Public key PCR mask set, but not public key included in JSON data, refusing.");
7542
acbb504e
WR
7543 w = json_variant_by_key(v, "tpm2_srk");
7544 if (w) {
8d042bc4 7545 r = json_variant_unbase64_iovec(w, &srk);
acbb504e
WR
7546 if (r < 0)
7547 return log_debug_errno(r, "Invalid base64 data in 'tpm2_srk' field.");
7548 }
7549
d37c312b
LP
7550 w = json_variant_by_key(v, "tpm2_pcrlock_nv");
7551 if (w) {
7552 r = json_variant_unbase64_iovec(w, &pcrlock_nv);
7553 if (r < 0)
7554 return log_debug_errno(r, "Invalid base64 data in 'tpm2_pcrlock_nv' field.");
7555 }
7556
fdf6c27c
LP
7557 if (ret_keyslot)
7558 *ret_keyslot = keyslot;
7559 if (ret_hash_pcr_mask)
7560 *ret_hash_pcr_mask = hash_pcr_mask;
7561 if (ret_pcr_bank)
7562 *ret_pcr_bank = pcr_bank;
7563 if (ret_pubkey)
8d042bc4 7564 *ret_pubkey = TAKE_STRUCT(pubkey);
fdf6c27c
LP
7565 if (ret_pubkey_pcr_mask)
7566 *ret_pubkey_pcr_mask = pubkey_pcr_mask;
7567 if (ret_primary_alg)
7568 *ret_primary_alg = primary_alg;
7569 if (ret_blob)
8d042bc4 7570 *ret_blob = TAKE_STRUCT(blob);
fdf6c27c 7571 if (ret_policy_hash)
8d042bc4 7572 *ret_policy_hash = TAKE_STRUCT(policy_hash);
aae6eb96 7573 if (ret_salt)
8d042bc4 7574 *ret_salt = TAKE_STRUCT(salt);
8d042bc4
LP
7575 if (ret_srk)
7576 *ret_srk = TAKE_STRUCT(srk);
d37c312b
LP
7577 if (ret_pcrlock_nv)
7578 *ret_pcrlock_nv = TAKE_STRUCT(pcrlock_nv);
7579 if (ret_flags)
7580 *ret_flags = flags;
fdf6c27c
LP
7581 return 0;
7582}
7583
c9df1fb1 7584int tpm2_hash_alg_to_size(uint16_t alg) {
7354a7cc
DS
7585 switch (alg) {
7586 case TPM2_ALG_SHA1:
c9df1fb1 7587 return 20;
7354a7cc 7588 case TPM2_ALG_SHA256:
c9df1fb1 7589 return 32;
7354a7cc 7590 case TPM2_ALG_SHA384:
c9df1fb1 7591 return 48;
7354a7cc 7592 case TPM2_ALG_SHA512:
c9df1fb1 7593 return 64;
7354a7cc
DS
7594 default:
7595 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown hash algorithm id 0x%" PRIx16, alg);
7596 }
c9df1fb1
DS
7597}
7598
7bfe0a48 7599const char *tpm2_hash_alg_to_string(uint16_t alg) {
7354a7cc
DS
7600 switch (alg) {
7601 case TPM2_ALG_SHA1:
07697bfe 7602 return "sha1";
7354a7cc 7603 case TPM2_ALG_SHA256:
98193c39 7604 return "sha256";
7354a7cc 7605 case TPM2_ALG_SHA384:
98193c39 7606 return "sha384";
7354a7cc 7607 case TPM2_ALG_SHA512:
98193c39 7608 return "sha512";
7354a7cc
DS
7609 default:
7610 log_debug("Unknown hash algorithm id 0x%" PRIx16, alg);
7611 return NULL;
7612 }
07697bfe
LP
7613}
7614
7bfe0a48
DS
7615int tpm2_hash_alg_from_string(const char *alg) {
7616 if (strcaseeq_ptr(alg, "sha1"))
07697bfe 7617 return TPM2_ALG_SHA1;
7bfe0a48 7618 if (strcaseeq_ptr(alg, "sha256"))
98193c39 7619 return TPM2_ALG_SHA256;
7bfe0a48 7620 if (strcaseeq_ptr(alg, "sha384"))
98193c39 7621 return TPM2_ALG_SHA384;
7bfe0a48 7622 if (strcaseeq_ptr(alg, "sha512"))
98193c39 7623 return TPM2_ALG_SHA512;
240774f5 7624 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown hash algorithm name '%s'", alg);
07697bfe 7625}
2b92a672 7626
7bfe0a48 7627const char *tpm2_asym_alg_to_string(uint16_t alg) {
7354a7cc
DS
7628 switch (alg) {
7629 case TPM2_ALG_ECC:
2b92a672 7630 return "ecc";
7354a7cc 7631 case TPM2_ALG_RSA:
2b92a672 7632 return "rsa";
7354a7cc
DS
7633 default:
7634 log_debug("Unknown asymmetric algorithm id 0x%" PRIx16, alg);
7635 return NULL;
7636 }
2b92a672
LP
7637}
7638
7bfe0a48 7639int tpm2_asym_alg_from_string(const char *alg) {
f92ebc86 7640 if (strcaseeq_ptr(alg, "ecc"))
2b92a672 7641 return TPM2_ALG_ECC;
f92ebc86 7642 if (strcaseeq_ptr(alg, "rsa"))
2b92a672 7643 return TPM2_ALG_RSA;
240774f5 7644 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown asymmetric algorithm name '%s'", alg);
2b92a672 7645}
ba578556 7646
2d784782
DS
7647const char *tpm2_sym_alg_to_string(uint16_t alg) {
7648 switch (alg) {
7649#if HAVE_TPM2
7650 case TPM2_ALG_AES:
7651 return "aes";
7652#endif
7653 default:
7654 log_debug("Unknown symmetric algorithm id 0x%" PRIx16, alg);
7655 return NULL;
7656 }
7657}
7658
7659int tpm2_sym_alg_from_string(const char *alg) {
7660#if HAVE_TPM2
7661 if (strcaseeq_ptr(alg, "aes"))
7662 return TPM2_ALG_AES;
7663#endif
7664 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown symmetric algorithm name '%s'", alg);
7665}
7666
7667const char *tpm2_sym_mode_to_string(uint16_t mode) {
7668 switch (mode) {
7669#if HAVE_TPM2
7670 case TPM2_ALG_CTR:
7671 return "ctr";
7672 case TPM2_ALG_OFB:
7673 return "ofb";
7674 case TPM2_ALG_CBC:
7675 return "cbc";
7676 case TPM2_ALG_CFB:
7677 return "cfb";
7678 case TPM2_ALG_ECB:
7679 return "ecb";
7680#endif
7681 default:
7682 log_debug("Unknown symmetric mode id 0x%" PRIx16, mode);
7683 return NULL;
7684 }
7685}
7686
7687int tpm2_sym_mode_from_string(const char *mode) {
7688#if HAVE_TPM2
7689 if (strcaseeq_ptr(mode, "ctr"))
7690 return TPM2_ALG_CTR;
7691 if (strcaseeq_ptr(mode, "ofb"))
7692 return TPM2_ALG_OFB;
7693 if (strcaseeq_ptr(mode, "cbc"))
7694 return TPM2_ALG_CBC;
7695 if (strcaseeq_ptr(mode, "cfb"))
7696 return TPM2_ALG_CFB;
7697 if (strcaseeq_ptr(mode, "ecb"))
7698 return TPM2_ALG_ECB;
7699#endif
7700 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown symmetric mode name '%s'", mode);
7701}
7702
ba578556
LP
7703Tpm2Support tpm2_support(void) {
7704 Tpm2Support support = TPM2_SUPPORT_NONE;
7705 int r;
7706
44d5dd65
LP
7707 if (detect_container() <= 0) {
7708 /* Check if there's a /dev/tpmrm* device via sysfs. If we run in a container we likely just
7709 * got the host sysfs mounted. Since devices are generally not virtualized for containers,
7710 * let's assume containers never have a TPM, at least for now. */
7711
db55bbf2 7712 r = dir_is_empty("/sys/class/tpmrm", /* ignore_hidden_or_backup= */ false);
44d5dd65
LP
7713 if (r < 0) {
7714 if (r != -ENOENT)
7715 log_debug_errno(r, "Unable to test whether /sys/class/tpmrm/ exists and is populated, assuming it is not: %m");
7716 } else if (r == 0) /* populated! */
300bba79
DDM
7717 support |= TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_DRIVER;
7718 else
7719 /* If the directory exists but is empty, we know the subsystem is enabled but no
7720 * driver has been loaded yet. */
7721 support |= TPM2_SUPPORT_SUBSYSTEM;
44d5dd65 7722 }
ba578556
LP
7723
7724 if (efi_has_tpm2())
7725 support |= TPM2_SUPPORT_FIRMWARE;
7726
7727#if HAVE_TPM2
7728 support |= TPM2_SUPPORT_SYSTEM;
33931049
DDM
7729
7730 r = dlopen_tpm2();
7731 if (r >= 0)
7732 support |= TPM2_SUPPORT_LIBRARIES;
ba578556
LP
7733#endif
7734
7735 return support;
7736}
222a951f 7737
07c04061
DS
7738#if HAVE_TPM2
7739static void tpm2_pcr_values_apply_default_hash_alg(Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
7740 TPMI_ALG_HASH default_hash = 0;
193fd573
DS
7741 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
7742 if (v->hash != 0) {
7743 default_hash = v->hash;
07c04061
DS
7744 break;
7745 }
7746
7747 if (default_hash != 0)
193fd573
DS
7748 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
7749 if (v->hash == 0)
7750 v->hash = default_hash;
07c04061
DS
7751}
7752#endif
7753
f9a0ee75
DS
7754/* The following tpm2_parse_pcr_argument*() functions all log errors, to match the behavior of system-wide
7755 * parse_*_argument() functions. */
7756
07c04061
DS
7757/* Parse the PCR selection/value arg(s) and return a corresponding array of Tpm2PCRValue objects.
7758 *
7759 * The format is the same as tpm2_pcr_values_from_string(). The first provided entry with a hash algorithm
7760 * set will be used as the 'default' hash algorithm. All entries with an unset hash algorithm will be updated
7761 * with the 'default' hash algorithm. The resulting array will be sorted and checked for validity.
7762 *
7763 * This will replace *ret_pcr_values with the new array of pcr values; to append to an existing array, use
7764 * tpm2_parse_pcr_argument_append(). */
7765int tpm2_parse_pcr_argument(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values) {
7766#if HAVE_TPM2
222a951f
LP
7767 int r;
7768
07c04061
DS
7769 assert(arg);
7770 assert(ret_pcr_values);
7771 assert(ret_n_pcr_values);
222a951f 7772
07c04061
DS
7773 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
7774 size_t n_pcr_values = 0;
7775 r = tpm2_pcr_values_from_string(arg, &pcr_values, &n_pcr_values);
7776 if (r < 0)
f9a0ee75 7777 return log_error_errno(r, "Could not parse PCR values from '%s': %m", arg);
07c04061
DS
7778
7779 tpm2_pcr_values_apply_default_hash_alg(pcr_values, n_pcr_values);
7780
7781 tpm2_sort_pcr_values(pcr_values, n_pcr_values);
7782
cc1a78d5 7783 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
07c04061
DS
7784 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parsed PCR values are not valid.");
7785
7786 *ret_pcr_values = TAKE_PTR(pcr_values);
7787 *ret_n_pcr_values = n_pcr_values;
222a951f 7788
07c04061
DS
7789 return 0;
7790#else
7791 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support is disabled.");
7792#endif
7793}
7794
7795/* Same as tpm2_parse_pcr_argument(), but the pcr values array is appended to. If the provided pcr values
7796 * array is not NULL, it must point to an allocated pcr values array and the provided number of pcr values
7797 * must be correct.
7798 *
7799 * Note that 'arg' is parsed into a new array of pcr values independently of any previous pcr values,
7800 * including application of the default hash algorithm. Then the two arrays are combined, the default hash
7801 * algorithm check applied again (in case either the previous or current array had no default hash
7802 * algorithm), and then the resulting array is sorted and rechecked for validity. */
ae2b38e4 7803int tpm2_parse_pcr_argument_append(const char *arg, Tpm2PCRValue **pcr_values, size_t *n_pcr_values) {
07c04061
DS
7804#if HAVE_TPM2
7805 int r;
7806
7807 assert(arg);
ae2b38e4
DS
7808 assert(pcr_values);
7809 assert(n_pcr_values);
07c04061 7810
ae2b38e4
DS
7811 _cleanup_free_ Tpm2PCRValue *more_pcr_values = NULL;
7812 size_t n_more_pcr_values;
7813 r = tpm2_parse_pcr_argument(arg, &more_pcr_values, &n_more_pcr_values);
07c04061
DS
7814 if (r < 0)
7815 return r;
7816
7817 /* If we got previous values, append them. */
ae2b38e4 7818 if (*pcr_values && !GREEDY_REALLOC_APPEND(more_pcr_values, n_more_pcr_values, *pcr_values, *n_pcr_values))
07c04061
DS
7819 return log_oom();
7820
ae2b38e4 7821 tpm2_pcr_values_apply_default_hash_alg(more_pcr_values, n_more_pcr_values);
07c04061 7822
ae2b38e4 7823 tpm2_sort_pcr_values(more_pcr_values, n_more_pcr_values);
07c04061 7824
ae2b38e4 7825 if (!tpm2_pcr_values_valid(more_pcr_values, n_more_pcr_values))
07c04061
DS
7826 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parsed PCR values are not valid.");
7827
ae2b38e4
DS
7828 SWAP_TWO(*pcr_values, more_pcr_values);
7829 *n_pcr_values = n_more_pcr_values;
07c04061
DS
7830
7831 return 0;
7832#else
7833 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support is disabled.");
7834#endif
7835}
7836
7837/* Same as tpm2_parse_pcr_argument() but converts the pcr values to a pcr mask. If more than one hash
7838 * algorithm is included in the pcr values array this results in error. This retains the previous behavior of
7839 * tpm2_parse_pcr_argument() of clearing the mask if 'arg' is empty, replacing the mask if it is set to
7840 * UINT32_MAX, and or-ing the mask otherwise. */
7841int tpm2_parse_pcr_argument_to_mask(const char *arg, uint32_t *ret_mask) {
7842#if HAVE_TPM2
7843 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
7844 size_t n_pcr_values;
7845 int r;
7846
7847 assert(arg);
7848 assert(ret_mask);
7849
7850 r = tpm2_parse_pcr_argument(arg, &pcr_values, &n_pcr_values);
7851 if (r < 0)
7852 return r;
7853
7854 if (n_pcr_values == 0) {
7855 /* This retains the previous behavior of clearing the mask if the arg is empty */
7856 *ret_mask = 0;
222a951f
LP
7857 return 0;
7858 }
7859
07c04061
DS
7860 size_t hash_count;
7861 r = tpm2_pcr_values_hash_count(pcr_values, n_pcr_values, &hash_count);
222a951f 7862 if (r < 0)
07c04061
DS
7863 return log_error_errno(r, "Could not get hash count from pcr values: %m");
7864
7865 if (hash_count > 1)
7866 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR hash banks selected.");
7867
7868 uint32_t new_mask;
7869 r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, pcr_values[0].hash, &new_mask);
7870 if (r < 0)
7871 return log_error_errno(r, "Could not get pcr values mask: %m");
222a951f 7872
07c04061
DS
7873 if (*ret_mask == UINT32_MAX)
7874 *ret_mask = new_mask;
222a951f 7875 else
07c04061 7876 *ret_mask |= new_mask;
222a951f
LP
7877
7878 return 0;
07c04061
DS
7879#else
7880 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support is disabled.");
7881#endif
222a951f 7882}
6a0779cb
LP
7883
7884int tpm2_load_pcr_signature(const char *path, JsonVariant **ret) {
6270b2e6 7885 _cleanup_strv_free_ char **search = NULL;
6a0779cb
LP
7886 _cleanup_free_ char *discovered_path = NULL;
7887 _cleanup_fclose_ FILE *f = NULL;
7888 int r;
7889
7890 /* Tries to load a JSON PCR signature file. Takes an absolute path, a simple file name or NULL. In
7891 * the latter two cases searches in /etc/, /usr/lib/, /run/, as usual. */
7892
8f431828 7893 search = strv_new(CONF_PATHS("systemd"));
6270b2e6 7894 if (!search)
f9a0ee75 7895 return log_oom_debug();
6270b2e6
LP
7896
7897 if (!path) {
7898 /* If no path is specified, then look for "tpm2-pcr-signature.json" automatically. Also, in
7899 * this case include /.extra/ in the search path, but only in this case, and if we run in the
7900 * initrd. We don't want to be too eager here, after all /.extra/ is untrusted territory. */
7901
6a0779cb
LP
7902 path = "tpm2-pcr-signature.json";
7903
6270b2e6
LP
7904 if (in_initrd())
7905 if (strv_extend(&search, "/.extra") < 0)
f9a0ee75 7906 return log_oom_debug();
6270b2e6
LP
7907 }
7908
7909 r = search_and_fopen(path, "re", NULL, (const char**) search, &f, &discovered_path);
6a0779cb
LP
7910 if (r < 0)
7911 return log_debug_errno(r, "Failed to find TPM PCR signature file '%s': %m", path);
7912
7913 r = json_parse_file(f, discovered_path, 0, ret, NULL, NULL);
7914 if (r < 0)
7915 return log_debug_errno(r, "Failed to parse TPM PCR signature JSON object '%s': %m", discovered_path);
7916
7917 return 0;
7918}
7919
7920int tpm2_load_pcr_public_key(const char *path, void **ret_pubkey, size_t *ret_pubkey_size) {
7921 _cleanup_free_ char *discovered_path = NULL;
7922 _cleanup_fclose_ FILE *f = NULL;
7923 int r;
7924
7925 /* Tries to load a PCR public key file. Takes an absolute path, a simple file name or NULL. In the
7926 * latter two cases searches in /etc/, /usr/lib/, /run/, as usual. */
7927
7928 if (!path)
7929 path = "tpm2-pcr-public-key.pem";
7930
7931 r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("systemd"), &f, &discovered_path);
7932 if (r < 0)
7933 return log_debug_errno(r, "Failed to find TPM PCR public key file '%s': %m", path);
7934
7935 r = read_full_stream(f, (char**) ret_pubkey, ret_pubkey_size);
7936 if (r < 0)
7937 return log_debug_errno(r, "Failed to load TPM PCR public key PEM file '%s': %m", discovered_path);
7938
7939 return 0;
7940}
4d5cc0d4 7941
aae6eb96
WR
7942#define PBKDF2_HMAC_SHA256_ITERATIONS 10000
7943
7944/*
7945 * Implements PBKDF2 HMAC SHA256 for a derived keylen of 32
7946 * bytes and for PBKDF2_HMAC_SHA256_ITERATIONS count.
7947 * I found the wikipedia entry relevant and it contains links to
7948 * relevant RFCs:
7949 * - https://en.wikipedia.org/wiki/PBKDF2
7950 * - https://www.rfc-editor.org/rfc/rfc2898#section-5.2
7951 */
7952int tpm2_util_pbkdf2_hmac_sha256(const void *pass,
7953 size_t passlen,
7954 const void *salt,
7955 size_t saltlen,
7956 uint8_t ret_key[static SHA256_DIGEST_SIZE]) {
7957
321e64dc 7958 _cleanup_(erase_and_freep) uint8_t *buffer = NULL;
aae6eb96
WR
7959 uint8_t u[SHA256_DIGEST_SIZE];
7960
7961 /* To keep this simple, since derived KeyLen (dkLen in docs)
7962 * Is the same as the hash output, we don't need multiple
7963 * blocks. Part of the algorithm is to add the block count
7964 * in, but this can be hardcoded to 1.
7965 */
7966 static const uint8_t block_cnt[] = { 0, 0, 0, 1 };
7967
504d0acf 7968 assert (salt);
aae6eb96
WR
7969 assert (saltlen > 0);
7970 assert (saltlen <= (SIZE_MAX - sizeof(block_cnt)));
7971 assert (passlen > 0);
7972
7973 /*
7974 * Build a buffer of salt + block_cnt and hmac_sha256 it we
7975 * do this as we don't have a context builder for HMAC_SHA256.
7976 */
7977 buffer = malloc(saltlen + sizeof(block_cnt));
7978 if (!buffer)
7979 return -ENOMEM;
7980
7981 memcpy(buffer, salt, saltlen);
7982 memcpy(&buffer[saltlen], block_cnt, sizeof(block_cnt));
7983
7984 hmac_sha256(pass, passlen, buffer, saltlen + sizeof(block_cnt), u);
7985
7986 /* dk needs to be an unmodified u as u gets modified in the loop */
7987 memcpy(ret_key, u, SHA256_DIGEST_SIZE);
7988 uint8_t *dk = ret_key;
7989
7990 for (size_t i = 1; i < PBKDF2_HMAC_SHA256_ITERATIONS; i++) {
7991 hmac_sha256(pass, passlen, u, sizeof(u), u);
7992
7993 for (size_t j=0; j < sizeof(u); j++)
7994 dk[j] ^= u[j];
7995 }
7996
7997 return 0;
7998}
96ead603 7999
2099cd62
LP
8000static const char* const tpm2_pcr_index_table[_TPM2_PCR_INDEX_MAX_DEFINED] = {
8001 [TPM2_PCR_PLATFORM_CODE] = "platform-code",
8002 [TPM2_PCR_PLATFORM_CONFIG] = "platform-config",
8003 [TPM2_PCR_EXTERNAL_CODE] = "external-code",
8004 [TPM2_PCR_EXTERNAL_CONFIG] = "external-config",
8005 [TPM2_PCR_BOOT_LOADER_CODE] = "boot-loader-code",
8006 [TPM2_PCR_BOOT_LOADER_CONFIG] = "boot-loader-config",
8007 [TPM2_PCR_HOST_PLATFORM] = "host-platform",
8008 [TPM2_PCR_SECURE_BOOT_POLICY] = "secure-boot-policy",
8009 [TPM2_PCR_KERNEL_INITRD] = "kernel-initrd",
8010 [TPM2_PCR_IMA] = "ima",
8011 [TPM2_PCR_KERNEL_BOOT] = "kernel-boot",
8012 [TPM2_PCR_KERNEL_CONFIG] = "kernel-config",
8013 [TPM2_PCR_SYSEXTS] = "sysexts",
8014 [TPM2_PCR_SHIM_POLICY] = "shim-policy",
8015 [TPM2_PCR_SYSTEM_IDENTITY] = "system-identity",
8016 [TPM2_PCR_DEBUG] = "debug",
8017 [TPM2_PCR_APPLICATION_SUPPORT] = "application-support",
96ead603
OJ
8018};
8019
2099cd62
LP
8020DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_FALLBACK(tpm2_pcr_index, int, TPM2_PCRS_MAX - 1);
8021DEFINE_STRING_TABLE_LOOKUP_TO_STRING(tpm2_pcr_index, int);