]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/tpm2-util.c
tree-wide: check if return value of lseek() and friends is negative
[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"
fdf6c27c 7#include "cryptsetup-util.h"
5e521624
LP
8#include "dirent-util.h"
9#include "dlfcn-util.h"
fdf6c27c
LP
10#include "efi-api.h"
11#include "extract-word.h"
5e521624 12#include "fd-util.h"
6a0779cb 13#include "fileio.h"
5e521624
LP
14#include "format-table.h"
15#include "fs-util.h"
16#include "hexdecoct.h"
aae6eb96 17#include "hmac.h"
6270b2e6 18#include "initrd-util.h"
cb19bdae 19#include "io-util.h"
acbb504e 20#include "lock-util.h"
a12bc99e
ZJS
21#include "log.h"
22#include "logarithm.h"
5e521624 23#include "memory-util.h"
cb19bdae 24#include "mkdir.h"
6270b2e6 25#include "nulstr-util.h"
fdf6c27c 26#include "parse-util.h"
5e521624 27#include "random-util.h"
2f5a892a 28#include "sha256.h"
323eb480 29#include "sort-util.h"
fdf6c27c 30#include "stat-util.h"
96ead603 31#include "string-table.h"
cb19bdae 32#include "sync-util.h"
5e521624 33#include "time-util.h"
fdf6c27c
LP
34#include "tpm2-util.h"
35#include "virt.h"
5e521624 36
fdf6c27c 37#if HAVE_TPM2
5e521624
LP
38static void *libtss2_esys_dl = NULL;
39static void *libtss2_rc_dl = NULL;
40static void *libtss2_mu_dl = NULL;
41
b57a7b3d 42static TSS2_RC (*sym_Esys_Create)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_PUBLIC *inPublic, const TPM2B_DATA *outsideInfo, const TPML_PCR_SELECTION *creationPCR, TPM2B_PRIVATE **outPrivate, TPM2B_PUBLIC **outPublic, TPM2B_CREATION_DATA **creationData, TPM2B_DIGEST **creationHash, TPMT_TK_CREATION **creationTicket) = NULL;
cea525a9 43static TSS2_RC (*sym_Esys_CreateLoaded)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_TEMPLATE *inPublic, ESYS_TR *objectHandle, TPM2B_PRIVATE **outPrivate, TPM2B_PUBLIC **outPublic) = NULL;
b57a7b3d
DS
44static TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR primaryHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_PUBLIC *inPublic, const TPM2B_DATA *outsideInfo, const TPML_PCR_SELECTION *creationPCR, ESYS_TR *objectHandle, TPM2B_PUBLIC **outPublic, TPM2B_CREATION_DATA **creationData, TPM2B_DIGEST **creationHash, TPMT_TK_CREATION **creationTicket) = NULL;
45static TSS2_RC (*sym_Esys_EvictControl)(ESYS_CONTEXT *esysContext, ESYS_TR auth, ESYS_TR objectHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPMI_DH_PERSISTENT persistentHandle, ESYS_TR *newObjectHandle) = NULL;
46static void (*sym_Esys_Finalize)(ESYS_CONTEXT **context) = NULL;
47static TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle) = NULL;
48static void (*sym_Esys_Free)(void *ptr) = NULL;
49static TSS2_RC (*sym_Esys_GetCapability)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2_CAP capability, UINT32 property, UINT32 propertyCount, TPMI_YES_NO *moreData, TPMS_CAPABILITY_DATA **capabilityData) = NULL;
50static TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes) = NULL;
51static TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL;
52static TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL;
53static TSS2_RC (*sym_Esys_LoadExternal)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR hierarchy, ESYS_TR *objectHandle) = NULL;
54static TSS2_RC (*sym_Esys_PCR_Extend)(ESYS_CONTEXT *esysContext, ESYS_TR pcrHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPML_DIGEST_VALUES *digests) = NULL;
55static TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues) = NULL;
56static TSS2_RC (*sym_Esys_PolicyAuthorize)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *approvedPolicy, const TPM2B_NONCE *policyRef, const TPM2B_NAME *keySign, const TPMT_TK_VERIFIED *checkTicket) = NULL;
57static TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3) = NULL;
58static TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL;
59static TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL;
60static TSS2_RC (*sym_Esys_ReadPublic)(ESYS_CONTEXT *esysContext, ESYS_TR objectHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_PUBLIC **outPublic, TPM2B_NAME **name, TPM2B_NAME **qualifiedName) = NULL;
61static TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL;
62static TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType) = NULL;
a47060bb 63static TSS2_RC (*sym_Esys_TestParms)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPMT_PUBLIC_PARMS *parameters) = NULL;
c8a85240 64static TSS2_RC (*sym_Esys_TR_Close)(ESYS_CONTEXT *esys_context, ESYS_TR *rsrc_handle) = NULL;
b57a7b3d
DS
65static TSS2_RC (*sym_Esys_TR_Deserialize)(ESYS_CONTEXT *esys_context, uint8_t const *buffer, size_t buffer_size, ESYS_TR *esys_handle) = NULL;
66static TSS2_RC (*sym_Esys_TR_FromTPMPublic)(ESYS_CONTEXT *esysContext, TPM2_HANDLE tpm_handle, ESYS_TR optionalSession1, ESYS_TR optionalSession2, ESYS_TR optionalSession3, ESYS_TR *object) = NULL;
ba723ea2 67static TSS2_RC (*sym_Esys_TR_GetName)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_NAME **name) = NULL;
13cf98f3 68static TSS2_RC (*sym_Esys_TR_GetTpmHandle)(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle, TPM2_HANDLE *tpm_handle) = NULL;
b57a7b3d
DS
69static TSS2_RC (*sym_Esys_TR_Serialize)(ESYS_CONTEXT *esys_context, ESYS_TR object, uint8_t **buffer, size_t *buffer_size) = NULL;
70static TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue) = NULL;
ba723ea2
DS
71static TSS2_RC (*sym_Esys_TRSess_GetAttributes)(ESYS_CONTEXT *esysContext, ESYS_TR session, TPMA_SESSION *flags) = NULL;
72static TSS2_RC (*sym_Esys_TRSess_SetAttributes)(ESYS_CONTEXT *esysContext, ESYS_TR session, TPMA_SESSION flags, TPMA_SESSION mask) = NULL;
b57a7b3d
DS
73static TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData) = NULL;
74static TSS2_RC (*sym_Esys_VerifySignature)(ESYS_CONTEXT *esysContext, ESYS_TR keyHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *digest, const TPMT_SIGNATURE *signature, TPMT_TK_VERIFIED **validation) = NULL;
75
b57a7b3d
DS
76static TSS2_RC (*sym_Tss2_MU_TPM2_CC_Marshal)(TPM2_CC src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
77static TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Marshal)(TPM2B_PRIVATE const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
78static TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PRIVATE *dest) = NULL;
79static TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal)(TPM2B_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
80static TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PUBLIC *dest) = NULL;
81static TSS2_RC (*sym_Tss2_MU_TPML_PCR_SELECTION_Marshal)(TPML_PCR_SELECTION const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
82static TSS2_RC (*sym_Tss2_MU_TPMT_HA_Marshal)(TPMT_HA const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
83static TSS2_RC (*sym_Tss2_MU_TPMT_PUBLIC_Marshal)(TPMT_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
5e521624 84
ba723ea2
DS
85static const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL;
86
5e521624 87int dlopen_tpm2(void) {
d32f7a8e
ZJS
88 int r;
89
90 r = dlopen_many_sym_or_warn(
91 &libtss2_esys_dl, "libtss2-esys.so.0", LOG_DEBUG,
92 DLSYM_ARG(Esys_Create),
cea525a9 93 DLSYM_ARG(Esys_CreateLoaded),
d32f7a8e 94 DLSYM_ARG(Esys_CreatePrimary),
acbb504e 95 DLSYM_ARG(Esys_EvictControl),
d32f7a8e
ZJS
96 DLSYM_ARG(Esys_Finalize),
97 DLSYM_ARG(Esys_FlushContext),
98 DLSYM_ARG(Esys_Free),
07697bfe 99 DLSYM_ARG(Esys_GetCapability),
d32f7a8e
ZJS
100 DLSYM_ARG(Esys_GetRandom),
101 DLSYM_ARG(Esys_Initialize),
102 DLSYM_ARG(Esys_Load),
0d756413 103 DLSYM_ARG(Esys_LoadExternal),
1421943a 104 DLSYM_ARG(Esys_PCR_Extend),
321a9d9e 105 DLSYM_ARG(Esys_PCR_Read),
0d756413 106 DLSYM_ARG(Esys_PolicyAuthorize),
2f5a892a 107 DLSYM_ARG(Esys_PolicyAuthValue),
d32f7a8e
ZJS
108 DLSYM_ARG(Esys_PolicyGetDigest),
109 DLSYM_ARG(Esys_PolicyPCR),
acbb504e 110 DLSYM_ARG(Esys_ReadPublic),
d32f7a8e
ZJS
111 DLSYM_ARG(Esys_StartAuthSession),
112 DLSYM_ARG(Esys_Startup),
a47060bb 113 DLSYM_ARG(Esys_TestParms),
c8a85240 114 DLSYM_ARG(Esys_TR_Close),
ba723ea2 115 DLSYM_ARG(Esys_TR_Deserialize),
acbb504e 116 DLSYM_ARG(Esys_TR_FromTPMPublic),
0d756413 117 DLSYM_ARG(Esys_TR_GetName),
acbb504e 118 DLSYM_ARG(Esys_TR_Serialize),
2f5a892a 119 DLSYM_ARG(Esys_TR_SetAuth),
ba723ea2
DS
120 DLSYM_ARG(Esys_TRSess_GetAttributes),
121 DLSYM_ARG(Esys_TRSess_SetAttributes),
0d756413
LP
122 DLSYM_ARG(Esys_Unseal),
123 DLSYM_ARG(Esys_VerifySignature));
d32f7a8e
ZJS
124 if (r < 0)
125 return r;
126
13cf98f3
DS
127 /* Esys_TR_GetTpmHandle was added to tpm2-tss in version 2.4.0. Once we can set a minimum tpm2-tss
128 * version of 2.4.0 this sym can be moved up to the normal list above. */
129 r = dlsym_many_or_warn(libtss2_esys_dl, LOG_DEBUG, DLSYM_ARG_FORCE(Esys_TR_GetTpmHandle));
130 if (r < 0)
131 log_debug("libtss2-esys too old, does not include Esys_TR_GetTpmHandle.");
132
d32f7a8e
ZJS
133 r = dlopen_many_sym_or_warn(
134 &libtss2_rc_dl, "libtss2-rc.so.0", LOG_DEBUG,
135 DLSYM_ARG(Tss2_RC_Decode));
136 if (r < 0)
137 return r;
138
139 return dlopen_many_sym_or_warn(
140 &libtss2_mu_dl, "libtss2-mu.so.0", LOG_DEBUG,
dcbc4674 141 DLSYM_ARG(Tss2_MU_TPM2_CC_Marshal),
d32f7a8e
ZJS
142 DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal),
143 DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal),
144 DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal),
dbae4b95 145 DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal),
dcbc4674 146 DLSYM_ARG(Tss2_MU_TPML_PCR_SELECTION_Marshal),
dbae4b95
DS
147 DLSYM_ARG(Tss2_MU_TPMT_HA_Marshal),
148 DLSYM_ARG(Tss2_MU_TPMT_PUBLIC_Marshal));
5e521624
LP
149}
150
2e64cb71 151void Esys_Freep(void *p) {
b57a7b3d
DS
152 if (*(void**) p)
153 sym_Esys_Free(*(void**) p);
154}
155
3a35d6cd
DS
156/* Get a specific TPM capability (or capabilities).
157 *
158 * Returns 0 if there are no more capability properties of the requested type, or 1 if there are more, or < 0
159 * on any error. Both 0 and 1 indicate this completed successfully, but do not indicate how many capability
160 * properties were provided in 'ret_capability_data'. To find the number of provided properties, check the
161 * specific type's 'count' field (e.g. for TPM2_CAP_ALGS, check ret_capability_data->algorithms.count).
162 *
163 * This calls TPM2_GetCapability() and does not alter the provided data, so it is important to understand how
164 * that TPM function works. It is recommended to check the TCG TPM specification Part 3 ("Commands") section
165 * on TPM2_GetCapability() for full details, but a short summary is: if this returns 0, all available
166 * properties have been provided in ret_capability_data, or no properties were available. If this returns 1,
167 * there are between 1 and "count" properties provided in ret_capability_data, and there are more available.
168 * Note that this may provide less than "count" properties even if the TPM has more available. Also, each
169 * capability category may have more specific requirements than described here; see the spec for exact
170 * details. */
171static int tpm2_get_capability(
172 Tpm2Context *c,
173 TPM2_CAP capability,
174 uint32_t property,
175 uint32_t count,
176 TPMU_CAPABILITIES *ret_capability_data) {
177
178 _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *capabilities = NULL;
179 TPMI_YES_NO more;
180 TSS2_RC rc;
181
182 assert(c);
183
184 log_debug("Getting TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 " count %" PRIu32 ".",
185 capability, property, count);
186
187 rc = sym_Esys_GetCapability(
188 c->esys_context,
189 ESYS_TR_NONE,
190 ESYS_TR_NONE,
191 ESYS_TR_NONE,
192 capability,
193 property,
194 count,
195 &more,
196 &capabilities);
197 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 198 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3a35d6cd
DS
199 "Failed to get TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 ": %s",
200 capability, property, sym_Tss2_RC_Decode(rc));
201
202 if (capabilities->capability != capability)
f9a0ee75 203 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3a35d6cd
DS
204 "TPM provided wrong capability: 0x%04" PRIx32 " instead of 0x%04" PRIx32 ".",
205 capabilities->capability, capability);
206
207 if (ret_capability_data)
208 *ret_capability_data = capabilities->data;
209
210 return more == TPM2_YES;
211}
212
adbf0c8c
DS
213#define TPMA_CC_TO_TPM2_CC(cca) (((cca) & TPMA_CC_COMMANDINDEX_MASK) >> TPMA_CC_COMMANDINDEX_SHIFT)
214
3a35d6cd
DS
215static int tpm2_cache_capabilities(Tpm2Context *c) {
216 TPMU_CAPABILITIES capability;
217 int r;
218
219 assert(c);
220
cbc92a31
DS
221 /* Cache the algorithms. The spec indicates supported algorithms can only be modified during runtime
222 * by the SetAlgorithmSet() command. Unfortunately, the spec doesn't require a TPM reinitialization
223 * after changing the algorithm set (unless the PCR algorithms are changed). However, the spec also
224 * indicates the TPM behavior after SetAlgorithmSet() is "vendor-dependent", giving the example of
627cdcc7 225 * flushing sessions and objects, erasing policies, etc. So, if the algorithm set is programmatically
cbc92a31
DS
226 * changed while we are performing some operation, it's reasonable to assume it will break us even if
227 * we don't cache the algorithms, thus they should be "safe" to cache. */
228 TPM2_ALG_ID current_alg = TPM2_ALG_FIRST;
229 for (;;) {
230 r = tpm2_get_capability(
231 c,
232 TPM2_CAP_ALGS,
233 (uint32_t) current_alg, /* The spec states to cast TPM2_ALG_ID to uint32_t. */
234 TPM2_MAX_CAP_ALGS,
235 &capability);
236 if (r < 0)
237 return r;
238
239 TPML_ALG_PROPERTY algorithms = capability.algorithms;
240
241 /* We should never get 0; the TPM must support some algorithms, and it must not set 'more' if
242 * there are no more. */
243 assert(algorithms.count > 0);
244
245 if (!GREEDY_REALLOC_APPEND(
246 c->capability_algorithms,
247 c->n_capability_algorithms,
248 algorithms.algProperties,
249 algorithms.count))
f9a0ee75 250 return log_oom_debug();
cbc92a31
DS
251
252 if (r == 0)
253 break;
254
255 /* Set current_alg to alg id after last alg id the TPM provided */
256 current_alg = algorithms.algProperties[algorithms.count - 1].alg + 1;
257 }
258
adbf0c8c 259 /* Cache the command capabilities. The spec isn't actually clear if commands can be added/removed
627cdcc7 260 * while running, but that would be crazy, so let's hope it is not possible. */
adbf0c8c
DS
261 TPM2_CC current_cc = TPM2_CC_FIRST;
262 for (;;) {
263 r = tpm2_get_capability(
264 c,
265 TPM2_CAP_COMMANDS,
266 current_cc,
267 TPM2_MAX_CAP_CC,
268 &capability);
269 if (r < 0)
270 return r;
271
272 TPML_CCA commands = capability.command;
273
274 /* We should never get 0; the TPM must support some commands, and it must not set 'more' if
275 * there are no more. */
276 assert(commands.count > 0);
277
278 if (!GREEDY_REALLOC_APPEND(
279 c->capability_commands,
280 c->n_capability_commands,
281 commands.commandAttributes,
282 commands.count))
f9a0ee75 283 return log_oom_debug();
adbf0c8c
DS
284
285 if (r == 0)
286 break;
287
288 /* Set current_cc to index after last cc the TPM provided */
289 current_cc = TPMA_CC_TO_TPM2_CC(commands.commandAttributes[commands.count - 1]) + 1;
290 }
291
639dca03
DS
292 /* Cache the ECC curves. The spec isn't actually clear if ECC curves can be added/removed
293 * while running, but that would be crazy, so let's hope it is not possible. */
294 TPM2_ECC_CURVE current_ecc_curve = TPM2_ECC_NONE;
295 for (;;) {
296 r = tpm2_get_capability(
297 c,
298 TPM2_CAP_ECC_CURVES,
299 current_ecc_curve,
300 TPM2_MAX_ECC_CURVES,
301 &capability);
302 if (r < 0)
303 return r;
304
305 TPML_ECC_CURVE ecc_curves = capability.eccCurves;
306
307 /* ECC support isn't required */
308 if (ecc_curves.count == 0)
309 break;
310
311 if (!GREEDY_REALLOC_APPEND(
312 c->capability_ecc_curves,
313 c->n_capability_ecc_curves,
314 ecc_curves.eccCurves,
315 ecc_curves.count))
316 return log_oom_debug();
317
318 if (r == 0)
319 break;
320
321 /* Set current_ecc_curve to index after last ecc curve the TPM provided */
322 current_ecc_curve = ecc_curves.eccCurves[ecc_curves.count - 1] + 1;
323 }
324
3a35d6cd
DS
325 /* Cache the PCR capabilities, which are safe to cache, as the only way they can change is
326 * TPM2_PCR_Allocate(), which changes the allocation after the next _TPM_Init(). If the TPM is
327 * reinitialized while we are using it, all our context and sessions will be invalid, so we can
328 * safely assume the TPM PCR allocation will not change while we are using it. */
329 r = tpm2_get_capability(
330 c,
331 TPM2_CAP_PCRS,
332 /* property= */ 0,
333 /* count= */ 1,
334 &capability);
335 if (r < 0)
336 return r;
337 if (r == 1)
338 /* This should never happen. Part 3 ("Commands") of the TCG TPM2 spec in the section for
339 * TPM2_GetCapability states: "TPM_CAP_PCRS – Returns the current allocation of PCR in a
340 * TPML_PCR_SELECTION. The property parameter shall be zero. The TPM will always respond to
341 * this command with the full PCR allocation and moreData will be NO." */
f9a0ee75 342 log_debug("TPM bug: reported multiple PCR sets; using only first set.");
3a35d6cd
DS
343 c->capability_pcrs = capability.assignedPCR;
344
345 return 0;
346}
347
cbc92a31
DS
348/* Get the TPMA_ALGORITHM for a TPM2_ALG_ID. Returns true if the TPM supports the algorithm and the
349 * TPMA_ALGORITHM is provided, otherwise false. */
350static bool tpm2_get_capability_alg(Tpm2Context *c, TPM2_ALG_ID alg, TPMA_ALGORITHM *ret) {
a47060bb
DS
351 assert(c);
352
cbc92a31
DS
353 FOREACH_ARRAY(alg_prop, c->capability_algorithms, c->n_capability_algorithms)
354 if (alg_prop->alg == alg) {
355 if (ret)
356 *ret = alg_prop->algProperties;
357 return true;
358 }
a47060bb 359
cbc92a31 360 log_debug("TPM does not support alg 0x%02" PRIx16 ".", alg);
a47060bb 361 if (ret)
cbc92a31 362 *ret = 0;
a47060bb 363
cbc92a31 364 return false;
a47060bb
DS
365}
366
cbc92a31 367bool tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg) {
a47060bb
DS
368 return tpm2_get_capability_alg(c, alg, NULL);
369}
370
adbf0c8c
DS
371/* Get the TPMA_CC for a TPM2_CC. Returns true if the TPM supports the command and the TPMA_CC is provided,
372 * otherwise false. */
373static bool tpm2_get_capability_command(Tpm2Context *c, TPM2_CC command, TPMA_CC *ret) {
374 assert(c);
375
376 FOREACH_ARRAY(cca, c->capability_commands, c->n_capability_commands)
377 if (TPMA_CC_TO_TPM2_CC(*cca) == command) {
378 if (ret)
379 *ret = *cca;
380 return true;
381 }
382
383 log_debug("TPM does not support command 0x%04" PRIx32 ".", command);
384 if (ret)
385 *ret = 0;
386
387 return false;
388}
389
390bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command) {
391 return tpm2_get_capability_command(c, command, NULL);
392}
393
639dca03
DS
394/* Returns true if the TPM supports the ECC curve, otherwise false. */
395bool tpm2_supports_ecc_curve(Tpm2Context *c, TPM2_ECC_CURVE ecc_curve) {
396 assert(c);
f4f5b3a9 397
639dca03
DS
398 FOREACH_ARRAY(curve, c->capability_ecc_curves, c->n_capability_ecc_curves)
399 if (*curve == ecc_curve)
400 return true;
f4f5b3a9 401
639dca03
DS
402 log_debug("TPM does not support ECC curve 0x%" PRIx16 ".", ecc_curve);
403 return false;
f4f5b3a9
DS
404}
405
c8a85240
DS
406/* Query the TPM for populated handles.
407 *
408 * This provides an array of handle indexes populated in the TPM, starting at the requested handle. The array will
409 * contain only populated handle addresses (which might not include the requested handle). The number of
410 * handles will be no more than the 'max' number requested. This will not search past the end of the handle
411 * range (i.e. handle & 0xff000000).
412 *
413 * Returns 0 if all populated handles in the range (starting at the requested handle) were provided (or no
414 * handles were in the range), or 1 if there are more populated handles in the range, or < 0 on any error. */
415static int tpm2_get_capability_handles(
416 Tpm2Context *c,
417 TPM2_HANDLE start,
418 size_t max,
419 TPM2_HANDLE **ret_handles,
420 size_t *ret_n_handles) {
421
422 _cleanup_free_ TPM2_HANDLE *handles = NULL;
423 size_t n_handles = 0;
424 TPM2_HANDLE current = start;
425 int r = 0;
426
427 assert(c);
428 assert(ret_handles);
429 assert(ret_n_handles);
430
70140069
DS
431 max = MIN(max, UINT32_MAX);
432
c8a85240
DS
433 while (max > 0) {
434 TPMU_CAPABILITIES capability;
435 r = tpm2_get_capability(c, TPM2_CAP_HANDLES, current, (uint32_t) max, &capability);
436 if (r < 0)
437 return r;
438
439 TPML_HANDLE handle_list = capability.handles;
440 if (handle_list.count == 0)
441 break;
442
443 assert(handle_list.count <= max);
444
445 if (n_handles > SIZE_MAX - handle_list.count)
f9a0ee75 446 return log_oom_debug();
c8a85240 447
70140069 448 if (!GREEDY_REALLOC_APPEND(handles, n_handles, handle_list.handle, handle_list.count))
f9a0ee75 449 return log_oom_debug();
c8a85240 450
c8a85240 451 max -= handle_list.count;
c8a85240
DS
452
453 /* Update current to the handle index after the last handle in the list. */
454 current = handles[n_handles - 1] + 1;
455
456 if (r == 0)
457 /* No more handles in this range. */
458 break;
459 }
460
461 *ret_handles = TAKE_PTR(handles);
462 *ret_n_handles = n_handles;
463
464 return r;
465}
466
467#define TPM2_HANDLE_RANGE(h) ((TPM2_HANDLE)((h) & TPM2_HR_RANGE_MASK))
468#define TPM2_HANDLE_TYPE(h) ((TPM2_HT)(TPM2_HANDLE_RANGE(h) >> TPM2_HR_SHIFT))
469
470/* Returns 1 if the handle is populated in the TPM, 0 if not, and < 0 on any error. */
471static int tpm2_get_capability_handle(Tpm2Context *c, TPM2_HANDLE handle) {
472 _cleanup_free_ TPM2_HANDLE *handles = NULL;
473 size_t n_handles = 0;
474 int r;
475
476 r = tpm2_get_capability_handles(c, handle, 1, &handles, &n_handles);
477 if (r < 0)
478 return r;
479
480 return n_handles == 0 ? false : handles[0] == handle;
481}
482
a47060bb
DS
483/* Returns 1 if the TPM supports the parms, or 0 if the TPM does not support the parms. */
484bool tpm2_test_parms(Tpm2Context *c, TPMI_ALG_PUBLIC alg, const TPMU_PUBLIC_PARMS *parms) {
485 TSS2_RC rc;
486
487 assert(c);
488 assert(parms);
489
490 TPMT_PUBLIC_PARMS parameters = {
491 .type = alg,
492 .parameters = *parms,
493 };
494
495 rc = sym_Esys_TestParms(c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &parameters);
496 if (rc != TSS2_RC_SUCCESS)
497 /* The spec says if the parms are not supported the TPM returns "...the appropriate
498 * unmarshaling error if a parameter is not valid". Since the spec (currently) defines 15
499 * unmarshaling errors, instead of checking for them all here, let's just assume any error
500 * indicates unsupported parms, and log the specific error text. */
501 log_debug("TPM does not support tested parms: %s", sym_Tss2_RC_Decode(rc));
502
503 return rc == TSS2_RC_SUCCESS;
504}
505
cf1ab844 506static bool tpm2_supports_tpmt_public(Tpm2Context *c, const TPMT_PUBLIC *public) {
f4f5b3a9
DS
507 assert(c);
508 assert(public);
509
510 return tpm2_test_parms(c, public->type, &public->parameters);
511}
512
cf1ab844 513static bool tpm2_supports_tpmt_sym_def_object(Tpm2Context *c, const TPMT_SYM_DEF_OBJECT *parameters) {
a47060bb
DS
514 assert(c);
515 assert(parameters);
516
517 TPMU_PUBLIC_PARMS parms = {
518 .symDetail.sym = *parameters,
519 };
520
521 return tpm2_test_parms(c, TPM2_ALG_SYMCIPHER, &parms);
522}
523
cf1ab844 524static bool tpm2_supports_tpmt_sym_def(Tpm2Context *c, const TPMT_SYM_DEF *parameters) {
a47060bb
DS
525 assert(c);
526 assert(parameters);
527
528 /* Unfortunately, TPMT_SYM_DEF and TPMT_SYM_DEF_OBEJECT are separately defined, even though they are
529 * functionally identical. */
530 TPMT_SYM_DEF_OBJECT object = {
531 .algorithm = parameters->algorithm,
532 .keyBits = parameters->keyBits,
533 .mode = parameters->mode,
534 };
535
536 return tpm2_supports_tpmt_sym_def_object(c, &object);
537}
538
68d084ce
DS
539static Tpm2Context *tpm2_context_free(Tpm2Context *c) {
540 if (!c)
541 return NULL;
5e521624
LP
542
543 if (c->esys_context)
544 sym_Esys_Finalize(&c->esys_context);
545
546 c->tcti_context = mfree(c->tcti_context);
f2592ef0 547 c->tcti_dl = safe_dlclose(c->tcti_dl);
5e521624 548
cbc92a31 549 c->capability_algorithms = mfree(c->capability_algorithms);
adbf0c8c 550 c->capability_commands = mfree(c->capability_commands);
639dca03 551 c->capability_ecc_curves = mfree(c->capability_ecc_curves);
adbf0c8c 552
68d084ce 553 return mfree(c);
5e521624
LP
554}
555
68d084ce
DS
556DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free);
557
a47060bb
DS
558static const TPMT_SYM_DEF SESSION_TEMPLATE_SYM_AES_128_CFB = {
559 .algorithm = TPM2_ALG_AES,
560 .keyBits.aes = 128,
561 .mode.aes = TPM2_ALG_CFB, /* The spec requires sessions to use CFB. */
562};
563
68d084ce 564int tpm2_context_new(const char *device, Tpm2Context **ret_context) {
1dc8f518 565 _cleanup_(tpm2_context_unrefp) Tpm2Context *context = NULL;
5e521624
LP
566 TSS2_RC rc;
567 int r;
568
68d084ce
DS
569 assert(ret_context);
570
d70e4bc9 571 context = new(Tpm2Context, 1);
68d084ce 572 if (!context)
f9a0ee75 573 return log_oom_debug();
68d084ce 574
d70e4bc9
LP
575 *context = (Tpm2Context) {
576 .n_ref = 1,
577 };
68d084ce 578
5e521624
LP
579 r = dlopen_tpm2();
580 if (r < 0)
f9a0ee75 581 return log_debug_errno(r, "TPM2 support not installed: %m");
5e521624 582
34906680 583 if (!device) {
5e521624 584 device = secure_getenv("SYSTEMD_TPM2_DEVICE");
34906680
LP
585 if (device)
586 /* Setting the env var to an empty string forces tpm2-tss' own device picking
587 * logic to be used. */
588 device = empty_to_null(device);
589 else
590 /* If nothing was specified explicitly, we'll use a hardcoded default: the "device" tcti
591 * driver and the "/dev/tpmrm0" device. We do this since on some distributions the tpm2-abrmd
592 * might be used and we really don't want that, since it is a system service and that creates
593 * various ordering issues/deadlocks during early boot. */
594 device = "device:/dev/tpmrm0";
595 }
5e521624
LP
596
597 if (device) {
598 const char *param, *driver, *fn;
599 const TSS2_TCTI_INFO* info;
600 TSS2_TCTI_INFO_FUNC func;
601 size_t sz = 0;
602
603 param = strchr(device, ':');
604 if (param) {
50a08514 605 /* Syntax #1: Pair of driver string and arbitrary parameter */
2f82562b 606 driver = strndupa_safe(device, param - device);
50a08514 607 if (isempty(driver))
f9a0ee75 608 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name is empty, refusing.");
50a08514 609
5e521624 610 param++;
50a08514
LP
611 } else if (path_is_absolute(device) && path_is_valid(device)) {
612 /* Syntax #2: TPM device node */
5e521624
LP
613 driver = "device";
614 param = device;
50a08514 615 } else
f9a0ee75 616 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid TPM2 driver string, refusing.");
50a08514
LP
617
618 log_debug("Using TPM2 TCTI driver '%s' with device '%s'.", driver, param);
5e521624
LP
619
620 fn = strjoina("libtss2-tcti-", driver, ".so.0");
621
50a08514
LP
622 /* Better safe than sorry, let's refuse strings that cannot possibly be valid driver early, before going to disk. */
623 if (!filename_is_valid(fn))
f9a0ee75 624 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name '%s' not valid, refusing.", driver);
50a08514 625
68d084ce
DS
626 context->tcti_dl = dlopen(fn, RTLD_NOW);
627 if (!context->tcti_dl)
f9a0ee75 628 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror());
5e521624 629
68d084ce 630 func = dlsym(context->tcti_dl, TSS2_TCTI_INFO_SYMBOL);
5e521624 631 if (!func)
f9a0ee75 632 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
633 "Failed to find TCTI info symbol " TSS2_TCTI_INFO_SYMBOL ": %s",
634 dlerror());
635
636 info = func();
637 if (!info)
f9a0ee75 638 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to get TCTI info data.");
5e521624 639
5e521624
LP
640 log_debug("Loaded TCTI module '%s' (%s) [Version %" PRIu32 "]", info->name, info->description, info->version);
641
642 rc = info->init(NULL, &sz, NULL);
643 if (rc != TPM2_RC_SUCCESS)
f9a0ee75 644 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
645 "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc));
646
68d084ce
DS
647 context->tcti_context = malloc0(sz);
648 if (!context->tcti_context)
f9a0ee75 649 return log_oom_debug();
5e521624 650
68d084ce 651 rc = info->init(context->tcti_context, &sz, param);
5e521624 652 if (rc != TPM2_RC_SUCCESS)
f9a0ee75 653 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
654 "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc));
655 }
656
68d084ce 657 rc = sym_Esys_Initialize(&context->esys_context, context->tcti_context, NULL);
5e521624 658 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 659 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
660 "Failed to initialize TPM context: %s", sym_Tss2_RC_Decode(rc));
661
68d084ce 662 rc = sym_Esys_Startup(context->esys_context, TPM2_SU_CLEAR);
5e521624
LP
663 if (rc == TPM2_RC_INITIALIZE)
664 log_debug("TPM already started up.");
665 else if (rc == TSS2_RC_SUCCESS)
666 log_debug("TPM successfully started up.");
667 else
f9a0ee75 668 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
669 "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc));
670
3a35d6cd
DS
671 r = tpm2_cache_capabilities(context);
672 if (r < 0)
fcdd21ec 673 return log_debug_errno(r, "Failed to cache TPM capabilities: %m");
3a35d6cd 674
a47060bb 675 /* We require AES and CFB support for session encryption. */
cbc92a31 676 if (!tpm2_supports_alg(context, TPM2_ALG_AES))
f9a0ee75 677 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM does not support AES.");
a47060bb 678
cbc92a31 679 if (!tpm2_supports_alg(context, TPM2_ALG_CFB))
f9a0ee75 680 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM does not support CFB.");
a47060bb
DS
681
682 if (!tpm2_supports_tpmt_sym_def(context, &SESSION_TEMPLATE_SYM_AES_128_CFB))
f9a0ee75 683 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM does not support AES-128-CFB.");
a47060bb 684
68d084ce 685 *ret_context = TAKE_PTR(context);
5e521624
LP
686
687 return 0;
688}
689
c8a85240
DS
690static void tpm2_handle_cleanup(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle, bool flush) {
691 TSS2_RC rc;
692
16e16b8c
DS
693 if (!esys_context || esys_handle == ESYS_TR_NONE)
694 return;
695
c8a85240
DS
696 /* Closing the handle removes its reference from the esys_context, but leaves the corresponding
697 * handle in the actual TPM. Flushing the handle removes its reference from the esys_context as well
698 * as removing its corresponding handle from the actual TPM. */
699 if (flush)
700 rc = sym_Esys_FlushContext(esys_context, esys_handle);
701 else
1524184d
DS
702 /* We can't use Esys_TR_Close() because the tpm2-tss library does not use reference counting
703 * for handles, and a single Esys_TR_Close() will remove the handle (internal to the tpm2-tss
704 * library) that might be in use by other code that is using the same ESYS_CONTEXT. This
705 * directly affects us; for example the src/test/test-tpm2.c test function
706 * check_seal_unseal() will encounter this issue and will result in a failure when trying to
707 * cleanup (i.e. Esys_FlushContext) the transient primary key that the test function
708 * generates. However, not calling Esys_TR_Close() here should be ok, since any leaked handle
709 * references will be cleaned up when we free our ESYS_CONTEXT.
710 *
711 * An upstream bug is open here: https://github.com/tpm2-software/tpm2-tss/issues/2693 */
712 rc = TSS2_RC_SUCCESS; // FIXME: restore sym_Esys_TR_Close() use once tpm2-tss is fixed and adopted widely enough
713 if (rc != TSS2_RC_SUCCESS)
714 /* We ignore failures here (besides debug logging), since this is called in error paths,
715 * where we cannot do anything about failures anymore. And when it is called in successful
716 * codepaths by this time we already did what we wanted to do, and got the results we wanted
717 * so there's no reason to make this fail more loudly than necessary. */
c8a85240 718 log_debug("Failed to %s TPM handle, ignoring: %s", flush ? "flush" : "close", sym_Tss2_RC_Decode(rc));
16e16b8c
DS
719}
720
721Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle) {
722 if (!handle)
723 return NULL;
724
1dc8f518 725 _cleanup_(tpm2_context_unrefp) Tpm2Context *context = (Tpm2Context*)handle->tpm2_context;
c8a85240
DS
726 if (context)
727 tpm2_handle_cleanup(context->esys_context, handle->esys_handle, handle->flush);
16e16b8c
DS
728
729 return mfree(handle);
730}
731
732int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) {
1dc8f518 733 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
16e16b8c
DS
734
735 assert(ret_handle);
736
d70e4bc9 737 handle = new(Tpm2Handle, 1);
16e16b8c 738 if (!handle)
f9a0ee75 739 return log_oom_debug();
16e16b8c 740
d70e4bc9
LP
741 *handle = (Tpm2Handle) {
742 .tpm2_context = tpm2_context_ref(context),
743 .esys_handle = ESYS_TR_NONE,
c8a85240 744 .flush = true,
d70e4bc9 745 };
16e16b8c
DS
746
747 *ret_handle = TAKE_PTR(handle);
748
749 return 0;
750}
751
13cf98f3
DS
752/* Create a Tpm2Handle object that references a pre-existing handle in the TPM, at the handle index provided.
753 * This should be used only for persistent, transient, or NV handles; and the handle must already exist in
754 * the TPM at the specified handle index. The handle index should not be 0. Returns 1 if found, 0 if the
755 * index is empty, or < 0 on error. Also see tpm2_get_srk() below; the SRK is a commonly used persistent
756 * Tpm2Handle. */
757int tpm2_index_to_handle(
c8a85240 758 Tpm2Context *c,
13cf98f3 759 TPM2_HANDLE index,
c8a85240 760 const Tpm2Handle *session,
13cf98f3
DS
761 TPM2B_PUBLIC **ret_public,
762 TPM2B_NAME **ret_name,
763 TPM2B_NAME **ret_qname,
c8a85240
DS
764 Tpm2Handle **ret_handle) {
765
766 TSS2_RC rc;
767 int r;
768
769 assert(c);
c8a85240 770
382bfd90 771 /* Only allow persistent, transient, or NV index handle types. */
13cf98f3 772 switch (TPM2_HANDLE_TYPE(index)) {
c8a85240
DS
773 case TPM2_HT_PERSISTENT:
774 case TPM2_HT_NV_INDEX:
775 case TPM2_HT_TRANSIENT:
776 break;
777 case TPM2_HT_PCR:
382bfd90 778 /* PCR handles are referenced by their actual index number and do not need a Tpm2Handle */
f9a0ee75 779 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 780 "Invalid handle 0x%08" PRIx32 " (in PCR range).", index);
c8a85240
DS
781 case TPM2_HT_HMAC_SESSION:
782 case TPM2_HT_POLICY_SESSION:
382bfd90 783 /* Session indexes are only used internally by tpm2-tss (or lower code) */
f9a0ee75 784 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 785 "Invalid handle 0x%08" PRIx32 " (in session range).", index);
382bfd90
DS
786 case TPM2_HT_PERMANENT:
787 /* Permanent handles are defined, e.g. ESYS_TR_RH_OWNER. */
f9a0ee75 788 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 789 "Invalid handle 0x%08" PRIx32 " (in permanent range).", index);
c8a85240 790 default:
f9a0ee75 791 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 792 "Invalid handle 0x%08" PRIx32 " (in unknown range).", index);
c8a85240
DS
793 }
794
0f1cb04f
DS
795 /* For transient handles, the kernel tpm "resource manager" (i.e. /dev/tpmrm0) performs mapping
796 * which breaks GetCapability requests, so only check GetCapability if it's not a transient handle.
797 * https://bugzilla.kernel.org/show_bug.cgi?id=218009 */
798 if (TPM2_HANDLE_TYPE(index) != TPM2_HT_TRANSIENT) { // FIXME: once kernel bug is fixed, check transient handles too
9c180197
DS
799 r = tpm2_get_capability_handle(c, index);
800 if (r < 0)
801 return r;
802 if (r == 0) {
803 log_debug("TPM handle 0x%08" PRIx32 " not populated.", index);
804 if (ret_public)
805 *ret_public = NULL;
806 if (ret_name)
807 *ret_name = NULL;
808 if (ret_qname)
809 *ret_qname = NULL;
810 if (ret_handle)
811 *ret_handle = NULL;
812 return 0;
813 }
c8a85240
DS
814 }
815
816 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
817 r = tpm2_handle_new(c, &handle);
818 if (r < 0)
819 return r;
820
821 /* Since we didn't create this handle in the TPM (this is only creating an ESYS_TR handle for the
822 * pre-existing TPM handle), we shouldn't flush (or evict) it on cleanup. */
823 handle->flush = false;
824
825 rc = sym_Esys_TR_FromTPMPublic(
826 c->esys_context,
13cf98f3 827 index,
c8a85240
DS
828 session ? session->esys_handle : ESYS_TR_NONE,
829 ESYS_TR_NONE,
830 ESYS_TR_NONE,
831 &handle->esys_handle);
832 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 833 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
c8a85240
DS
834 "Failed to read public info: %s", sym_Tss2_RC_Decode(rc));
835
13cf98f3
DS
836 if (ret_public || ret_name || ret_qname) {
837 r = tpm2_read_public(c, session, handle, ret_public, ret_name, ret_qname);
838 if (r < 0)
839 return r;
840 }
841
842 if (ret_handle)
843 *ret_handle = TAKE_PTR(handle);
c8a85240
DS
844
845 return 1;
846}
847
13cf98f3
DS
848/* Get the handle index for the provided Tpm2Handle. */
849int tpm2_index_from_handle(Tpm2Context *c, const Tpm2Handle *handle, TPM2_HANDLE *ret_index) {
850 TSS2_RC rc;
851
852 assert(c);
853 assert(handle);
854 assert(ret_index);
855
856 /* Esys_TR_GetTpmHandle was added to tpm2-tss in version 2.4.0. Once we can set a minimum tpm2-tss
857 * version of 2.4.0 this check can be removed. */
858 if (!sym_Esys_TR_GetTpmHandle)
f9a0ee75 859 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
13cf98f3
DS
860 "libtss2-esys too old, does not include Esys_TR_GetTpmHandle.");
861
862 rc = sym_Esys_TR_GetTpmHandle(c->esys_context, handle->esys_handle, ret_index);
863 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 864 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
13cf98f3
DS
865 "Failed to get handle index: %s", sym_Tss2_RC_Decode(rc));
866
867 return 0;
868}
869
870/* Copy an object in the TPM at a transient handle to a persistent handle.
d2d29c3b 871 *
13cf98f3
DS
872 * The provided transient handle must exist in the TPM in the transient range. The persistent handle may be 0
873 * or any handle in the persistent range. If 0, this will try each handle in the persistent range, in
874 * ascending order, until an available one is found. If non-zero, only the requested persistent handle will
d2d29c3b
DS
875 * be used.
876 *
13cf98f3
DS
877 * Note that the persistent handle parameter is an handle index (i.e. number), while the transient handle is
878 * a Tpm2Handle object. The returned persistent handle will be a Tpm2Handle object that is located in the TPM
879 * at the requested persistent handle index (or the first available if none was requested).
880 *
d2d29c3b 881 * Returns 1 if the object was successfully persisted, or 0 if there is already a key at the requested
13cf98f3 882 * handle, or < 0 on error. Theoretically, this would also return 0 if no specific persistent handle is
fcdd21ec 883 * requested but all persistent handles are used, but it is extremely unlikely the TPM has enough internal
13cf98f3
DS
884 * memory to store the entire persistent range, in which case an error will be returned if the TPM is out of
885 * memory for persistent storage. The persistent handle is only provided when returning 1. */
d2d29c3b
DS
886static int tpm2_persist_handle(
887 Tpm2Context *c,
888 const Tpm2Handle *transient_handle,
889 const Tpm2Handle *session,
13cf98f3 890 TPMI_DH_PERSISTENT persistent_handle_index,
d2d29c3b
DS
891 Tpm2Handle **ret_persistent_handle) {
892
893 /* We don't use TPM2_PERSISTENT_FIRST and TPM2_PERSISTENT_LAST here due to:
894 * https://github.com/systemd/systemd/pull/27713#issuecomment-1591864753 */
895 TPMI_DH_PERSISTENT first = UINT32_C(0x81000000), last = UINT32_C(0x81ffffff);
896 TSS2_RC rc;
897 int r;
898
899 assert(c);
900 assert(transient_handle);
901
13cf98f3
DS
902 /* If persistent handle index specified, only try that. */
903 if (persistent_handle_index != 0) {
904 if (TPM2_HANDLE_TYPE(persistent_handle_index) != TPM2_HT_PERSISTENT)
d2d29c3b 905 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
13cf98f3 906 "Handle not in persistent range: 0x%x", persistent_handle_index);
d2d29c3b 907
13cf98f3 908 first = last = persistent_handle_index;
d2d29c3b
DS
909 }
910
911 for (TPMI_DH_PERSISTENT requested = first; requested <= last; requested++) {
912 _cleanup_(tpm2_handle_freep) Tpm2Handle *persistent_handle = NULL;
913 r = tpm2_handle_new(c, &persistent_handle);
914 if (r < 0)
915 return r;
916
917 /* Since this is a persistent handle, don't flush it. */
918 persistent_handle->flush = false;
919
920 rc = sym_Esys_EvictControl(
921 c->esys_context,
922 ESYS_TR_RH_OWNER,
923 transient_handle->esys_handle,
924 session ? session->esys_handle : ESYS_TR_PASSWORD,
925 ESYS_TR_NONE,
926 ESYS_TR_NONE,
927 requested,
928 &persistent_handle->esys_handle);
929 if (rc == TSS2_RC_SUCCESS) {
930 if (ret_persistent_handle)
931 *ret_persistent_handle = TAKE_PTR(persistent_handle);
932
933 return 1;
934 }
935 if (rc != TPM2_RC_NV_DEFINED)
f9a0ee75 936 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
d2d29c3b
DS
937 "Failed to persist handle: %s", sym_Tss2_RC_Decode(rc));
938 }
939
940 if (ret_persistent_handle)
941 *ret_persistent_handle = NULL;
942
943 return 0;
944}
945
aba5dac3
LP
946#define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited"
947
23e9ccc2 948static int tpm2_credit_random(Tpm2Context *c) {
5e521624
LP
949 size_t rps, done = 0;
950 TSS2_RC rc;
aba5dac3 951 usec_t t;
5e521624
LP
952 int r;
953
954 assert(c);
955
956 /* Pulls some entropy from the TPM and adds it into the kernel RNG pool. That way we can say that the
957 * key we will ultimately generate with the kernel random pool is at least as good as the TPM's RNG,
958 * but likely better. Note that we don't trust the TPM RNG very much, hence do not actually credit
959 * any entropy. */
960
aba5dac3
LP
961 if (access(TPM2_CREDIT_RANDOM_FLAG_PATH, F_OK) < 0) {
962 if (errno != ENOENT)
963 log_debug_errno(errno, "Failed to detect if '" TPM2_CREDIT_RANDOM_FLAG_PATH "' exists, ignoring: %m");
964 } else {
965 log_debug("Not adding TPM2 entropy to the kernel random pool again.");
966 return 0; /* Already done */
967 }
968
969 t = now(CLOCK_MONOTONIC);
970
5e521624
LP
971 for (rps = random_pool_size(); rps > 0;) {
972 _cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL;
973
974 rc = sym_Esys_GetRandom(
23e9ccc2 975 c->esys_context,
5e521624
LP
976 ESYS_TR_NONE,
977 ESYS_TR_NONE,
978 ESYS_TR_NONE,
979 MIN(rps, 32U), /* 32 is supposedly a safe choice, given that AES 256bit keys are this long, and TPM2 baseline requires support for those. */
980 &buffer);
981 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 982 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
983 "Failed to acquire entropy from TPM: %s", sym_Tss2_RC_Decode(rc));
984
985 if (buffer->size == 0)
f9a0ee75 986 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5e521624
LP
987 "Zero-sized entropy returned from TPM.");
988
aba5dac3 989 r = random_write_entropy(-1, buffer->buffer, buffer->size, /* credit= */ false);
5e521624 990 if (r < 0)
f9a0ee75 991 return log_debug_errno(r, "Failed wo write entropy to kernel: %m");
5e521624
LP
992
993 done += buffer->size;
994 rps = LESS_BY(rps, buffer->size);
995 }
996
aba5dac3
LP
997 log_debug("Added %zu bytes of TPM2 entropy to the kernel random pool in %s.", done, FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - t, 0));
998
999 r = touch(TPM2_CREDIT_RANDOM_FLAG_PATH);
1000 if (r < 0)
1001 log_debug_errno(r, "Failed to touch '" TPM2_CREDIT_RANDOM_FLAG_PATH "', ignoring: %m");
1002
5e521624
LP
1003 return 0;
1004}
1005
13cf98f3 1006int tpm2_read_public(
98d6a809
DS
1007 Tpm2Context *c,
1008 const Tpm2Handle *session,
1009 const Tpm2Handle *handle,
1010 TPM2B_PUBLIC **ret_public,
1011 TPM2B_NAME **ret_name,
1012 TPM2B_NAME **ret_qname) {
1013
1014 TSS2_RC rc;
1015
1016 assert(c);
1017 assert(handle);
1018
1019 rc = sym_Esys_ReadPublic(
1020 c->esys_context,
1021 handle->esys_handle,
1022 session ? session->esys_handle : ESYS_TR_NONE,
1023 ESYS_TR_NONE,
1024 ESYS_TR_NONE,
1025 ret_public,
1026 ret_name,
1027 ret_qname);
1028 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 1029 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
98d6a809
DS
1030 "Failed to read public info: %s", sym_Tss2_RC_Decode(rc));
1031
1032 return 0;
1033}
1034
f4f5b3a9
DS
1035/* Get one of the legacy primary key templates.
1036 *
1037 * The legacy templates should only be used for older sealed data that did not use the SRK. Instead of a
1038 * persistent SRK, a transient key was created to seal the data and then flushed; and the exact same template
1039 * must be used to recreate the same transient key to unseal the data. The alg parameter must be TPM2_ALG_RSA
1040 * or TPM2_ALG_ECC. This does not check if the alg is actually supported on this TPM. */
1041static int tpm2_get_legacy_template(TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template) {
1042 /* Do not modify. */
1043 static const TPMT_PUBLIC legacy_ecc = {
1044 .type = TPM2_ALG_ECC,
1045 .nameAlg = TPM2_ALG_SHA256,
1046 .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
1047 .parameters.eccDetail = {
1048 .symmetric = {
1049 .algorithm = TPM2_ALG_AES,
1050 .keyBits.aes = 128,
1051 .mode.aes = TPM2_ALG_CFB,
5e521624 1052 },
f4f5b3a9
DS
1053 .scheme.scheme = TPM2_ALG_NULL,
1054 .curveID = TPM2_ECC_NIST_P256,
1055 .kdf.scheme = TPM2_ALG_NULL,
5e521624 1056 },
f4f5b3a9
DS
1057 };
1058
1059 /* Do not modify. */
1060 static const TPMT_PUBLIC legacy_rsa = {
1061 .type = TPM2_ALG_RSA,
1062 .nameAlg = TPM2_ALG_SHA256,
1063 .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
1064 .parameters.rsaDetail = {
1065 .symmetric = {
1066 .algorithm = TPM2_ALG_AES,
1067 .keyBits.aes = 128,
1068 .mode.aes = TPM2_ALG_CFB,
acbb504e 1069 },
f4f5b3a9
DS
1070 .scheme.scheme = TPM2_ALG_NULL,
1071 .keyBits = 2048,
acbb504e 1072 },
f4f5b3a9
DS
1073 };
1074
1075 assert(ret_template);
1076
1077 if (alg == TPM2_ALG_ECC)
1078 *ret_template = legacy_ecc;
1079 else if (alg == TPM2_ALG_RSA)
1080 *ret_template = legacy_rsa;
1081 else
1082 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1083 "Unsupported legacy SRK alg: 0x%x", alg);
1084
1085 return 0;
1086}
1087
1088/* Get a Storage Root Key (SRK) template.
1089 *
1090 * The SRK template values are recommended by the "TCG TPM v2.0 Provisioning Guidance" document in section
1091 * 7.5.1 "Storage Primary Key (SRK) Templates", referencing "TCG EK Credential Profile for TPM Family 2.0".
1092 * The EK Credential Profile version 2.0 provides only a single template each for RSA and ECC, while later EK
1093 * Credential Profile versions provide more templates, and keep the original templates as "L-1" (for RSA) and
1094 * "L-2" (for ECC).
1095 *
1096 * https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance
1097 * https://trustedcomputinggroup.org/resource/http-trustedcomputinggroup-org-wp-content-uploads-tcg-ek-credential-profile
1098 *
1099 * These templates are only needed to create a new persistent SRK (or a new transient key that is
1100 * SRK-compatible). Preferably, the TPM should contain a shared SRK located at the reserved shared SRK handle
adcd3266 1101 * (see TPM2_SRK_HANDLE in tpm2-util.h, and tpm2_get_srk() below).
f4f5b3a9
DS
1102 *
1103 * The alg must be TPM2_ALG_RSA or TPM2_ALG_ECC. Returns error if the requested template is not supported on
cea525a9 1104 * this TPM. Also see tpm2_get_best_srk_template() below. */
f4f5b3a9
DS
1105static int tpm2_get_srk_template(Tpm2Context *c, TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template) {
1106 /* The attributes are the same between ECC and RSA templates. This has the changes specified in the
1107 * Provisioning Guidance document, specifically:
1108 * TPMA_OBJECT_USERWITHAUTH is added.
1109 * TPMA_OBJECT_ADMINWITHPOLICY is removed.
1110 * TPMA_OBJECT_NODA is added. */
1111 TPMA_OBJECT srk_attributes =
1112 TPMA_OBJECT_DECRYPT |
1113 TPMA_OBJECT_FIXEDPARENT |
1114 TPMA_OBJECT_FIXEDTPM |
1115 TPMA_OBJECT_NODA |
1116 TPMA_OBJECT_RESTRICTED |
1117 TPMA_OBJECT_SENSITIVEDATAORIGIN |
1118 TPMA_OBJECT_USERWITHAUTH;
1119
1120 /* The symmetric configuration is the same between ECC and RSA templates. */
1121 TPMT_SYM_DEF_OBJECT srk_symmetric = {
1122 .algorithm = TPM2_ALG_AES,
1123 .keyBits.aes = 128,
1124 .mode.aes = TPM2_ALG_CFB,
1125 };
1126
1127 /* Both templates have an empty authPolicy as specified by the Provisioning Guidance document. */
1128
1129 /* From the EK Credential Profile template "L-2". */
1130 TPMT_PUBLIC srk_ecc = {
1131 .type = TPM2_ALG_ECC,
1132 .nameAlg = TPM2_ALG_SHA256,
1133 .objectAttributes = srk_attributes,
1134 .parameters.eccDetail = {
1135 .symmetric = srk_symmetric,
1136 .scheme.scheme = TPM2_ALG_NULL,
1137 .curveID = TPM2_ECC_NIST_P256,
1138 .kdf.scheme = TPM2_ALG_NULL,
acbb504e 1139 },
f4f5b3a9
DS
1140 };
1141
1142 /* From the EK Credential Profile template "L-1". */
1143 TPMT_PUBLIC srk_rsa = {
1144 .type = TPM2_ALG_RSA,
1145 .nameAlg = TPM2_ALG_SHA256,
1146 .objectAttributes = srk_attributes,
1147 .parameters.rsaDetail = {
1148 .symmetric = srk_symmetric,
1149 .scheme.scheme = TPM2_ALG_NULL,
1150 .keyBits = 2048,
2b92a672
LP
1151 },
1152 };
1153
f4f5b3a9
DS
1154 assert(c);
1155 assert(ret_template);
1156
1157 if (alg == TPM2_ALG_ECC) {
1158 if (!tpm2_supports_alg(c, TPM2_ALG_ECC))
1159 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1160 "TPM does not support ECC.");
1161
1162 if (!tpm2_supports_ecc_curve(c, srk_ecc.parameters.eccDetail.curveID))
1163 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1164 "TPM does not support ECC-NIST-P256 curve.");
1165
1166 if (!tpm2_supports_tpmt_public(c, &srk_ecc))
1167 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1168 "TPM does not support SRK ECC template L-2.");
1169
1170 *ret_template = srk_ecc;
1171 return 0;
1172 }
1173
1174 if (alg == TPM2_ALG_RSA) {
1175 if (!tpm2_supports_alg(c, TPM2_ALG_RSA))
1176 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1177 "TPM does not support RSA.");
1178
1179 if (!tpm2_supports_tpmt_public(c, &srk_rsa))
1180 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1181 "TPM does not support SRK RSA template L-1.");
1182
1183 *ret_template = srk_rsa;
1184 return 0;
1185 }
1186
1187 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported SRK alg: 0x%x.", alg);
acbb504e
WR
1188}
1189
cea525a9
DS
1190/* Get the best supported SRK template. ECC is preferred, then RSA. */
1191static int tpm2_get_best_srk_template(Tpm2Context *c, TPMT_PUBLIC *ret_template) {
1192 if (tpm2_get_srk_template(c, TPM2_ALG_ECC, ret_template) >= 0 ||
1193 tpm2_get_srk_template(c, TPM2_ALG_RSA, ret_template) >= 0)
1194 return 0;
1195
1196 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1197 "TPM does not support either SRK template L-1 (RSA) or L-2 (ECC).");
1198}
1199
cea525a9
DS
1200/* Get the SRK. Returns 1 if SRK is found, 0 if there is no SRK, or < 0 on error. Also see
1201 * tpm2_get_or_create_srk() below. */
acbb504e
WR
1202static int tpm2_get_srk(
1203 Tpm2Context *c,
c8a85240 1204 const Tpm2Handle *session,
98d6a809
DS
1205 TPM2B_PUBLIC **ret_public,
1206 TPM2B_NAME **ret_name,
1207 TPM2B_NAME **ret_qname,
c8a85240 1208 Tpm2Handle **ret_handle) {
acbb504e 1209
13cf98f3 1210 return tpm2_index_to_handle(c, TPM2_SRK_HANDLE, session, ret_public, ret_name, ret_qname, ret_handle);
acbb504e
WR
1211}
1212
3ed34256
DS
1213/* Get the SRK, creating one if needed. Returns 1 if a new SRK was created and persisted, 0 if an SRK already
1214 * exists, or < 0 on error. */
2e64cb71 1215int tpm2_get_or_create_srk(
cea525a9
DS
1216 Tpm2Context *c,
1217 const Tpm2Handle *session,
1218 TPM2B_PUBLIC **ret_public,
1219 TPM2B_NAME **ret_name,
1220 TPM2B_NAME **ret_qname,
1221 Tpm2Handle **ret_handle) {
1222
1223 int r;
1224
1225 r = tpm2_get_srk(c, session, ret_public, ret_name, ret_qname, ret_handle);
1226 if (r < 0)
1227 return r;
1228 if (r == 1)
2e64cb71 1229 return 0; /* 0 → SRK already set up */
cea525a9
DS
1230
1231 /* No SRK, create and persist one */
aff853f8
DS
1232 TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
1233 r = tpm2_get_best_srk_template(c, &template.publicArea);
cea525a9 1234 if (r < 0)
f9a0ee75 1235 return log_debug_errno(r, "Could not get best SRK template: %m");
cea525a9
DS
1236
1237 _cleanup_(tpm2_handle_freep) Tpm2Handle *transient_handle = NULL;
aff853f8 1238 r = tpm2_create_primary(
cea525a9 1239 c,
cea525a9
DS
1240 session,
1241 &template,
1242 /* sensitive= */ NULL,
1243 /* ret_public= */ NULL,
cea525a9
DS
1244 &transient_handle);
1245 if (r < 0)
1246 return r;
1247
1248 /* Try to persist the transient SRK we created. No locking needed; if multiple threads are trying to
1249 * persist SRKs concurrently, only one will succeed (r == 1) while the rest will fail (r == 0). In
1250 * either case, all threads will get the persistent SRK below. */
1251 r = tpm2_persist_handle(c, transient_handle, session, TPM2_SRK_HANDLE, /* ret_persistent_handle= */ NULL);
1252 if (r < 0)
1253 return r;
1254
1255 /* The SRK should exist now. */
1256 r = tpm2_get_srk(c, session, ret_public, ret_name, ret_qname, ret_handle);
1257 if (r < 0)
1258 return r;
1259 if (r == 0)
1260 /* This should never happen. */
f9a0ee75 1261 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "SRK we just persisted couldn't be found.");
cea525a9 1262
2e64cb71 1263 return 1; /* > 0 → SRK newly set up */
cea525a9
DS
1264}
1265
c69bd0ab
DS
1266/* Utility functions for TPMS_PCR_SELECTION. */
1267
1268/* Convert a TPMS_PCR_SELECTION object to a mask. */
dbaae766 1269uint32_t tpm2_tpms_pcr_selection_to_mask(const TPMS_PCR_SELECTION *s) {
c69bd0ab
DS
1270 assert(s);
1271 assert(s->sizeofSelect <= sizeof(s->pcrSelect));
321a9d9e 1272
c69bd0ab
DS
1273 uint32_t mask = 0;
1274 for (unsigned i = 0; i < s->sizeofSelect; i++)
1275 SET_FLAG(mask, (uint32_t)s->pcrSelect[i] << (i * 8), true);
dbaae766 1276 return mask;
c69bd0ab 1277}
321a9d9e 1278
c69bd0ab
DS
1279/* Convert a mask and hash alg to a TPMS_PCR_SELECTION object. */
1280void tpm2_tpms_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash_alg, TPMS_PCR_SELECTION *ret) {
1281 assert(ret);
1282
1283 /* This is currently hardcoded at 24 PCRs, above. */
1284 if (!TPM2_PCR_MASK_VALID(mask))
f9a0ee75
DS
1285 log_debug("PCR mask selections (%x) out of range, ignoring.",
1286 mask & ~((uint32_t)TPM2_PCRS_MASK));
c69bd0ab
DS
1287
1288 *ret = (TPMS_PCR_SELECTION){
1289 .hash = hash_alg,
1290 .sizeofSelect = TPM2_PCRS_MAX / 8,
1291 .pcrSelect[0] = mask & 0xff,
1292 .pcrSelect[1] = (mask >> 8) & 0xff,
1293 .pcrSelect[2] = (mask >> 16) & 0xff,
1294 };
1295}
1296
13b55174
DS
1297/* Test if all bits in the mask are set in the TPMS_PCR_SELECTION. */
1298bool tpm2_tpms_pcr_selection_has_mask(const TPMS_PCR_SELECTION *s, uint32_t mask) {
1299 assert(s);
1300
1301 return FLAGS_SET(tpm2_tpms_pcr_selection_to_mask(s), mask);
1302}
1303
1304static void tpm2_tpms_pcr_selection_update_mask(TPMS_PCR_SELECTION *s, uint32_t mask, bool b) {
1305 assert(s);
1306
1307 tpm2_tpms_pcr_selection_from_mask(UPDATE_FLAG(tpm2_tpms_pcr_selection_to_mask(s), mask, b), s->hash, s);
1308}
1309
1310/* Add all PCR selections in the mask. */
1311void tpm2_tpms_pcr_selection_add_mask(TPMS_PCR_SELECTION *s, uint32_t mask) {
1312 tpm2_tpms_pcr_selection_update_mask(s, mask, 1);
1313}
1314
1315/* Remove all PCR selections in the mask. */
1316void tpm2_tpms_pcr_selection_sub_mask(TPMS_PCR_SELECTION *s, uint32_t mask) {
1317 tpm2_tpms_pcr_selection_update_mask(s, mask, 0);
1318}
1319
c69bd0ab
DS
1320/* Add all PCR selections in 'b' to 'a'. Both must have the same hash alg. */
1321void tpm2_tpms_pcr_selection_add(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b) {
1322 assert(a);
1323 assert(b);
1324 assert(a->hash == b->hash);
1325
13b55174 1326 tpm2_tpms_pcr_selection_add_mask(a, tpm2_tpms_pcr_selection_to_mask(b));
c69bd0ab
DS
1327}
1328
1329/* Remove all PCR selections in 'b' from 'a'. Both must have the same hash alg. */
1330void tpm2_tpms_pcr_selection_sub(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b) {
1331 assert(a);
1332 assert(b);
1333 assert(a->hash == b->hash);
1334
13b55174 1335 tpm2_tpms_pcr_selection_sub_mask(a, tpm2_tpms_pcr_selection_to_mask(b));
c69bd0ab
DS
1336}
1337
1338/* Move all PCR selections in 'b' to 'a'. Both must have the same hash alg. */
1339void tpm2_tpms_pcr_selection_move(TPMS_PCR_SELECTION *a, TPMS_PCR_SELECTION *b) {
1340 if (a == b)
1341 return;
1342
1343 tpm2_tpms_pcr_selection_add(a, b);
1344 tpm2_tpms_pcr_selection_from_mask(0, b->hash, b);
1345}
1346
193fd573
DS
1347#define FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \
1348 _FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml, UNIQ_T(l, UNIQ))
1349#define _FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml, l) \
1350 for (typeof(tpml) (l) = (tpml); (l); (l) = NULL) \
1351 FOREACH_ARRAY(tpms, (l)->pcrSelections, (l)->count)
1352
c69bd0ab 1353#define FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms) \
dbaae766 1354 FOREACH_PCR_IN_MASK(pcr, tpm2_tpms_pcr_selection_to_mask(tpms))
c69bd0ab 1355
c69bd0ab
DS
1356#define FOREACH_PCR_IN_TPML_PCR_SELECTION(pcr, tpms, tpml) \
1357 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(tpms, tpml) \
1358 FOREACH_PCR_IN_TPMS_PCR_SELECTION(pcr, tpms)
1359
1360char *tpm2_tpms_pcr_selection_to_string(const TPMS_PCR_SELECTION *s) {
1361 assert(s);
1362
1363 const char *algstr = strna(tpm2_hash_alg_to_string(s->hash));
1364
dbaae766
DS
1365 _cleanup_free_ char *mask = tpm2_pcr_mask_to_string(tpm2_tpms_pcr_selection_to_mask(s));
1366 if (!mask)
c69bd0ab
DS
1367 return NULL;
1368
dbaae766 1369 return strjoin(algstr, "(", mask, ")");
c69bd0ab
DS
1370}
1371
1372size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s) {
1373 assert(s);
1374
dbaae766 1375 return popcount(tpm2_tpms_pcr_selection_to_mask(s));
c69bd0ab
DS
1376}
1377
1378/* Utility functions for TPML_PCR_SELECTION. */
1379
1380/* Remove the (0-based) index entry from 'l', shift all following entries, and update the count. */
1381static void tpm2_tpml_pcr_selection_remove_index(TPML_PCR_SELECTION *l, uint32_t index) {
1382 assert(l);
9afd4dde 1383 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1384 assert(index < l->count);
1385
1386 size_t s = l->count - (index + 1);
1387 memmove(&l->pcrSelections[index], &l->pcrSelections[index + 1], s * sizeof(l->pcrSelections[0]));
1388 l->count--;
1389}
1390
1391/* Get a TPMS_PCR_SELECTION from a TPML_PCR_SELECTION for the given hash alg. Returns NULL if there is no
1392 * entry for the hash alg. This guarantees the returned entry contains all the PCR selections for the given
1393 * hash alg, which may require modifying the TPML_PCR_SELECTION by removing duplicate entries. */
1394static TPMS_PCR_SELECTION *tpm2_tpml_pcr_selection_get_tpms_pcr_selection(
1395 TPML_PCR_SELECTION *l,
1396 TPMI_ALG_HASH hash_alg) {
1397
1398 assert(l);
9afd4dde 1399 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1400
1401 TPMS_PCR_SELECTION *selection = NULL;
1402 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l)
1403 if (s->hash == hash_alg) {
1404 selection = s;
1405 break;
1406 }
1407
1408 if (!selection)
1409 return NULL;
1410
1411 /* Iterate backwards through the entries, removing any other entries for the hash alg. */
1412 for (uint32_t i = l->count - 1; i > 0; i--) {
1413 TPMS_PCR_SELECTION *s = &l->pcrSelections[i];
1414
1415 if (selection == s)
1416 break;
1417
1418 if (s->hash == hash_alg) {
1419 tpm2_tpms_pcr_selection_move(selection, s);
1420 tpm2_tpml_pcr_selection_remove_index(l, i);
4dde902e 1421 }
c69bd0ab
DS
1422 }
1423
1424 return selection;
1425}
1426
193fd573
DS
1427/* Combine all duplicate (same hash alg) TPMS_PCR_SELECTION entries in 'l'. */
1428static void tpm2_tpml_pcr_selection_cleanup(TPML_PCR_SELECTION *l) {
1429 /* Can't use FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION() because we might modify l->count */
1430 for (uint32_t i = 0; i < l->count; i++)
1431 /* This removes all duplicate TPMS_PCR_SELECTION entries for this hash. */
1432 (void) tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, l->pcrSelections[i].hash);
1433}
1434
dbaae766
DS
1435/* Convert a TPML_PCR_SELECTION object to a mask. Returns empty mask (i.e. 0) if 'hash_alg' is not in the object. */
1436uint32_t tpm2_tpml_pcr_selection_to_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash_alg) {
c69bd0ab 1437 assert(l);
c69bd0ab
DS
1438
1439 /* Make a copy, as tpm2_tpml_pcr_selection_get_tpms_pcr_selection() will modify the object if there
1440 * are multiple entries with the requested hash alg. */
1441 TPML_PCR_SELECTION lcopy = *l;
1442
1443 TPMS_PCR_SELECTION *s;
1444 s = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(&lcopy, hash_alg);
1445 if (!s)
dbaae766 1446 return 0;
c69bd0ab 1447
dbaae766 1448 return tpm2_tpms_pcr_selection_to_mask(s);
c69bd0ab
DS
1449}
1450
1451/* Convert a mask and hash alg to a TPML_PCR_SELECTION object. */
1452void tpm2_tpml_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash_alg, TPML_PCR_SELECTION *ret) {
1453 assert(ret);
1454
1455 TPMS_PCR_SELECTION s;
1456 tpm2_tpms_pcr_selection_from_mask(mask, hash_alg, &s);
1457
1458 *ret = (TPML_PCR_SELECTION){
1459 .count = 1,
1460 .pcrSelections[0] = s,
321a9d9e
LP
1461 };
1462}
1463
c69bd0ab
DS
1464/* Add the PCR selections in 's' to the corresponding hash alg TPMS_PCR_SELECTION entry in 'l'. Adds a new
1465 * TPMS_PCR_SELECTION entry for the hash alg if needed. This may modify the TPML_PCR_SELECTION by combining
1466 * entries with the same hash alg. */
1467void tpm2_tpml_pcr_selection_add_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s) {
1468 assert(l);
1469 assert(s);
1470
1471 if (tpm2_tpms_pcr_selection_is_empty(s))
1472 return;
1473
1474 TPMS_PCR_SELECTION *selection = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash);
1475 if (selection) {
1476 tpm2_tpms_pcr_selection_add(selection, s);
1477 return;
1478 }
1479
1480 /* It's already broken if the count is higher than the array has size for. */
9afd4dde 1481 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1482
1483 /* If full, the cleanup should result in at least one available entry. */
9afd4dde 1484 if (l->count == ELEMENTSOF(l->pcrSelections))
c69bd0ab
DS
1485 tpm2_tpml_pcr_selection_cleanup(l);
1486
9afd4dde 1487 assert(l->count < ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1488 l->pcrSelections[l->count++] = *s;
1489}
1490
1491/* Remove the PCR selections in 's' from the corresponding hash alg TPMS_PCR_SELECTION entry in 'l'. This
1492 * will combine all entries for 's->hash' in 'l'. */
1493void tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s) {
1494 assert(l);
1495 assert(s);
1496
1497 if (tpm2_tpms_pcr_selection_is_empty(s))
1498 return;
1499
1500 TPMS_PCR_SELECTION *selection = tpm2_tpml_pcr_selection_get_tpms_pcr_selection(l, s->hash);
1501 if (selection)
1502 tpm2_tpms_pcr_selection_sub(selection, s);
1503}
1504
13b55174
DS
1505/* Test if all bits in the mask for the hash are set in the TPML_PCR_SELECTION. */
1506bool tpm2_tpml_pcr_selection_has_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask) {
1507 assert(l);
1508
1509 return FLAGS_SET(tpm2_tpml_pcr_selection_to_mask(l, hash), mask);
1510}
1511
1512/* Add the PCR selections in the mask, with the provided hash. */
1513void tpm2_tpml_pcr_selection_add_mask(TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask) {
1514 TPMS_PCR_SELECTION tpms;
1515
1516 assert(l);
1517
1518 tpm2_tpms_pcr_selection_from_mask(mask, hash, &tpms);
1519 tpm2_tpml_pcr_selection_add_tpms_pcr_selection(l, &tpms);
1520}
1521
1522/* Remove the PCR selections in the mask, with the provided hash. */
1523void tpm2_tpml_pcr_selection_sub_mask(TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask) {
1524 TPMS_PCR_SELECTION tpms;
1525
1526 assert(l);
1527
1528 tpm2_tpms_pcr_selection_from_mask(mask, hash, &tpms);
1529 tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(l, &tpms);
1530}
1531
c69bd0ab
DS
1532/* Add all PCR selections in 'b' to 'a'. */
1533void tpm2_tpml_pcr_selection_add(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b) {
1534 assert(a);
1535 assert(b);
1536
193fd573 1537 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection_b, b)
c69bd0ab
DS
1538 tpm2_tpml_pcr_selection_add_tpms_pcr_selection(a, selection_b);
1539}
1540
1541/* Remove all PCR selections in 'b' from 'a'. */
1542void tpm2_tpml_pcr_selection_sub(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b) {
1543 assert(a);
1544 assert(b);
1545
193fd573 1546 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection_b, b)
c69bd0ab
DS
1547 tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(a, selection_b);
1548}
1549
1550char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l) {
1551 assert(l);
1552
1553 _cleanup_free_ char *banks = NULL;
193fd573 1554 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) {
c69bd0ab
DS
1555 if (tpm2_tpms_pcr_selection_is_empty(s))
1556 continue;
1557
1558 _cleanup_free_ char *str = tpm2_tpms_pcr_selection_to_string(s);
1559 if (!str || !strextend_with_separator(&banks, ",", str))
1560 return NULL;
1561 }
1562
1563 return strjoin("[", strempty(banks), "]");
1564}
1565
1566size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l) {
1567 assert(l);
9afd4dde 1568 assert(l->count <= ELEMENTSOF(l->pcrSelections));
c69bd0ab
DS
1569
1570 size_t weight = 0;
1571 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(s, l) {
1572 size_t w = tpm2_tpms_pcr_selection_weight(s);
1573 assert(weight <= SIZE_MAX - w);
1574 weight += w;
1575 }
1576
1577 return weight;
1578}
1579
cc1a78d5 1580bool tpm2_pcr_value_valid(const Tpm2PCRValue *pcr_value) {
323eb480
DS
1581 int r;
1582
064ac95d
DS
1583 if (!pcr_value)
1584 return false;
323eb480
DS
1585
1586 if (!TPM2_PCR_INDEX_VALID(pcr_value->index)) {
1587 log_debug("PCR index %u invalid.", pcr_value->index);
1588 return false;
1589 }
1590
1591 /* If it contains a value, the value size must match the hash size. */
1592 if (pcr_value->value.size > 0) {
1593 r = tpm2_hash_alg_to_size(pcr_value->hash);
1594 if (r < 0)
1595 return false;
1596
3cd4145f 1597 if (pcr_value->value.size != (size_t) r) {
323eb480
DS
1598 log_debug("PCR hash 0x%" PRIx16 " expected size %d does not match actual size %" PRIu16 ".",
1599 pcr_value->hash, r, pcr_value->value.size);
1600 return false;
1601 }
1602 }
1603
1604 return true;
1605}
1606
1607/* Verify all entries are valid, and consistent with each other. The requirements for consistency are:
1608 *
1609 * 1) all entries must be sorted in ascending order (e.g. using tpm2_sort_pcr_values())
1610 * 2) all entries must be unique, i.e. there cannot be 2 entries with the same hash and index
064ac95d
DS
1611 *
1612 * Returns true if all entries are valid (or if no entries are provided), false otherwise.
323eb480 1613 */
cc1a78d5 1614bool tpm2_pcr_values_valid(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
064ac95d
DS
1615 if (!pcr_values && n_pcr_values > 0)
1616 return false;
323eb480 1617
193fd573
DS
1618 const Tpm2PCRValue *previous = NULL;
1619 FOREACH_ARRAY(current, pcr_values, n_pcr_values) {
1620 if (!tpm2_pcr_value_valid(current))
323eb480
DS
1621 return false;
1622
193fd573
DS
1623 if (!previous) {
1624 previous = current;
323eb480 1625 continue;
193fd573 1626 }
323eb480
DS
1627
1628 /* Hashes must be sorted in ascending order */
193fd573 1629 if (current->hash < previous->hash) {
323eb480 1630 log_debug("PCR values not in ascending order, hash %" PRIu16 " is after %" PRIu16 ".",
193fd573 1631 current->hash, previous->hash);
323eb480
DS
1632 return false;
1633 }
1634
193fd573 1635 if (current->hash == previous->hash) {
323eb480 1636 /* Indexes (for the same hash) must be sorted in ascending order */
193fd573 1637 if (current->index < previous->index) {
323eb480 1638 log_debug("PCR values not in ascending order, hash %" PRIu16 " index %u is after %u.",
193fd573 1639 current->hash, current->index, previous->index);
323eb480
DS
1640 return false;
1641 }
1642
1643 /* Indexes (for the same hash) must not be duplicates */
193fd573 1644 if (current->index == previous->index) {
323eb480 1645 log_debug("PCR values contain duplicates for hash %" PRIu16 " index %u.",
193fd573 1646 current->hash, previous->index);
323eb480
DS
1647 return false;
1648 }
1649 }
1650 }
1651
1652 return true;
1653}
1654
26d8d71f
DS
1655/* Returns true if any of the provided PCR values has an actual hash value included, false otherwise. */
1656bool tpm2_pcr_values_has_any_values(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1657 assert(pcr_values || n_pcr_values == 0);
1658
1659 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
1660 if (v->value.size > 0)
1661 return true;
1662
1663 return false;
1664}
1665
1666/* Returns true if all of the provided PCR values has an actual hash value included, false otherwise. */
1667bool tpm2_pcr_values_has_all_values(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1668 assert(pcr_values || n_pcr_values == 0);
1669
1670 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
1671 if (v->value.size == 0)
1672 return false;
1673
1674 return true;
1675}
1676
323eb480
DS
1677static int cmp_pcr_values(const Tpm2PCRValue *a, const Tpm2PCRValue *b) {
1678 assert(a);
1679 assert(b);
1680
1681 return CMP(a->hash, b->hash) ?: CMP(a->index, b->index);
1682}
1683
1684/* Sort the array of Tpm2PCRValue entries in-place. This sorts first in ascending order of hash algorithm
1685 * (sorting simply by the TPM2 hash algorithm number), and then sorting by pcr index. */
1686void tpm2_sort_pcr_values(Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1687 typesafe_qsort(pcr_values, n_pcr_values, cmp_pcr_values);
1688}
1689
1690int tpm2_pcr_values_from_mask(uint32_t mask, TPMI_ALG_HASH hash, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values) {
1691 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
1692 size_t n_pcr_values = 0;
1693
1694 assert(ret_pcr_values);
1695 assert(ret_n_pcr_values);
1696
1697 FOREACH_PCR_IN_MASK(index, mask)
1698 if (!GREEDY_REALLOC_APPEND(
1699 pcr_values,
1700 n_pcr_values,
1701 &TPM2_PCR_VALUE_MAKE(index, hash, {}),
1702 1))
1703 return log_oom_debug();
1704
1705 *ret_pcr_values = TAKE_PTR(pcr_values);
1706 *ret_n_pcr_values = n_pcr_values;
1707
1708 return 0;
1709}
1710
1711int tpm2_pcr_values_to_mask(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPMI_ALG_HASH hash, uint32_t *ret_mask) {
1712 uint32_t mask = 0;
1713
1714 assert(pcr_values || n_pcr_values == 0);
1715 assert(ret_mask);
1716
cc1a78d5 1717 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
323eb480
DS
1718 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PCR values.");
1719
193fd573
DS
1720 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
1721 if (v->hash == hash)
1722 SET_BIT(mask, v->index);
323eb480
DS
1723
1724 *ret_mask = mask;
1725
1726 return 0;
1727}
1728
1729int tpm2_tpml_pcr_selection_from_pcr_values(
1730 const Tpm2PCRValue *pcr_values,
1731 size_t n_pcr_values,
1732 TPML_PCR_SELECTION *ret_selection,
1733 TPM2B_DIGEST **ret_values,
1734 size_t *ret_n_values) {
1735
1736 TPML_PCR_SELECTION selection = {};
1737 _cleanup_free_ TPM2B_DIGEST *values = NULL;
1738 size_t n_values = 0;
1739
1740 assert(pcr_values || n_pcr_values == 0);
1741
cc1a78d5 1742 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
323eb480
DS
1743 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "PCR values are not valid.");
1744
193fd573
DS
1745 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
1746 tpm2_tpml_pcr_selection_add_mask(&selection, v->hash, INDEX_TO_MASK(uint32_t, v->index));
323eb480 1747
193fd573 1748 if (!GREEDY_REALLOC_APPEND(values, n_values, &v->value, 1))
323eb480
DS
1749 return log_oom_debug();
1750 }
1751
1752 if (ret_selection)
1753 *ret_selection = selection;
1754 if (ret_values)
1755 *ret_values = TAKE_PTR(values);
1756 if (ret_n_values)
1757 *ret_n_values = n_values;
1758
1759 return 0;
1760}
1761
1762/* Count the number of different hash algorithms for all the entries. */
1763int tpm2_pcr_values_hash_count(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, size_t *ret_count) {
1764 TPML_PCR_SELECTION selection;
1765 int r;
1766
1767 assert(pcr_values);
1768 assert(ret_count);
1769
1770 r = tpm2_tpml_pcr_selection_from_pcr_values(
1771 pcr_values,
1772 n_pcr_values,
1773 &selection,
1774 /* ret_values= */ NULL,
1775 /* ret_n_values= */ NULL);
1776 if (r < 0)
1777 return r;
1778
1779 *ret_count = selection.count;
1780
1781 return 0;
1782}
1783
1784/* Parse a string argument into a Tpm2PCRValue object.
1785 *
1786 * The format is <index>[:hash[=value]] where index is the index number (or name) of the PCR, e.g. 0 (or
1787 * platform-code), hash is the name of the hash algorithm (e.g. sha256) and value is the hex hash digest
1788 * value, optionally with a leading 0x. This does not check for validity of the fields. */
1789int tpm2_pcr_value_from_string(const char *arg, Tpm2PCRValue *ret_pcr_value) {
1790 Tpm2PCRValue pcr_value = {};
1791 const char *p = arg;
1792 int r;
1793
1794 assert(arg);
1795 assert(ret_pcr_value);
1796
1797 _cleanup_free_ char *index = NULL;
1798 r = extract_first_word(&p, &index, ":", /* flags= */ 0);
1799 if (r < 1)
f9a0ee75 1800 return log_debug_errno(r, "Could not parse pcr value '%s': %m", p);
323eb480 1801
2099cd62 1802 r = tpm2_pcr_index_from_string(index);
323eb480 1803 if (r < 0)
f9a0ee75 1804 return log_debug_errno(r, "Invalid pcr index '%s': %m", index);
323eb480
DS
1805 pcr_value.index = (unsigned) r;
1806
1807 if (!isempty(p)) {
1808 _cleanup_free_ char *hash = NULL;
1809 r = extract_first_word(&p, &hash, "=", /* flags= */ 0);
1810 if (r < 1)
f9a0ee75 1811 return log_debug_errno(r, "Could not parse pcr hash algorithm '%s': %m", p);
323eb480
DS
1812
1813 r = tpm2_hash_alg_from_string(hash);
1814 if (r < 0)
f9a0ee75 1815 return log_debug_errno(r, "Invalid pcr hash algorithm '%s': %m", hash);
323eb480 1816 pcr_value.hash = (TPMI_ALG_HASH) r;
323eb480 1817
2b2ee3f2
DS
1818 if (!isempty(p)) {
1819 /* Remove leading 0x if present */
1820 p = startswith_no_case(p, "0x") ?: p;
323eb480 1821
2b2ee3f2
DS
1822 _cleanup_free_ void *buf = NULL;
1823 size_t buf_size = 0;
1824 r = unhexmem(p, SIZE_MAX, &buf, &buf_size);
1825 if (r < 0)
f9a0ee75 1826 return log_debug_errno(r, "Invalid pcr hash value '%s': %m", p);
323eb480 1827
2b2ee3f2
DS
1828 r = TPM2B_DIGEST_CHECK_SIZE(buf_size);
1829 if (r < 0)
f9a0ee75 1830 return log_debug_errno(r, "PCR hash value size %zu too large.", buf_size);
53b91e19 1831
2b2ee3f2
DS
1832 pcr_value.value = TPM2B_DIGEST_MAKE(buf, buf_size);
1833 }
323eb480
DS
1834 }
1835
1836 *ret_pcr_value = pcr_value;
1837
1838 return 0;
1839}
1840
1841/* Return a string for the PCR value. The format is described in tpm2_pcr_value_from_string(). Note that if
1842 * the hash algorithm is not recognized, neither hash name nor hash digest value is included in the
1843 * string. This does not check for validity. */
1844char *tpm2_pcr_value_to_string(const Tpm2PCRValue *pcr_value) {
1845 _cleanup_free_ char *index = NULL, *value = NULL;
323eb480 1846
495f2bf5 1847 if (asprintf(&index, "%u", pcr_value->index) < 0)
323eb480
DS
1848 return NULL;
1849
8e757259 1850 const char *hash = pcr_value->hash > 0 ? tpm2_hash_alg_to_string(pcr_value->hash) : NULL;
323eb480
DS
1851
1852 if (hash && pcr_value->value.size > 0) {
1853 value = hexmem(pcr_value->value.buffer, pcr_value->value.size);
1854 if (!value)
1855 return NULL;
1856 }
1857
85b6f299 1858 return strjoin(index, hash ? ":" : "", strempty(hash), value ? "=" : "", strempty(value));
323eb480
DS
1859}
1860
1861/* Parse a string argument into an array of Tpm2PCRValue objects.
1862 *
1863 * The format is zero or more entries separated by ',' or '+'. The format of each entry is described in
1864 * tpm2_pcr_value_from_string(). This does not check for validity of the entries. */
1865int tpm2_pcr_values_from_string(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values) {
1866 const char *p = arg;
1867 int r;
1868
1869 assert(arg);
1870 assert(ret_pcr_values);
1871 assert(ret_n_pcr_values);
1872
1873 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
1874 size_t n_pcr_values = 0;
1875
1876 for (;;) {
1877 _cleanup_free_ char *pcr_arg = NULL;
1878 r = extract_first_word(&p, &pcr_arg, ",+", /* flags= */ 0);
1879 if (r < 0)
f9a0ee75 1880 return log_debug_errno(r, "Could not parse pcr values '%s': %m", p);
323eb480
DS
1881 if (r == 0)
1882 break;
1883
1884 Tpm2PCRValue pcr_value;
1885 r = tpm2_pcr_value_from_string(pcr_arg, &pcr_value);
1886 if (r < 0)
1887 return r;
1888
1889 if (!GREEDY_REALLOC_APPEND(pcr_values, n_pcr_values, &pcr_value, 1))
f9a0ee75 1890 return log_oom_debug();
323eb480
DS
1891 }
1892
1893 *ret_pcr_values = TAKE_PTR(pcr_values);
1894 *ret_n_pcr_values = n_pcr_values;
1895
1896 return 0;
1897}
1898
1899/* Return a string representing the array of PCR values. The format is as described in
1900 * tpm2_pcr_values_from_string(). This does not check for validity. */
1901char *tpm2_pcr_values_to_string(const Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
1902 _cleanup_free_ char *s = NULL;
1903
193fd573
DS
1904 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
1905 _cleanup_free_ char *pcrstr = tpm2_pcr_value_to_string(v);
323eb480
DS
1906 if (!pcrstr || !strextend_with_separator(&s, "+", pcrstr))
1907 return NULL;
1908 }
1909
1910 return s ? TAKE_PTR(s) : strdup("");
1911}
1912
75de375a 1913void tpm2_log_debug_tpml_pcr_selection(const TPML_PCR_SELECTION *l, const char *msg) {
c57d8bc8
DS
1914 if (!DEBUG_LOGGING || !l)
1915 return;
1916
1917 _cleanup_free_ char *s = tpm2_tpml_pcr_selection_to_string(l);
1918 log_debug("%s: %s", msg ?: "PCR selection", strna(s));
1919}
1920
75de375a 1921void tpm2_log_debug_pcr_value(const Tpm2PCRValue *pcr_value, const char *msg) {
323eb480
DS
1922 if (!DEBUG_LOGGING || !pcr_value)
1923 return;
1924
1925 _cleanup_free_ char *s = tpm2_pcr_value_to_string(pcr_value);
1926 log_debug("%s: %s", msg ?: "PCR value", strna(s));
1927}
1928
75de375a 1929void tpm2_log_debug_buffer(const void *buffer, size_t size, const char *msg) {
23b972d5
DS
1930 if (!DEBUG_LOGGING || !buffer || size == 0)
1931 return;
1932
1933 _cleanup_free_ char *h = hexmem(buffer, size);
1934 log_debug("%s: %s", msg ?: "Buffer", strna(h));
1935}
1936
75de375a 1937void tpm2_log_debug_digest(const TPM2B_DIGEST *digest, const char *msg) {
23b972d5
DS
1938 if (digest)
1939 tpm2_log_debug_buffer(digest->buffer, digest->size, msg ?: "Digest");
1940}
1941
75de375a 1942void tpm2_log_debug_name(const TPM2B_NAME *name, const char *msg) {
dbae4b95
DS
1943 if (name)
1944 tpm2_log_debug_buffer(name->name, name->size, msg ?: "Name");
1945}
1946
23b972d5
DS
1947static int tpm2_get_policy_digest(
1948 Tpm2Context *c,
1949 const Tpm2Handle *session,
1950 TPM2B_DIGEST **ret_policy_digest) {
1951
1952 TSS2_RC rc;
1953
1954 if (!DEBUG_LOGGING && !ret_policy_digest)
1955 return 0;
1956
1957 assert(c);
1958 assert(session);
1959
1960 log_debug("Acquiring policy digest.");
1961
1962 _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
1963 rc = sym_Esys_PolicyGetDigest(
1964 c->esys_context,
1965 session->esys_handle,
1966 ESYS_TR_NONE,
1967 ESYS_TR_NONE,
1968 ESYS_TR_NONE,
1969 &policy_digest);
1970 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 1971 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
23b972d5
DS
1972 "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
1973
1974 tpm2_log_debug_digest(policy_digest, "Session policy digest");
1975
1976 if (ret_policy_digest)
1977 *ret_policy_digest = TAKE_PTR(policy_digest);
1978
1979 return 0;
1980}
1981
aff853f8 1982int tpm2_create_primary(
e3f1f210 1983 Tpm2Context *c,
aff853f8
DS
1984 const Tpm2Handle *session,
1985 const TPM2B_PUBLIC *template,
1986 const TPM2B_SENSITIVE_CREATE *sensitive,
1987 TPM2B_PUBLIC **ret_public,
1988 Tpm2Handle **ret_handle) {
1989
1990 usec_t ts;
1991 TSS2_RC rc;
1992 int r;
1993
1994 assert(c);
1995 assert(template);
1996
1997 log_debug("Creating primary key on TPM.");
1998
1999 ts = now(CLOCK_MONOTONIC);
2000
2001 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2002 r = tpm2_handle_new(c, &handle);
2003 if (r < 0)
2004 return r;
2005
2006 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2007 rc = sym_Esys_CreatePrimary(
2008 c->esys_context,
2009 ESYS_TR_RH_OWNER,
2010 session ? session->esys_handle : ESYS_TR_PASSWORD,
2011 ESYS_TR_NONE,
2012 ESYS_TR_NONE,
2013 sensitive ? sensitive : &(TPM2B_SENSITIVE_CREATE) {},
2014 template,
2015 /* outsideInfo= */ NULL,
2016 &(TPML_PCR_SELECTION) {},
2017 &handle->esys_handle,
2018 &public,
2019 /* creationData= */ NULL,
2020 /* creationHash= */ NULL,
2021 /* creationTicket= */ NULL);
2022 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2023 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
aff853f8
DS
2024 "Failed to generate primary key in TPM: %s",
2025 sym_Tss2_RC_Decode(rc));
2026
2027 log_debug("Successfully created primary key on TPM in %s.",
2028 FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
2029
2030 if (ret_public)
2031 *ret_public = TAKE_PTR(public);
2032 if (ret_handle)
2033 *ret_handle = TAKE_PTR(handle);
2034
2035 return 0;
2036}
2037
2038/* Create a TPM object. Do not use this to create primary keys, because some HW TPMs refuse to allow that;
2039 * instead use tpm2_create_primary(). */
2040int tpm2_create(Tpm2Context *c,
e3f1f210
DS
2041 const Tpm2Handle *parent,
2042 const Tpm2Handle *session,
2043 const TPMT_PUBLIC *template,
2044 const TPMS_SENSITIVE_CREATE *sensitive,
2045 TPM2B_PUBLIC **ret_public,
2046 TPM2B_PRIVATE **ret_private) {
2047
2048 usec_t ts;
2049 TSS2_RC rc;
2050
2051 assert(c);
aff853f8 2052 assert(parent);
e3f1f210
DS
2053 assert(template);
2054
2055 log_debug("Creating object on TPM.");
2056
2057 ts = now(CLOCK_MONOTONIC);
2058
2059 TPM2B_PUBLIC tpm2b_public = {
2060 .size = sizeof(*template) - sizeof(template->unique),
2061 .publicArea = *template,
2062 };
2063
2064 /* Zero the unique area. */
2065 zero(tpm2b_public.publicArea.unique);
2066
2067 TPM2B_SENSITIVE_CREATE tpm2b_sensitive;
2068 if (sensitive)
2069 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {
2070 .size = sizeof(*sensitive),
2071 .sensitive = *sensitive,
2072 };
2073 else
2074 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {};
2075
2076 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2077 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
2078 rc = sym_Esys_Create(
2079 c->esys_context,
aff853f8 2080 parent->esys_handle,
e3f1f210
DS
2081 session ? session->esys_handle : ESYS_TR_PASSWORD,
2082 ESYS_TR_NONE,
2083 ESYS_TR_NONE,
2084 &tpm2b_sensitive,
2085 &tpm2b_public,
2086 /* outsideInfo= */ NULL,
2087 &(TPML_PCR_SELECTION) {},
2088 &private,
2089 &public,
2090 /* creationData= */ NULL,
2091 /* creationHash= */ NULL,
2092 /* creationTicket= */ NULL);
2093 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2094 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
e3f1f210
DS
2095 "Failed to generate object in TPM: %s",
2096 sym_Tss2_RC_Decode(rc));
2097
2098 log_debug("Successfully created object on TPM in %s.",
2099 FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
2100
2101 if (ret_public)
2102 *ret_public = TAKE_PTR(public);
2103 if (ret_private)
2104 *ret_private = TAKE_PTR(private);
2105
2106 return 0;
2107}
2108
d1d0de73
DS
2109static int tpm2_load(
2110 Tpm2Context *c,
2111 const Tpm2Handle *parent,
2112 const Tpm2Handle *session,
2113 const TPM2B_PUBLIC *public,
2114 const TPM2B_PRIVATE *private,
2115 Tpm2Handle **ret_handle) {
2116
2117 TSS2_RC rc;
2118 int r;
2119
2120 assert(c);
2121 assert(public);
2122 assert(private);
2123 assert(ret_handle);
2124
2125 log_debug("Loading object into TPM.");
2126
2127 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2128 r = tpm2_handle_new(c, &handle);
2129 if (r < 0)
2130 return r;
2131
2132 rc = sym_Esys_Load(
2133 c->esys_context,
2134 parent ? parent->esys_handle : ESYS_TR_RH_OWNER,
2135 session ? session->esys_handle : ESYS_TR_PASSWORD,
2136 ESYS_TR_NONE,
2137 ESYS_TR_NONE,
2138 private,
2139 public,
2140 &handle->esys_handle);
2141 if (rc == TPM2_RC_LOCKOUT)
f9a0ee75 2142 return log_debug_errno(SYNTHETIC_ERRNO(ENOLCK),
d1d0de73
DS
2143 "TPM2 device is in dictionary attack lockout mode.");
2144 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2145 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
d1d0de73
DS
2146 "Failed to load key into TPM: %s", sym_Tss2_RC_Decode(rc));
2147
2148 *ret_handle = TAKE_PTR(handle);
2149
2150 return 0;
2151}
2152
efe153bd
DS
2153static int tpm2_load_external(
2154 Tpm2Context *c,
2155 const Tpm2Handle *session,
2156 const TPM2B_PUBLIC *public,
2157 const TPM2B_SENSITIVE *private,
2158 Tpm2Handle **ret_handle) {
2159
2160 TSS2_RC rc;
2161 int r;
2162
2163 assert(c);
2164 assert(ret_handle);
2165
2166 log_debug("Loading external key into TPM.");
2167
2168 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2169 r = tpm2_handle_new(c, &handle);
2170 if (r < 0)
2171 return r;
2172
2173 rc = sym_Esys_LoadExternal(
2174 c->esys_context,
2175 session ? session->esys_handle : ESYS_TR_NONE,
2176 ESYS_TR_NONE,
2177 ESYS_TR_NONE,
2178 private,
2179 public,
2180#if HAVE_TSS2_ESYS3
2181 /* tpm2-tss >= 3.0.0 requires a ESYS_TR_RH_* constant specifying the requested
2182 * hierarchy, older versions need TPM2_RH_* instead. */
2183 ESYS_TR_RH_OWNER,
2184#else
2185 TPM2_RH_OWNER,
2186#endif
2187 &handle->esys_handle);
2188 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2189 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
efe153bd
DS
2190 "Failed to load public key into TPM: %s", sym_Tss2_RC_Decode(rc));
2191
2192 *ret_handle = TAKE_PTR(handle);
2193
2194 return 0;
2195}
2196
cea525a9
DS
2197/* This calls TPM2_CreateLoaded() directly, without checking if the TPM supports it. Callers should instead
2198 * use tpm2_create_loaded(). */
2199static int _tpm2_create_loaded(
2200 Tpm2Context *c,
2201 const Tpm2Handle *parent,
2202 const Tpm2Handle *session,
2203 const TPMT_PUBLIC *template,
2204 const TPMS_SENSITIVE_CREATE *sensitive,
2205 TPM2B_PUBLIC **ret_public,
2206 TPM2B_PRIVATE **ret_private,
2207 Tpm2Handle **ret_handle) {
2208
2209 usec_t ts;
2210 TSS2_RC rc;
2211 int r;
2212
2213 assert(c);
aff853f8 2214 assert(parent);
cea525a9
DS
2215 assert(template);
2216
2217 log_debug("Creating loaded object on TPM.");
2218
2219 ts = now(CLOCK_MONOTONIC);
2220
2221 /* Copy the input template and zero the unique area. */
2222 TPMT_PUBLIC template_copy = *template;
2223 zero(template_copy.unique);
2224
2225 TPM2B_TEMPLATE tpm2b_template;
2226 size_t size = 0;
2227 rc = sym_Tss2_MU_TPMT_PUBLIC_Marshal(
2228 &template_copy,
2229 tpm2b_template.buffer,
2230 sizeof(tpm2b_template.buffer),
2231 &size);
2232 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2233 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
cea525a9
DS
2234 "Failed to marshal public key template: %s", sym_Tss2_RC_Decode(rc));
2235 assert(size <= UINT16_MAX);
2236 tpm2b_template.size = size;
2237
2238 TPM2B_SENSITIVE_CREATE tpm2b_sensitive;
2239 if (sensitive)
2240 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {
2241 .size = sizeof(*sensitive),
2242 .sensitive = *sensitive,
2243 };
2244 else
2245 tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {};
2246
2247 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2248 r = tpm2_handle_new(c, &handle);
2249 if (r < 0)
2250 return r;
2251
2252 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2253 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
2254 rc = sym_Esys_CreateLoaded(
2255 c->esys_context,
aff853f8 2256 parent->esys_handle,
cea525a9
DS
2257 session ? session->esys_handle : ESYS_TR_PASSWORD,
2258 ESYS_TR_NONE,
2259 ESYS_TR_NONE,
2260 &tpm2b_sensitive,
2261 &tpm2b_template,
2262 &handle->esys_handle,
2263 &private,
2264 &public);
2265 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2266 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
cea525a9
DS
2267 "Failed to generate loaded object in TPM: %s",
2268 sym_Tss2_RC_Decode(rc));
2269
2270 log_debug("Successfully created loaded object on TPM in %s.",
2271 FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
2272
2273 if (ret_public)
2274 *ret_public = TAKE_PTR(public);
2275 if (ret_private)
2276 *ret_private = TAKE_PTR(private);
2277 if (ret_handle)
2278 *ret_handle = TAKE_PTR(handle);
2279
2280 return 0;
2281}
2282
2283/* This calls TPM2_CreateLoaded() if the TPM supports it, otherwise it calls TPM2_Create() and TPM2_Load()
aff853f8
DS
2284 * separately. Do not use this to create primary keys, because some HW TPMs refuse to allow that; instead use
2285 * tpm2_create_primary(). */
2286int tpm2_create_loaded(
cea525a9
DS
2287 Tpm2Context *c,
2288 const Tpm2Handle *parent,
2289 const Tpm2Handle *session,
2290 const TPMT_PUBLIC *template,
2291 const TPMS_SENSITIVE_CREATE *sensitive,
2292 TPM2B_PUBLIC **ret_public,
2293 TPM2B_PRIVATE **ret_private,
2294 Tpm2Handle **ret_handle) {
2295
2296 int r;
2297
2298 if (tpm2_supports_command(c, TPM2_CC_CreateLoaded))
2299 return _tpm2_create_loaded(c, parent, session, template, sensitive, ret_public, ret_private, ret_handle);
2300
2301 /* Unfortunately, this TPM doesn't support CreateLoaded (added at spec revision 130) so we need to
2302 * create and load manually. */
2303 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
2304 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
2305 r = tpm2_create(c, parent, session, template, sensitive, &public, &private);
2306 if (r < 0)
2307 return r;
2308
2309 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
2310 r = tpm2_load(c, parent, session, public, private, &handle);
2311 if (r < 0)
2312 return r;
2313
2314 if (ret_public)
2315 *ret_public = TAKE_PTR(public);
2316 if (ret_private)
2317 *ret_private = TAKE_PTR(private);
2318 if (ret_handle)
2319 *ret_handle = TAKE_PTR(handle);
2320
2321 return 0;
2322}
2323
323eb480
DS
2324/* Read hash values from the specified PCR selection. Provides a Tpm2PCRValue array that contains all
2325 * requested PCR values, in the order provided by the TPM. Normally, the provided pcr values will match
2326 * exactly what is in the provided selection, but the TPM may ignore some selected PCRs (for example, if an
2327 * unimplemented PCR index is requested), in which case those PCRs will be absent from the provided pcr
2328 * values. */
b4a6fcd5 2329int tpm2_pcr_read(
c57d8bc8
DS
2330 Tpm2Context *c,
2331 const TPML_PCR_SELECTION *pcr_selection,
323eb480 2332 Tpm2PCRValue **ret_pcr_values,
c648a4b8 2333 size_t *ret_n_pcr_values) {
c57d8bc8 2334
323eb480 2335 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
c648a4b8 2336 size_t n_pcr_values = 0;
c57d8bc8 2337 TSS2_RC rc;
321a9d9e 2338
c57d8bc8
DS
2339 assert(c);
2340 assert(pcr_selection);
323eb480
DS
2341 assert(ret_pcr_values);
2342 assert(ret_n_pcr_values);
321a9d9e 2343
323eb480 2344 TPML_PCR_SELECTION remaining = *pcr_selection;
c57d8bc8
DS
2345 while (!tpm2_tpml_pcr_selection_is_empty(&remaining)) {
2346 _cleanup_(Esys_Freep) TPML_PCR_SELECTION *current_read = NULL;
2347 _cleanup_(Esys_Freep) TPML_DIGEST *current_values = NULL;
321a9d9e 2348
c57d8bc8 2349 tpm2_log_debug_tpml_pcr_selection(&remaining, "Reading PCR selection");
321a9d9e 2350
c57d8bc8
DS
2351 /* Unfortunately, PCR_Read will not return more than 8 values. */
2352 rc = sym_Esys_PCR_Read(
2353 c->esys_context,
2354 ESYS_TR_NONE,
2355 ESYS_TR_NONE,
2356 ESYS_TR_NONE,
2357 &remaining,
2358 NULL,
2359 &current_read,
2360 &current_values);
2361 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2362 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
c57d8bc8 2363 "Failed to read TPM2 PCRs: %s", sym_Tss2_RC_Decode(rc));
321a9d9e 2364
323eb480
DS
2365 tpm2_log_debug_tpml_pcr_selection(current_read, "Read PCR selection");
2366
c57d8bc8 2367 if (tpm2_tpml_pcr_selection_is_empty(current_read)) {
f9a0ee75 2368 log_debug("TPM2 refused to read possibly unimplemented PCRs, ignoring.");
c57d8bc8 2369 break;
321a9d9e
LP
2370 }
2371
323eb480
DS
2372 unsigned i = 0;
2373 FOREACH_PCR_IN_TPML_PCR_SELECTION(index, tpms, current_read) {
2374 assert(i < current_values->count);
2375 Tpm2PCRValue pcr_value = {
2376 .index = index,
2377 .hash = tpms->hash,
2378 .value = current_values->digests[i++],
2379 };
c57d8bc8 2380
323eb480 2381 tpm2_log_debug_pcr_value(&pcr_value, /* msg= */ NULL);
c57d8bc8 2382
323eb480 2383 if (!GREEDY_REALLOC_APPEND(pcr_values, n_pcr_values, &pcr_value, 1))
f9a0ee75 2384 return log_oom_debug();
323eb480
DS
2385 }
2386 assert(i == current_values->count);
c57d8bc8 2387
323eb480
DS
2388 tpm2_tpml_pcr_selection_sub(&remaining, current_read);
2389 }
c57d8bc8 2390
323eb480 2391 tpm2_sort_pcr_values(pcr_values, n_pcr_values);
c57d8bc8 2392
cc1a78d5 2393 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
f9a0ee75 2394 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "PCR values read from TPM are not valid.");
321a9d9e 2395
323eb480
DS
2396 *ret_pcr_values = TAKE_PTR(pcr_values);
2397 *ret_n_pcr_values = n_pcr_values;
c57d8bc8
DS
2398
2399 return 0;
321a9d9e
LP
2400}
2401
b4a6fcd5
DS
2402/* Read the PCR value for each TPM2PCRValue entry in the array that does not have a value set. If all entries
2403 * have an unset hash (i.e. hash == 0), this first detects the "best" PCR bank to use; otherwise, all entries
2404 * must have a valid hash set. All entries must have a valid index. If this cannot read a PCR value for all
2405 * appropriate entries, this returns an error. This does not check the array for validity. */
2406int tpm2_pcr_read_missing_values(Tpm2Context *c, Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
2407 TPMI_ALG_HASH pcr_bank = 0;
2408 int r;
2409
2410 assert(c);
2411 assert(pcr_values || n_pcr_values == 0);
2412
2413 if (n_pcr_values > 0) {
2414 size_t hash_count;
2415 r = tpm2_pcr_values_hash_count(pcr_values, n_pcr_values, &hash_count);
2416 if (r < 0)
f9a0ee75 2417 return log_debug_errno(r, "Could not get hash count from pcr values: %m");
b4a6fcd5
DS
2418
2419 if (hash_count == 1 && pcr_values[0].hash == 0) {
2420 uint32_t mask;
2421 r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, 0, &mask);
2422 if (r < 0)
2423 return r;
2424
2425 r = tpm2_get_best_pcr_bank(c, mask, &pcr_bank);
2426 if (r < 0)
2427 return r;
2428 }
2429 }
2430
193fd573 2431 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
b4a6fcd5
DS
2432 if (v->hash == 0)
2433 v->hash = pcr_bank;
2434
2435 if (v->value.size > 0)
2436 continue;
2437
2438 TPML_PCR_SELECTION selection;
2439 r = tpm2_tpml_pcr_selection_from_pcr_values(v, 1, &selection, NULL, NULL);
2440 if (r < 0)
2441 return r;
2442
2443 _cleanup_free_ Tpm2PCRValue *read_values = NULL;
2444 size_t n_read_values;
2445 r = tpm2_pcr_read(c, &selection, &read_values, &n_read_values);
2446 if (r < 0)
2447 return r;
2448
2449 if (n_read_values == 0)
f9a0ee75 2450 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
b4a6fcd5
DS
2451 "Could not read PCR hash 0x%" PRIu16 " index %u",
2452 v->hash, v->index);
2453
2454 assert(n_read_values == 1);
2455 assert(read_values[0].hash == v->hash);
2456 assert(read_values[0].index == v->index);
2457
2458 v->value = read_values[0].value;
2459 }
2460
2461 return 0;
2462}
2463
321a9d9e 2464static int tpm2_pcr_mask_good(
23e9ccc2 2465 Tpm2Context *c,
321a9d9e
LP
2466 TPMI_ALG_HASH bank,
2467 uint32_t mask) {
2468
321a9d9e 2469 TPML_PCR_SELECTION selection;
c57d8bc8 2470 int r;
321a9d9e
LP
2471
2472 assert(c);
2473
2474 /* So we have the problem that some systems might have working TPM2 chips, but the firmware doesn't
2475 * actually measure into them, or only into a suboptimal bank. If so, the PCRs should be all zero or
2476 * all 0xFF. Detect that, so that we can warn and maybe pick a better bank. */
2477
c69bd0ab 2478 tpm2_tpml_pcr_selection_from_mask(mask, bank, &selection);
321a9d9e 2479
323eb480
DS
2480 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
2481 size_t n_pcr_values;
2482 r = tpm2_pcr_read(c, &selection, &pcr_values, &n_pcr_values);
c57d8bc8
DS
2483 if (r < 0)
2484 return r;
321a9d9e
LP
2485
2486 /* If at least one of the selected PCR values is something other than all 0x00 or all 0xFF we are happy. */
193fd573
DS
2487 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
2488 if (!memeqbyte(0x00, v->value.buffer, v->value.size) &&
2489 !memeqbyte(0xFF, v->value.buffer, v->value.size))
c57d8bc8 2490 return true;
321a9d9e 2491
c57d8bc8 2492 return false;
321a9d9e
LP
2493}
2494
59fafaee
LP
2495static int tpm2_bank_has24(const TPMS_PCR_SELECTION *selection) {
2496
2497 assert(selection);
2498
2499 /* As per https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
2500 * TPM2 on a Client PC must have at least 24 PCRs. If this TPM has less, just skip over it. */
2501 if (selection->sizeofSelect < TPM2_PCRS_MAX/8) {
2502 log_debug("Skipping TPM2 PCR bank %s with fewer than 24 PCRs.",
7bfe0a48 2503 strna(tpm2_hash_alg_to_string(selection->hash)));
59fafaee
LP
2504 return false;
2505 }
2506
2507 assert_cc(TPM2_PCRS_MAX % 8 == 0);
2508
2509 /* It's not enough to check how many PCRs there are, we also need to check that the 24 are
2510 * enabled for this bank. Otherwise this TPM doesn't qualify. */
2511 bool valid = true;
2512 for (size_t j = 0; j < TPM2_PCRS_MAX/8; j++)
2513 if (selection->pcrSelect[j] != 0xFF) {
2514 valid = false;
2515 break;
2516 }
2517
2518 if (!valid)
2519 log_debug("TPM2 PCR bank %s has fewer than 24 PCR bits enabled, ignoring.",
7bfe0a48 2520 strna(tpm2_hash_alg_to_string(selection->hash)));
59fafaee
LP
2521
2522 return valid;
2523}
2524
b4a6fcd5 2525int tpm2_get_best_pcr_bank(
23e9ccc2 2526 Tpm2Context *c,
321a9d9e 2527 uint32_t pcr_mask,
07697bfe
LP
2528 TPMI_ALG_HASH *ret) {
2529
321a9d9e 2530 TPMI_ALG_HASH supported_hash = 0, hash_with_valid_pcr = 0;
59fafaee 2531 int r;
07697bfe 2532
321a9d9e 2533 assert(c);
3a35d6cd 2534 assert(ret);
321a9d9e 2535
9ea0ffe6 2536 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &c->capability_pcrs) {
3a35d6cd 2537 TPMI_ALG_HASH hash = selection->hash;
321a9d9e
LP
2538 int good;
2539
2540 /* For now we are only interested in the SHA1 and SHA256 banks */
3a35d6cd 2541 if (!IN_SET(hash, TPM2_ALG_SHA256, TPM2_ALG_SHA1))
321a9d9e 2542 continue;
07697bfe 2543
3a35d6cd 2544 r = tpm2_bank_has24(selection);
59fafaee
LP
2545 if (r < 0)
2546 return r;
2547 if (!r)
07697bfe 2548 continue;
07697bfe 2549
3a35d6cd 2550 good = tpm2_pcr_mask_good(c, hash, pcr_mask);
321a9d9e
LP
2551 if (good < 0)
2552 return good;
2553
3a35d6cd 2554 if (hash == TPM2_ALG_SHA256) {
321a9d9e
LP
2555 supported_hash = TPM2_ALG_SHA256;
2556 if (good) {
2557 /* Great, SHA256 is supported and has initialized PCR values, we are done. */
2558 hash_with_valid_pcr = TPM2_ALG_SHA256;
2559 break;
2560 }
2561 } else {
3a35d6cd 2562 assert(hash == TPM2_ALG_SHA1);
321a9d9e
LP
2563
2564 if (supported_hash == 0)
2565 supported_hash = TPM2_ALG_SHA1;
07697bfe 2566
321a9d9e
LP
2567 if (good && hash_with_valid_pcr == 0)
2568 hash_with_valid_pcr = TPM2_ALG_SHA1;
2569 }
07697bfe
LP
2570 }
2571
321a9d9e
LP
2572 /* We preferably pick SHA256, but only if its PCRs are initialized or neither the SHA1 nor the SHA256
2573 * PCRs are initialized. If SHA256 is not supported but SHA1 is and its PCRs are too, we prefer
2574 * SHA1.
2575 *
2576 * We log at LOG_NOTICE level whenever we end up using the SHA1 bank or when the PCRs we bind to are
2577 * not initialized. */
2578
2579 if (hash_with_valid_pcr == TPM2_ALG_SHA256) {
2580 assert(supported_hash == TPM2_ALG_SHA256);
2581 log_debug("TPM2 device supports SHA256 PCR bank and SHA256 PCRs are valid, yay!");
2582 *ret = TPM2_ALG_SHA256;
2583 } else if (hash_with_valid_pcr == TPM2_ALG_SHA1) {
2584 if (supported_hash == TPM2_ALG_SHA256)
2585 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.");
2586 else {
2587 assert(supported_hash == TPM2_ALG_SHA1);
2588 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.");
2589 }
2590
2591 *ret = TPM2_ALG_SHA1;
2592 } else if (supported_hash == TPM2_ALG_SHA256) {
2593 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!");
2594 *ret = TPM2_ALG_SHA256;
2595 } else if (supported_hash == TPM2_ALG_SHA1) {
2596 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!");
2597 *ret = TPM2_ALG_SHA1;
2598 } else
f9a0ee75 2599 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
07697bfe
LP
2600 "TPM2 module supports neither SHA1 nor SHA256 PCR banks, cannot operate.");
2601
07697bfe
LP
2602 return 0;
2603}
2604
c5bf1f85 2605int tpm2_get_good_pcr_banks(
23e9ccc2 2606 Tpm2Context *c,
c5bf1f85
LP
2607 uint32_t pcr_mask,
2608 TPMI_ALG_HASH **ret) {
2609
2610 _cleanup_free_ TPMI_ALG_HASH *good_banks = NULL, *fallback_banks = NULL;
c5bf1f85 2611 size_t n_good_banks = 0, n_fallback_banks = 0;
c5bf1f85
LP
2612 int r;
2613
2614 assert(c);
2615 assert(ret);
2616
9ea0ffe6 2617 FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &c->capability_pcrs) {
3a35d6cd 2618 TPMI_ALG_HASH hash = selection->hash;
c5bf1f85
LP
2619
2620 /* Let's see if this bank is superficially OK, i.e. has at least 24 enabled registers */
3a35d6cd 2621 r = tpm2_bank_has24(selection);
c5bf1f85
LP
2622 if (r < 0)
2623 return r;
2624 if (!r)
2625 continue;
2626
2627 /* Let's now see if this bank has any of the selected PCRs actually initialized */
3a35d6cd 2628 r = tpm2_pcr_mask_good(c, hash, pcr_mask);
c5bf1f85
LP
2629 if (r < 0)
2630 return r;
2631
2632 if (n_good_banks + n_fallback_banks >= INT_MAX)
f9a0ee75 2633 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "Too many good TPM2 banks?");
c5bf1f85
LP
2634
2635 if (r) {
2636 if (!GREEDY_REALLOC(good_banks, n_good_banks+1))
f9a0ee75 2637 return log_oom_debug();
c5bf1f85 2638
3a35d6cd 2639 good_banks[n_good_banks++] = hash;
c5bf1f85
LP
2640 } else {
2641 if (!GREEDY_REALLOC(fallback_banks, n_fallback_banks+1))
f9a0ee75 2642 return log_oom_debug();
c5bf1f85 2643
3a35d6cd 2644 fallback_banks[n_fallback_banks++] = hash;
c5bf1f85
LP
2645 }
2646 }
2647
2648 /* Preferably, use the good banks (i.e. the ones the PCR values are actually initialized so
2649 * far). Otherwise use the fallback banks (i.e. which exist and are enabled, but so far not used. */
2650 if (n_good_banks > 0) {
2651 log_debug("Found %zu fully initialized TPM2 banks.", n_good_banks);
2652 *ret = TAKE_PTR(good_banks);
2653 return (int) n_good_banks;
2654 }
2655 if (n_fallback_banks > 0) {
2656 log_debug("Found %zu enabled but un-initialized TPM2 banks.", n_fallback_banks);
2657 *ret = TAKE_PTR(fallback_banks);
2658 return (int) n_fallback_banks;
2659 }
2660
2661 /* No suitable banks found. */
2662 *ret = NULL;
2663 return 0;
2664}
2665
e4481cc5 2666int tpm2_get_good_pcr_banks_strv(
23e9ccc2 2667 Tpm2Context *c,
e4481cc5
LP
2668 uint32_t pcr_mask,
2669 char ***ret) {
2670
0d7009d3 2671#if HAVE_OPENSSL
e4481cc5
LP
2672 _cleanup_free_ TPMI_ALG_HASH *algs = NULL;
2673 _cleanup_strv_free_ char **l = NULL;
2674 int n_algs;
2675
2676 assert(c);
2677 assert(ret);
2678
2679 n_algs = tpm2_get_good_pcr_banks(c, pcr_mask, &algs);
2680 if (n_algs < 0)
2681 return n_algs;
2682
193fd573 2683 FOREACH_ARRAY(a, algs, n_algs) {
e4481cc5
LP
2684 _cleanup_free_ char *n = NULL;
2685 const EVP_MD *implementation;
2686 const char *salg;
2687
193fd573 2688 salg = tpm2_hash_alg_to_string(*a);
e4481cc5 2689 if (!salg)
f9a0ee75 2690 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM2 operates with unknown PCR algorithm, can't measure.");
e4481cc5
LP
2691
2692 implementation = EVP_get_digestbyname(salg);
2693 if (!implementation)
f9a0ee75 2694 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM2 operates with unsupported PCR algorithm, can't measure.");
e4481cc5
LP
2695
2696 n = strdup(ASSERT_PTR(EVP_MD_name(implementation)));
2697 if (!n)
f9a0ee75 2698 return log_oom_debug();
e4481cc5
LP
2699
2700 ascii_strlower(n); /* OpenSSL uses uppercase digest names, we prefer them lower case. */
2701
2702 if (strv_consume(&l, TAKE_PTR(n)) < 0)
f9a0ee75 2703 return log_oom_debug();
e4481cc5
LP
2704 }
2705
2706 *ret = TAKE_PTR(l);
2707 return 0;
0d7009d3 2708#else /* HAVE_OPENSSL */
f9a0ee75 2709 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
0d7009d3 2710#endif
e4481cc5
LP
2711}
2712
da92d39a
DS
2713/* Hash data into the digest.
2714 *
2715 * If 'extend' is true, the hashing operation starts with the existing digest hash (and the digest is
2716 * required to have a hash and its size must be correct). If 'extend' is false, the digest size is
2717 * initialized to the correct size for 'alg' and the hashing operation does not include any existing digest
2718 * hash. If 'extend' is false and no data is provided, the digest is initialized to a zero digest.
2719 *
2720 * On success, the digest hash will be updated with the hashing operation result and the digest size will be
2721 * correct for 'alg'.
2722 *
2723 * This currently only provides SHA256, so 'alg' must be TPM2_ALG_SHA256. */
2724int tpm2_digest_many(
2725 TPMI_ALG_HASH alg,
2726 TPM2B_DIGEST *digest,
2727 const struct iovec data[],
2728 size_t n_data,
2729 bool extend) {
2730
2731 struct sha256_ctx ctx;
2732
2733 assert(digest);
2734 assert(data || n_data == 0);
2735
2736 if (alg != TPM2_ALG_SHA256)
f9a0ee75 2737 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
da92d39a
DS
2738 "Hash algorithm not supported: 0x%x", alg);
2739
2740 if (extend && digest->size != SHA256_DIGEST_SIZE)
f9a0ee75 2741 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
da92d39a
DS
2742 "Digest size 0x%x, require 0x%x",
2743 digest->size, (unsigned)SHA256_DIGEST_SIZE);
2744
2745 /* Since we're hardcoding SHA256 (for now), we can check this at compile time. */
2746 assert_cc(sizeof(digest->buffer) >= SHA256_DIGEST_SIZE);
2747
2748 CLEANUP_ERASE(ctx);
2749
2750 sha256_init_ctx(&ctx);
2751
2752 if (extend)
2753 sha256_process_bytes(digest->buffer, digest->size, &ctx);
2754 else {
2755 *digest = (TPM2B_DIGEST){ .size = SHA256_DIGEST_SIZE, };
2756 if (n_data == 0) /* If not extending and no data, return zero hash */
2757 return 0;
2758 }
2759
193fd573
DS
2760 FOREACH_ARRAY(d, data, n_data)
2761 sha256_process_bytes(d->iov_base, d->iov_len, &ctx);
da92d39a
DS
2762
2763 sha256_finish_ctx(&ctx, digest->buffer);
2764
2765 return 0;
2766}
2767
2768/* Same as tpm2_digest_many() but data is contained in TPM2B_DIGEST[]. The digests may be any size digests. */
2769int tpm2_digest_many_digests(
2770 TPMI_ALG_HASH alg,
2771 TPM2B_DIGEST *digest,
2772 const TPM2B_DIGEST data[],
2773 size_t n_data,
2774 bool extend) {
2775
2776 _cleanup_free_ struct iovec *iovecs = NULL;
2777
2778 assert(data || n_data == 0);
2779
2780 iovecs = new(struct iovec, n_data);
2781 if (!iovecs)
f9a0ee75 2782 return log_oom_debug();
da92d39a
DS
2783
2784 for (size_t i = 0; i < n_data; i++)
2785 iovecs[i] = IOVEC_MAKE((void*) data[i].buffer, data[i].size);
2786
2787 return tpm2_digest_many(alg, digest, iovecs, n_data, extend);
2788}
2789
f230572f
DS
2790/* This hashes the provided pin into a digest value, but also verifies that the final byte is not 0, because
2791 * the TPM specification Part 1 ("Architecture") section Authorization Values (subsection "Authorization Size
2792 * Convention") states "Trailing octets of zero are to be removed from any string before it is used as an
2793 * authValue". Since the TPM doesn't know if the auth value is a "string" or just a hash digest, any hash
63477a71
DS
2794 * digest that randomly happens to end in 0 must have the final 0(s) trimmed.
2795 *
2796 * This is required at 2 points. First, when setting the authValue during creation of new sealed objects, in
2797 * tpm2_seal(). This only applies to newly created objects, of course. Second, when using a previously
2798 * created sealed object that has an authValue set, we use the sealed objects as the session bind key. This
2799 * requires calling SetAuth so tpm2-tss can correctly calculate the HMAC to use for the encryption session.
2800 *
2801 * TPM implementations will perform the trimming for any authValue for existing sealed objects, so the
2802 * tpm2-tss library must also perform the trimming before HMAC calculation, but it does not yet; this bug is
2803 * open to add the trimming: https://github.com/tpm2-software/tpm2-tss/issues/2664
2804 *
2805 * Until our minimum tpm2-tss version contains a fix for that bug, we must perform the trimming
2806 * ourselves. Note that since we are trimming, which is exactly what a TPM implementation would do, this will
2807 * work for both existing objects with a authValue ending in 0(s) as well as new sealed objects we create,
2808 * which we will trim the 0(s) from before sending to the TPM.
2809 */
2810static void tpm2_trim_auth_value(TPM2B_AUTH *auth) {
2811 bool trimmed = false;
2812
2813 assert(auth);
2814
2815 while (auth->size > 0 && auth->buffer[auth->size - 1] == 0) {
2816 trimmed = true;
2817 auth->size--;
2818 }
2819
2820 if (trimmed)
2821 log_debug("authValue ends in 0, trimming as required by the TPM2 specification Part 1 section 'HMAC Computation' authValue Note 2.");
2822}
2823
f230572f
DS
2824static int tpm2_get_pin_auth(TPMI_ALG_HASH hash, const char *pin, TPM2B_AUTH *ret_auth) {
2825 TPM2B_AUTH auth = {};
2826 int r;
2827
2828 assert(pin);
2829 assert(ret_auth);
2830
2831 r = tpm2_digest_buffer(hash, &auth, pin, strlen(pin), /* extend= */ false);
2832 if (r < 0)
2833 return r;
2834
63477a71 2835 tpm2_trim_auth_value(&auth);
f230572f
DS
2836
2837 *ret_auth = TAKE_STRUCT(auth);
2838
2839 return 0;
2840}
2841
409a65f8
DS
2842static int tpm2_set_auth(Tpm2Context *c, const Tpm2Handle *handle, const char *pin) {
2843 TPM2B_AUTH auth = {};
2844 TSS2_RC rc;
2845 int r;
2846
2847 assert(c);
2848 assert(handle);
2849
2850 if (!pin)
2851 return 0;
2852
2853 CLEANUP_ERASE(auth);
2854
f230572f 2855 r = tpm2_get_pin_auth(TPM2_ALG_SHA256, pin, &auth);
409a65f8
DS
2856 if (r < 0)
2857 return r;
2858
2859 rc = sym_Esys_TR_SetAuth(c->esys_context, handle->esys_handle, &auth);
2860 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2861 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
409a65f8
DS
2862 "Failed to load PIN in TPM: %s", sym_Tss2_RC_Decode(rc));
2863
2864 return 0;
2865}
2866
e976445d
DS
2867static bool tpm2_is_encryption_session(Tpm2Context *c, const Tpm2Handle *session) {
2868 TPMA_SESSION flags = 0;
2869 TSS2_RC rc;
2870
2871 assert(c);
2872 assert(session);
2873
2874 rc = sym_Esys_TRSess_GetAttributes(c->esys_context, session->esys_handle, &flags);
2875 if (rc != TSS2_RC_SUCCESS)
2876 return false;
2877
2878 return (flags & TPMA_SESSION_DECRYPT) && (flags & TPMA_SESSION_ENCRYPT);
2879}
2880
da29de23 2881static int tpm2_make_encryption_session(
23e9ccc2 2882 Tpm2Context *c,
16e16b8c
DS
2883 const Tpm2Handle *primary,
2884 const Tpm2Handle *bind_key,
16e16b8c 2885 Tpm2Handle **ret_session) {
da29de23 2886
da29de23
GG
2887 const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT |
2888 TPMA_SESSION_CONTINUESESSION;
da29de23 2889 TSS2_RC rc;
16e16b8c 2890 int r;
da29de23
GG
2891
2892 assert(c);
73592a7c 2893 assert(primary);
16e16b8c 2894 assert(ret_session);
da29de23
GG
2895
2896 log_debug("Starting HMAC encryption session.");
2897
2898 /* Start a salted, unbound HMAC session with a well-known key (e.g. primary key) as tpmKey, which
2899 * means that the random salt will be encrypted with the well-known key. That way, only the TPM can
2900 * recover the salt, which is then used for key derivation. */
1dc8f518 2901 _cleanup_(tpm2_handle_freep) Tpm2Handle *session = NULL;
16e16b8c
DS
2902 r = tpm2_handle_new(c, &session);
2903 if (r < 0)
2904 return r;
2905
da29de23 2906 rc = sym_Esys_StartAuthSession(
23e9ccc2 2907 c->esys_context,
16e16b8c 2908 primary->esys_handle,
73592a7c 2909 bind_key ? bind_key->esys_handle : ESYS_TR_NONE,
da29de23
GG
2910 ESYS_TR_NONE,
2911 ESYS_TR_NONE,
2912 ESYS_TR_NONE,
2913 NULL,
2914 TPM2_SE_HMAC,
a47060bb 2915 &SESSION_TEMPLATE_SYM_AES_128_CFB,
da29de23 2916 TPM2_ALG_SHA256,
16e16b8c 2917 &session->esys_handle);
da29de23 2918 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2919 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
da29de23
GG
2920 "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
2921
2922 /* Enable parameter encryption/decryption with AES in CFB mode. Together with HMAC digests (which are
2923 * always used for sessions), this provides confidentiality, integrity and replay protection for
2924 * operations that use this session. */
16e16b8c 2925 rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session->esys_handle, sessionAttributes, 0xff);
da29de23 2926 if (rc != TSS2_RC_SUCCESS)
f9a0ee75
DS
2927 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2928 "Failed to configure TPM session: %s", sym_Tss2_RC_Decode(rc));
da29de23 2929
16e16b8c 2930 *ret_session = TAKE_PTR(session);
da29de23 2931
da29de23
GG
2932 return 0;
2933}
2934
2cd9d575
DS
2935static int tpm2_make_policy_session(
2936 Tpm2Context *c,
2937 const Tpm2Handle *primary,
2938 const Tpm2Handle *encryption_session,
2cd9d575
DS
2939 Tpm2Handle **ret_session) {
2940
2cd9d575
DS
2941 TSS2_RC rc;
2942 int r;
2943
2944 assert(c);
2945 assert(primary);
2946 assert(encryption_session);
2947 assert(ret_session);
2948
2949 if (!tpm2_is_encryption_session(c, encryption_session))
f9a0ee75 2950 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
2cd9d575
DS
2951 "Missing encryption session");
2952
2953 log_debug("Starting policy session.");
2954
1dc8f518 2955 _cleanup_(tpm2_handle_freep) Tpm2Handle *session = NULL;
2cd9d575
DS
2956 r = tpm2_handle_new(c, &session);
2957 if (r < 0)
2958 return r;
2959
2960 rc = sym_Esys_StartAuthSession(
2961 c->esys_context,
2962 primary->esys_handle,
2963 ESYS_TR_NONE,
2964 encryption_session->esys_handle,
2965 ESYS_TR_NONE,
2966 ESYS_TR_NONE,
2967 NULL,
4bba26ae 2968 TPM2_SE_POLICY,
a47060bb 2969 &SESSION_TEMPLATE_SYM_AES_128_CFB,
2cd9d575
DS
2970 TPM2_ALG_SHA256,
2971 &session->esys_handle);
2972 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 2973 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
2cd9d575
DS
2974 "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
2975
2976 *ret_session = TAKE_PTR(session);
2977
2978 return 0;
2979}
2980
d9b5841d
LP
2981static int find_signature(
2982 JsonVariant *v,
95898241
DS
2983 const TPML_PCR_SELECTION *pcr_selection,
2984 const void *fp,
2985 size_t fp_size,
d9b5841d
LP
2986 const void *policy,
2987 size_t policy_size,
2988 void *ret_signature,
2989 size_t *ret_signature_size) {
2990
95898241 2991#if HAVE_OPENSSL
d9b5841d 2992 JsonVariant *b, *i;
d9b5841d
LP
2993 const char *k;
2994 int r;
2995
2996 /* Searches for a signature blob in the specified JSON object. Search keys are PCR bank, PCR mask,
2997 * public key, and policy digest. */
2998
2999 if (!json_variant_is_object(v))
f9a0ee75 3000 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Signature is not a JSON object.");
d9b5841d 3001
95898241 3002 uint16_t pcr_bank = pcr_selection->pcrSelections[0].hash;
dbaae766 3003 uint32_t pcr_mask = tpm2_tpml_pcr_selection_to_mask(pcr_selection, pcr_bank);
95898241 3004
7bfe0a48 3005 k = tpm2_hash_alg_to_string(pcr_bank);
d9b5841d 3006 if (!k)
f9a0ee75 3007 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Don't know PCR bank %" PRIu16, pcr_bank);
d9b5841d
LP
3008
3009 /* First, find field by bank */
3010 b = json_variant_by_key(v, k);
3011 if (!b)
f9a0ee75 3012 return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Signature lacks data for PCR bank '%s'.", k);
d9b5841d
LP
3013
3014 if (!json_variant_is_array(b))
f9a0ee75 3015 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Bank data is not a JSON array.");
d9b5841d
LP
3016
3017 /* Now iterate through all signatures known for this bank */
3018 JSON_VARIANT_ARRAY_FOREACH(i, b) {
3019 _cleanup_free_ void *fpj_data = NULL, *polj_data = NULL;
3020 JsonVariant *maskj, *fpj, *sigj, *polj;
3021 size_t fpj_size, polj_size;
3022 uint32_t parsed_mask;
3023
3024 if (!json_variant_is_object(i))
f9a0ee75 3025 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Bank data element is not a JSON object");
d9b5841d
LP
3026
3027 /* Check if the PCR mask matches our expectations */
3028 maskj = json_variant_by_key(i, "pcrs");
3029 if (!maskj)
3030 continue;
3031
3032 r = tpm2_parse_pcr_json_array(maskj, &parsed_mask);
3033 if (r < 0)
f9a0ee75 3034 return log_debug_errno(r, "Failed to parse JSON PCR mask");
d9b5841d
LP
3035
3036 if (parsed_mask != pcr_mask)
3037 continue; /* Not for this PCR mask */
3038
3039 /* Then check if this is for the public key we operate with */
3040 fpj = json_variant_by_key(i, "pkfp");
3041 if (!fpj)
3042 continue;
3043
3044 r = json_variant_unhex(fpj, &fpj_data, &fpj_size);
3045 if (r < 0)
f9a0ee75 3046 return log_debug_errno(r, "Failed to decode fingerprint in JSON data: %m");
d9b5841d 3047
d9b5841d
LP
3048 if (memcmp_nn(fp, fp_size, fpj_data, fpj_size) != 0)
3049 continue; /* Not for this public key */
3050
3051 /* Finally, check if this is for the PCR policy we expect this to be */
3052 polj = json_variant_by_key(i, "pol");
3053 if (!polj)
3054 continue;
3055
3056 r = json_variant_unhex(polj, &polj_data, &polj_size);
3057 if (r < 0)
f9a0ee75 3058 return log_debug_errno(r, "Failed to decode policy hash JSON data: %m");
d9b5841d
LP
3059
3060 if (memcmp_nn(policy, policy_size, polj_data, polj_size) != 0)
3061 continue;
3062
3063 /* This entry matches all our expectations, now return the signature included in it */
3064 sigj = json_variant_by_key(i, "sig");
3065 if (!sigj)
3066 continue;
3067
3068 return json_variant_unbase64(sigj, ret_signature, ret_signature_size);
3069 }
3070
f9a0ee75 3071 return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Couldn't find signature for this PCR bank, PCR index and public key.");
95898241 3072#else /* HAVE_OPENSSL */
f9a0ee75 3073 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
395c1d9a 3074#endif
95898241 3075}
d9b5841d 3076
dbae4b95
DS
3077/* Calculates the "name" of a public key.
3078 *
3079 * As specified in TPM2 spec "Part 1: Architecture", a key's "name" is its nameAlg value followed by a hash
3080 * of its TPM2 public area, all properly marshalled. This allows a key's "name" to be dependent not only on
3081 * the key fingerprint, but also on the TPM2-specific fields that associated with the key (i.e. all fields in
3082 * TPMT_PUBLIC). Note that this means an existing key may not change any of its TPMT_PUBLIC fields, since
3083 * that would also change the key name.
3084 *
3085 * Since we (currently) hardcode to always using SHA256 for hashing, this returns an error if the public key
3086 * nameAlg is not TPM2_ALG_SHA256. */
3087int tpm2_calculate_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name) {
3088 TSS2_RC rc;
3089 int r;
3090
3091 assert(public);
3092 assert(ret_name);
3093
3094 r = dlopen_tpm2();
3095 if (r < 0)
f9a0ee75 3096 return log_debug_errno(r, "TPM2 support not installed: %m");
dbae4b95
DS
3097
3098 if (public->nameAlg != TPM2_ALG_SHA256)
f9a0ee75 3099 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
dbae4b95
DS
3100 "Unsupported nameAlg: 0x%x",
3101 public->nameAlg);
3102
3103 _cleanup_free_ uint8_t *buf = NULL;
3104 size_t size = 0;
3105
3106 buf = (uint8_t*) new(TPMT_PUBLIC, 1);
3107 if (!buf)
f9a0ee75 3108 return log_oom_debug();
dbae4b95
DS
3109
3110 rc = sym_Tss2_MU_TPMT_PUBLIC_Marshal(public, buf, sizeof(TPMT_PUBLIC), &size);
3111 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3112 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dbae4b95
DS
3113 "Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
3114
3115 TPM2B_DIGEST digest = {};
3116 r = tpm2_digest_buffer(TPM2_ALG_SHA256, &digest, buf, size, /* extend= */ false);
3117 if (r < 0)
3118 return r;
3119
3120 TPMT_HA ha = {
3121 .hashAlg = TPM2_ALG_SHA256,
3122 };
3123 assert(digest.size <= sizeof(ha.digest.sha256));
3124 memcpy_safe(ha.digest.sha256, digest.buffer, digest.size);
3125
3126 TPM2B_NAME name;
3127 size = 0;
3128 rc = sym_Tss2_MU_TPMT_HA_Marshal(&ha, name.name, sizeof(name.name), &size);
3129 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3130 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dbae4b95
DS
3131 "Failed to marshal key name: %s", sym_Tss2_RC_Decode(rc));
3132 name.size = size;
3133
3134 tpm2_log_debug_name(&name, "Calculated name");
3135
3136 *ret_name = name;
3137
3138 return 0;
3139}
3140
3141/* Get the "name" of a key from the TPM.
3142 *
3143 * The "name" of a key is explained above in tpm2_calculate_name().
3144 *
3145 * The handle must reference a key already present in the TPM. It may be either a public key only, or a
3146 * public/private keypair. */
3147static int tpm2_get_name(
3148 Tpm2Context *c,
3149 const Tpm2Handle *handle,
3150 TPM2B_NAME **ret_name) {
3151
3152 _cleanup_(Esys_Freep) TPM2B_NAME *name = NULL;
3153 TSS2_RC rc;
3154
3155 assert(c);
3156 assert(handle);
3157 assert(ret_name);
3158
3159 rc = sym_Esys_TR_GetName(c->esys_context, handle->esys_handle, &name);
3160 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3161 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dbae4b95
DS
3162 "Failed to get name of public key from TPM: %s", sym_Tss2_RC_Decode(rc));
3163
3164 tpm2_log_debug_name(name, "Object name");
3165
3166 *ret_name = TAKE_PTR(name);
3167
3168 return 0;
3169}
3170
8a716354
DS
3171/* Extend 'digest' with the PolicyAuthValue calculated hash. */
3172int tpm2_calculate_policy_auth_value(TPM2B_DIGEST *digest) {
3173 TPM2_CC command = TPM2_CC_PolicyAuthValue;
3174 TSS2_RC rc;
3175 int r;
3176
3177 assert(digest);
3178 assert(digest->size == SHA256_DIGEST_SIZE);
3179
3180 r = dlopen_tpm2();
3181 if (r < 0)
f9a0ee75 3182 return log_debug_errno(r, "TPM2 support not installed: %m");
8a716354
DS
3183
3184 uint8_t buf[sizeof(command)];
3185 size_t offset = 0;
3186
3187 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
3188 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3189 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
8a716354
DS
3190 "Failed to marshal PolicyAuthValue command: %s", sym_Tss2_RC_Decode(rc));
3191
3192 if (offset != sizeof(command))
f9a0ee75 3193 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
8a716354
DS
3194 "Offset 0x%zx wrong after marshalling PolicyAuthValue command", offset);
3195
3196 r = tpm2_digest_buffer(TPM2_ALG_SHA256, digest, buf, offset, /* extend= */ true);
3197 if (r < 0)
3198 return r;
3199
3200 tpm2_log_debug_digest(digest, "PolicyAuthValue calculated digest");
3201
3202 return 0;
3203}
3204
3205static int tpm2_policy_auth_value(
3206 Tpm2Context *c,
3207 const Tpm2Handle *session,
3208 TPM2B_DIGEST **ret_policy_digest) {
3209
3210 TSS2_RC rc;
3211
3212 assert(c);
3213 assert(session);
3214
3215 log_debug("Adding authValue policy.");
3216
3217 rc = sym_Esys_PolicyAuthValue(
3218 c->esys_context,
3219 session->esys_handle,
3220 ESYS_TR_NONE,
3221 ESYS_TR_NONE,
3222 ESYS_TR_NONE);
3223 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3224 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
8a716354
DS
3225 "Failed to add authValue policy to TPM: %s",
3226 sym_Tss2_RC_Decode(rc));
3227
3228 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3229}
3230
dcbc4674
DS
3231/* Extend 'digest' with the PolicyPCR calculated hash. */
3232int tpm2_calculate_policy_pcr(
6e8fb3ad 3233 const Tpm2PCRValue *pcr_values,
dcbc4674
DS
3234 size_t n_pcr_values,
3235 TPM2B_DIGEST *digest) {
3236
3237 TPM2_CC command = TPM2_CC_PolicyPCR;
3238 TSS2_RC rc;
3239 int r;
3240
dcbc4674
DS
3241 assert(pcr_values || n_pcr_values == 0);
3242 assert(digest);
3243 assert(digest->size == SHA256_DIGEST_SIZE);
3244
3245 r = dlopen_tpm2();
3246 if (r < 0)
f9a0ee75 3247 return log_debug_errno(r, "TPM2 support not installed: %m");
dcbc4674 3248
6e8fb3ad
DS
3249 TPML_PCR_SELECTION pcr_selection;
3250 _cleanup_free_ TPM2B_DIGEST *values = NULL;
3251 size_t n_values;
3252 r = tpm2_tpml_pcr_selection_from_pcr_values(pcr_values, n_pcr_values, &pcr_selection, &values, &n_values);
3253 if (r < 0)
f9a0ee75 3254 return log_debug_errno(r, "Could not convert PCR values to TPML_PCR_SELECTION: %m");
6e8fb3ad 3255
dcbc4674 3256 TPM2B_DIGEST hash = {};
6e8fb3ad 3257 r = tpm2_digest_many_digests(TPM2_ALG_SHA256, &hash, values, n_values, /* extend= */ false);
dcbc4674
DS
3258 if (r < 0)
3259 return r;
3260
3261 _cleanup_free_ uint8_t *buf = NULL;
6e8fb3ad 3262 size_t size = 0, maxsize = sizeof(command) + sizeof(pcr_selection);
dcbc4674
DS
3263
3264 buf = malloc(maxsize);
3265 if (!buf)
f9a0ee75 3266 return log_oom_debug();
dcbc4674
DS
3267
3268 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, maxsize, &size);
3269 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3270 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dcbc4674
DS
3271 "Failed to marshal PolicyPCR command: %s", sym_Tss2_RC_Decode(rc));
3272
6e8fb3ad 3273 rc = sym_Tss2_MU_TPML_PCR_SELECTION_Marshal(&pcr_selection, buf, maxsize, &size);
dcbc4674 3274 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3275 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dcbc4674
DS
3276 "Failed to marshal PCR selection: %s", sym_Tss2_RC_Decode(rc));
3277
3278 struct iovec data[] = {
3279 IOVEC_MAKE(buf, size),
3280 IOVEC_MAKE(hash.buffer, hash.size),
3281 };
3282 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
3283 if (r < 0)
3284 return r;
3285
3286 tpm2_log_debug_digest(digest, "PolicyPCR calculated digest");
3287
3288 return 0;
3289}
3290
3291static int tpm2_policy_pcr(
3292 Tpm2Context *c,
3293 const Tpm2Handle *session,
3294 const TPML_PCR_SELECTION *pcr_selection,
3295 TPM2B_DIGEST **ret_policy_digest) {
3296
3297 TSS2_RC rc;
3298
3299 assert(c);
3300 assert(session);
3301 assert(pcr_selection);
3302
3303 log_debug("Adding PCR hash policy.");
3304
3305 rc = sym_Esys_PolicyPCR(
3306 c->esys_context,
3307 session->esys_handle,
3308 ESYS_TR_NONE,
3309 ESYS_TR_NONE,
3310 ESYS_TR_NONE,
3311 NULL,
3312 pcr_selection);
3313 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3314 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
dcbc4674
DS
3315 "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
3316
3317 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3318}
3319
5c7852f7
DS
3320/* Extend 'digest' with the PolicyAuthorize calculated hash. */
3321int tpm2_calculate_policy_authorize(
3322 const TPM2B_PUBLIC *public,
3323 const TPM2B_DIGEST *policy_ref,
3324 TPM2B_DIGEST *digest) {
3325
3326 TPM2_CC command = TPM2_CC_PolicyAuthorize;
3327 TSS2_RC rc;
3328 int r;
3329
3330 assert(public);
3331 assert(digest);
3332 assert(digest->size == SHA256_DIGEST_SIZE);
3333
3334 r = dlopen_tpm2();
3335 if (r < 0)
f9a0ee75 3336 return log_debug_errno(r, "TPM2 support not installed: %m");
5c7852f7
DS
3337
3338 uint8_t buf[sizeof(command)];
3339 size_t offset = 0;
3340
3341 rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset);
3342 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3343 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
3344 "Failed to marshal PolicyAuthorize command: %s", sym_Tss2_RC_Decode(rc));
3345
3346 if (offset != sizeof(command))
f9a0ee75 3347 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
3348 "Offset 0x%zx wrong after marshalling PolicyAuthorize command", offset);
3349
3350 TPM2B_NAME name = {};
3351 r = tpm2_calculate_name(&public->publicArea, &name);
3352 if (r < 0)
3353 return r;
3354
3355 /* PolicyAuthorize does not use the previous hash value; we must zero and then extend it. */
3356 zero(digest->buffer);
3357
3358 struct iovec data[] = {
3359 IOVEC_MAKE(buf, offset),
3360 IOVEC_MAKE(name.name, name.size),
3361 };
3362 r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
3363 if (r < 0)
3364 return r;
3365
3366 /* PolicyAuthorize requires hashing twice; this is either an extension or rehashing. */
3367 if (policy_ref)
3368 r = tpm2_digest_many_digests(TPM2_ALG_SHA256, digest, policy_ref, 1, /* extend= */ true);
3369 else
3370 r = tpm2_digest_rehash(TPM2_ALG_SHA256, digest);
3371 if (r < 0)
3372 return r;
3373
3374 tpm2_log_debug_digest(digest, "PolicyAuthorize calculated digest");
3375
3376 return 0;
3377}
3378
3379static int tpm2_policy_authorize(
3380 Tpm2Context *c,
3381 const Tpm2Handle *session,
3382 TPML_PCR_SELECTION *pcr_selection,
3383 const TPM2B_PUBLIC *public,
3384 const void *fp,
3385 size_t fp_size,
3386 JsonVariant *signature_json,
3387 TPM2B_DIGEST **ret_policy_digest) {
3388
3389 TSS2_RC rc;
3390 int r;
3391
3392 assert(c);
3393 assert(session);
3394 assert(pcr_selection);
3395 assert(public);
3396 assert(fp && fp_size > 0);
3397
3398 log_debug("Adding PCR signature policy.");
3399
1dc8f518 3400 _cleanup_(tpm2_handle_freep) Tpm2Handle *pubkey_handle = NULL;
efe153bd 3401 r = tpm2_load_external(c, NULL, public, NULL, &pubkey_handle);
5c7852f7
DS
3402 if (r < 0)
3403 return r;
3404
5c7852f7
DS
3405 /* Acquire the "name" of what we just loaded */
3406 _cleanup_(Esys_Freep) TPM2B_NAME *pubkey_name = NULL;
3407 r = tpm2_get_name(c, pubkey_handle, &pubkey_name);
3408 if (r < 0)
3409 return r;
3410
3411 /* If we have a signature, proceed with verifying the PCR digest */
3412 const TPMT_TK_VERIFIED *check_ticket;
3413 _cleanup_(Esys_Freep) TPMT_TK_VERIFIED *check_ticket_buffer = NULL;
3414 _cleanup_(Esys_Freep) TPM2B_DIGEST *approved_policy = NULL;
3415 if (signature_json) {
3416 r = tpm2_policy_pcr(
3417 c,
3418 session,
3419 pcr_selection,
3420 &approved_policy);
3421 if (r < 0)
3422 return r;
3423
3424 _cleanup_free_ void *signature_raw = NULL;
3425 size_t signature_size;
3426
3427 r = find_signature(
3428 signature_json,
3429 pcr_selection,
3430 fp, fp_size,
3431 approved_policy->buffer,
3432 approved_policy->size,
3433 &signature_raw,
3434 &signature_size);
3435 if (r < 0)
3436 return r;
3437
3438 /* TPM2_VerifySignature() will only verify the RSA part of the RSA+SHA256 signature,
3439 * hence we need to do the SHA256 part ourselves, first */
3440 TPM2B_DIGEST signature_hash = *approved_policy;
3441 r = tpm2_digest_rehash(TPM2_ALG_SHA256, &signature_hash);
3442 if (r < 0)
3443 return r;
3444
53b91e19
DS
3445 r = TPM2B_PUBLIC_KEY_RSA_CHECK_SIZE(signature_size);
3446 if (r < 0)
f9a0ee75 3447 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Signature larger than buffer.");
53b91e19 3448
5c7852f7
DS
3449 TPMT_SIGNATURE policy_signature = {
3450 .sigAlg = TPM2_ALG_RSASSA,
3451 .signature.rsassa = {
3452 .hash = TPM2_ALG_SHA256,
53b91e19 3453 .sig = TPM2B_PUBLIC_KEY_RSA_MAKE(signature_raw, signature_size),
5c7852f7
DS
3454 },
3455 };
5c7852f7
DS
3456
3457 rc = sym_Esys_VerifySignature(
3458 c->esys_context,
3459 pubkey_handle->esys_handle,
3460 ESYS_TR_NONE,
3461 ESYS_TR_NONE,
3462 ESYS_TR_NONE,
3463 &signature_hash,
3464 &policy_signature,
3465 &check_ticket_buffer);
3466 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3467 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
3468 "Failed to validate signature in TPM: %s", sym_Tss2_RC_Decode(rc));
3469
3470 check_ticket = check_ticket_buffer;
3471 } else {
3472 /* When enrolling, we pass a NULL ticket */
3473 static const TPMT_TK_VERIFIED check_ticket_null = {
3474 .tag = TPM2_ST_VERIFIED,
3475 .hierarchy = TPM2_RH_OWNER,
3476 };
3477
3478 check_ticket = &check_ticket_null;
3479 }
3480
3481 rc = sym_Esys_PolicyAuthorize(
3482 c->esys_context,
3483 session->esys_handle,
3484 ESYS_TR_NONE,
3485 ESYS_TR_NONE,
3486 ESYS_TR_NONE,
3487 approved_policy,
3488 /* policyRef= */ &(const TPM2B_NONCE) {},
3489 pubkey_name,
3490 check_ticket);
3491 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3492 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
5c7852f7
DS
3493 "Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc));
3494
3495 return tpm2_get_policy_digest(c, session, ret_policy_digest);
3496}
3497
d9a1f1a7 3498/* Extend 'digest' with the calculated policy hash. */
9e437994 3499int tpm2_calculate_sealing_policy(
6e8fb3ad
DS
3500 const Tpm2PCRValue *pcr_values,
3501 size_t n_pcr_values,
d9a1f1a7 3502 const TPM2B_PUBLIC *public,
6e8fb3ad 3503 bool use_pin,
d9a1f1a7
DS
3504 TPM2B_DIGEST *digest) {
3505
3506 int r;
3507
6e8fb3ad 3508 assert(pcr_values || n_pcr_values == 0);
d9a1f1a7
DS
3509 assert(digest);
3510
3511 if (public) {
3512 r = tpm2_calculate_policy_authorize(public, NULL, digest);
3513 if (r < 0)
3514 return r;
3515 }
3516
6e8fb3ad
DS
3517 if (n_pcr_values > 0) {
3518 r = tpm2_calculate_policy_pcr(pcr_values, n_pcr_values, digest);
d9a1f1a7
DS
3519 if (r < 0)
3520 return r;
3521 }
3522
6e8fb3ad 3523 if (use_pin) {
d9a1f1a7
DS
3524 r = tpm2_calculate_policy_auth_value(digest);
3525 if (r < 0)
3526 return r;
3527 }
3528
3529 return 0;
3530}
3531
2cd9d575 3532static int tpm2_build_sealing_policy(
23e9ccc2 3533 Tpm2Context *c,
2cd9d575 3534 const Tpm2Handle *session,
d9b5841d 3535 uint32_t hash_pcr_mask,
2cd9d575 3536 uint16_t pcr_bank,
524cef3f
DS
3537 const TPM2B_PUBLIC *public,
3538 const void *fp,
3539 size_t fp_size,
d9b5841d
LP
3540 uint32_t pubkey_pcr_mask,
3541 JsonVariant *signature_json,
2f5a892a 3542 bool use_pin,
2cd9d575 3543 TPM2B_DIGEST **ret_policy_digest) {
5e521624 3544
5e521624
LP
3545 int r;
3546
3547 assert(c);
2cd9d575 3548 assert(session);
524cef3f 3549 assert(pubkey_pcr_mask == 0 || public);
5e521624 3550
2cd9d575 3551 log_debug("Building sealing policy.");
251d2ea2 3552
d9b5841d 3553 if ((hash_pcr_mask | pubkey_pcr_mask) != 0) {
2cd9d575
DS
3554 r = tpm2_pcr_mask_good(c, pcr_bank, hash_pcr_mask|pubkey_pcr_mask);
3555 if (r < 0)
3556 return r;
3557 if (r == 0)
f9a0ee75 3558 log_debug("Selected TPM2 PCRs are not initialized on this system.");
d9b5841d 3559 }
321a9d9e 3560
d9b5841d 3561 if (pubkey_pcr_mask != 0) {
d9b5841d 3562 TPML_PCR_SELECTION pcr_selection;
c69bd0ab 3563 tpm2_tpml_pcr_selection_from_mask(pubkey_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection);
524cef3f 3564 r = tpm2_policy_authorize(c, session, &pcr_selection, public, fp, fp_size, signature_json, NULL);
23b972d5
DS
3565 if (r < 0)
3566 return r;
d9b5841d
LP
3567 }
3568
3569 if (hash_pcr_mask != 0) {
d9b5841d 3570 TPML_PCR_SELECTION pcr_selection;
c69bd0ab 3571 tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection);
dcbc4674
DS
3572 r = tpm2_policy_pcr(c, session, &pcr_selection, NULL);
3573 if (r < 0)
3574 return r;
5e521624
LP
3575 }
3576
2f5a892a 3577 if (use_pin) {
8a716354
DS
3578 r = tpm2_policy_auth_value(c, session, NULL);
3579 if (r < 0)
3580 return r;
2f5a892a
GG
3581 }
3582
23b972d5
DS
3583 r = tpm2_get_policy_digest(c, session, ret_policy_digest);
3584 if (r < 0)
3585 return r;
5e521624 3586
16e16b8c 3587 return 0;
5e521624
LP
3588}
3589
e3acb4d2 3590#if HAVE_OPENSSL
6761e135
DS
3591static const struct {
3592 TPM2_ECC_CURVE tpm2_ecc_curve_id;
3593 int openssl_ecc_curve_id;
3594} tpm2_openssl_ecc_curve_table[] = {
3595 { TPM2_ECC_NIST_P192, NID_X9_62_prime192v1, },
3596 { TPM2_ECC_NIST_P224, NID_secp224r1, },
3597 { TPM2_ECC_NIST_P256, NID_X9_62_prime256v1, },
3598 { TPM2_ECC_NIST_P384, NID_secp384r1, },
3599 { TPM2_ECC_NIST_P521, NID_secp521r1, },
3600 { TPM2_ECC_SM2_P256, NID_sm2, },
3601};
3602
3603static int tpm2_ecc_curve_from_openssl_curve_id(int openssl_ecc_curve_id, TPM2_ECC_CURVE *ret) {
e3acb4d2
DS
3604 assert(ret);
3605
6761e135
DS
3606 FOREACH_ARRAY(t, tpm2_openssl_ecc_curve_table, ELEMENTSOF(tpm2_openssl_ecc_curve_table))
3607 if (t->openssl_ecc_curve_id == openssl_ecc_curve_id) {
3608 *ret = t->tpm2_ecc_curve_id;
3609 return 0;
3610 }
e3acb4d2
DS
3611
3612 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
6761e135 3613 "Openssl ECC curve id %d not supported.", openssl_ecc_curve_id);
e3acb4d2
DS
3614}
3615
6761e135 3616static int tpm2_ecc_curve_to_openssl_curve_id(TPM2_ECC_CURVE tpm2_ecc_curve_id, int *ret) {
e3acb4d2
DS
3617 assert(ret);
3618
6761e135
DS
3619 FOREACH_ARRAY(t, tpm2_openssl_ecc_curve_table, ELEMENTSOF(tpm2_openssl_ecc_curve_table))
3620 if (t->tpm2_ecc_curve_id == tpm2_ecc_curve_id) {
3621 *ret = t->openssl_ecc_curve_id;
3622 return 0;
3623 }
e3acb4d2
DS
3624
3625 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
6761e135 3626 "TPM2 ECC curve %u not supported.", tpm2_ecc_curve_id);
e3acb4d2
DS
3627}
3628
3629#define TPM2_RSA_DEFAULT_EXPONENT UINT32_C(0x10001)
3630
3631int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret) {
3632 int r;
3633
3634 assert(public);
3635 assert(ret);
3636
3637 const TPMT_PUBLIC *p = &public->publicArea;
3f4d5dfd
DS
3638 switch (p->type) {
3639 case TPM2_ALG_ECC: {
e3acb4d2
DS
3640 int curve_id;
3641 r = tpm2_ecc_curve_to_openssl_curve_id(p->parameters.eccDetail.curveID, &curve_id);
3642 if (r < 0)
3643 return r;
3644
3645 const TPMS_ECC_POINT *point = &p->unique.ecc;
3646 return ecc_pkey_from_curve_x_y(
3647 curve_id,
3648 point->x.buffer,
3649 point->x.size,
3650 point->y.buffer,
3651 point->y.size,
3652 ret);
3653 }
3f4d5dfd 3654 case TPM2_ALG_RSA: {
e3acb4d2
DS
3655 /* TPM specification Part 2 ("Structures") section for TPMS_RSA_PARAMS states "An exponent of
3656 * zero indicates that the exponent is the default of 2^16 + 1". */
3657 uint32_t exponent = htobe32(p->parameters.rsaDetail.exponent ?: TPM2_RSA_DEFAULT_EXPONENT);
3658 return rsa_pkey_from_n_e(
3659 p->unique.rsa.buffer,
3660 p->unique.rsa.size,
3661 &exponent,
3662 sizeof(exponent),
3663 ret);
3664 }
3f4d5dfd
DS
3665 default:
3666 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
3667 "TPM2 asymmetric algorithm 0x%" PRIx16 " not supported.", p->type);
3668 }
e3acb4d2
DS
3669}
3670
3671int tpm2_tpm2b_public_from_openssl_pkey(const EVP_PKEY *pkey, TPM2B_PUBLIC *ret) {
3672 int key_id, r;
3673
3674 assert(pkey);
3675 assert(ret);
3676
3677 TPMT_PUBLIC public = {
3678 .nameAlg = TPM2_ALG_SHA256,
3679 .objectAttributes = TPMA_OBJECT_DECRYPT | TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_USERWITHAUTH,
3680 .parameters.asymDetail = {
3681 .symmetric.algorithm = TPM2_ALG_NULL,
3682 .scheme.scheme = TPM2_ALG_NULL,
3683 },
3684 };
3685
3686#if OPENSSL_VERSION_MAJOR >= 3
3687 key_id = EVP_PKEY_get_id(pkey);
3688#else
3689 key_id = EVP_PKEY_id(pkey);
3690#endif
3691
3f4d5dfd
DS
3692 switch (key_id) {
3693 case EVP_PKEY_EC: {
e3acb4d2
DS
3694 public.type = TPM2_ALG_ECC;
3695
3696 int curve_id;
3697 _cleanup_free_ void *x = NULL, *y = NULL;
3698 size_t x_size, y_size;
3699 r = ecc_pkey_to_curve_x_y(pkey, &curve_id, &x, &x_size, &y, &y_size);
3700 if (r < 0)
ed35ac31 3701 return log_debug_errno(r, "Could not get ECC key curve/x/y: %m");
e3acb4d2
DS
3702
3703 TPM2_ECC_CURVE curve;
3704 r = tpm2_ecc_curve_from_openssl_curve_id(curve_id, &curve);
3705 if (r < 0)
3706 return r;
3707
3708 public.parameters.eccDetail.curveID = curve;
3709
3710 public.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
3711
3712 r = TPM2B_ECC_PARAMETER_CHECK_SIZE(x_size);
3713 if (r < 0)
ed35ac31 3714 return log_debug_errno(r, "ECC key x size %zu too large.", x_size);
e3acb4d2
DS
3715
3716 public.unique.ecc.x = TPM2B_ECC_PARAMETER_MAKE(x, x_size);
3717
3718 r = TPM2B_ECC_PARAMETER_CHECK_SIZE(y_size);
3719 if (r < 0)
ed35ac31 3720 return log_debug_errno(r, "ECC key y size %zu too large.", y_size);
e3acb4d2
DS
3721
3722 public.unique.ecc.y = TPM2B_ECC_PARAMETER_MAKE(y, y_size);
3f4d5dfd
DS
3723
3724 break;
3725 }
3726 case EVP_PKEY_RSA: {
e3acb4d2
DS
3727 public.type = TPM2_ALG_RSA;
3728
3729 _cleanup_free_ void *n = NULL, *e = NULL;
3730 size_t n_size, e_size;
3731 r = rsa_pkey_to_n_e(pkey, &n, &n_size, &e, &e_size);
3732 if (r < 0)
ed35ac31 3733 return log_debug_errno(r, "Could not get RSA key n/e: %m");
e3acb4d2
DS
3734
3735 r = TPM2B_PUBLIC_KEY_RSA_CHECK_SIZE(n_size);
3736 if (r < 0)
ed35ac31 3737 return log_debug_errno(r, "RSA key n size %zu too large.", n_size);
e3acb4d2
DS
3738
3739 public.unique.rsa = TPM2B_PUBLIC_KEY_RSA_MAKE(n, n_size);
3740 public.parameters.rsaDetail.keyBits = n_size * 8;
3741
3742 if (sizeof(uint32_t) < e_size)
ed35ac31 3743 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
e3acb4d2
DS
3744 "RSA key e size %zu too large.", e_size);
3745
3746 uint32_t exponent = 0;
70cb382d 3747 memcpy(&exponent, e, e_size);
e3acb4d2
DS
3748 exponent = be32toh(exponent) >> (32 - e_size * 8);
3749 if (exponent == TPM2_RSA_DEFAULT_EXPONENT)
3750 exponent = 0;
3751 public.parameters.rsaDetail.exponent = exponent;
3f4d5dfd
DS
3752
3753 break;
3754 }
3755 default:
e3acb4d2
DS
3756 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
3757 "EVP_PKEY type %d not supported.", key_id);
3f4d5dfd 3758 }
e3acb4d2
DS
3759
3760 *ret = (TPM2B_PUBLIC) {
3761 .size = sizeof(public),
3762 .publicArea = public,
3763 };
3764
3765 return 0;
3766}
3767#endif
3768
3769int tpm2_tpm2b_public_to_fingerprint(
3770 const TPM2B_PUBLIC *public,
3771 void **ret_fingerprint,
3772 size_t *ret_fingerprint_size) {
3773
3774#if HAVE_OPENSSL
3775 int r;
3776
3777 assert(public);
3778 assert(ret_fingerprint);
3779 assert(ret_fingerprint_size);
3780
3781 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
3782 r = tpm2_tpm2b_public_to_openssl_pkey(public, &pkey);
3783 if (r < 0)
3784 return r;
3785
3786 /* Hardcode fingerprint to SHA256 */
3787 return pubkey_fingerprint(pkey, EVP_sha256(), ret_fingerprint, ret_fingerprint_size);
3788#else
f9a0ee75 3789 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
e3acb4d2
DS
3790#endif
3791}
3792
3793int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret) {
3794#if HAVE_OPENSSL
3795 int r;
3796
3797 assert(pem);
3798 assert(ret);
3799
3800 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
3801 r = openssl_pkey_from_pem(pem, pem_size, &pkey);
3802 if (r < 0)
3803 return r;
3804
3805 return tpm2_tpm2b_public_from_openssl_pkey(pkey, ret);
3806#else
f9a0ee75 3807 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
e3acb4d2
DS
3808#endif
3809}
3810
653c3fe9
DS
3811/* Marshal the public and private objects into a single nonstandard 'blob'. This is not a (publicly) standard
3812 * format, this is specific to how we currently store the sealed object. This 'blob' can be unmarshalled by
3813 * tpm2_unmarshal_blob(). */
3814int tpm2_marshal_blob(
3815 const TPM2B_PUBLIC *public,
3816 const TPM2B_PRIVATE *private,
3817 void **ret_blob,
3818 size_t *ret_blob_size) {
3819
3820 TSS2_RC rc;
3821
3822 assert(public);
3823 assert(private);
3824 assert(ret_blob);
3825 assert(ret_blob_size);
3826
3827 size_t max_size = sizeof(*private) + sizeof(*public);
3828
3829 _cleanup_free_ void *blob = malloc(max_size);
3830 if (!blob)
3831 return log_oom_debug();
3832
3833 size_t blob_size = 0;
3834 rc = sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, blob, max_size, &blob_size);
3835 if (rc != TSS2_RC_SUCCESS)
3836 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3837 "Failed to marshal private key: %s", sym_Tss2_RC_Decode(rc));
3838
3839 rc = sym_Tss2_MU_TPM2B_PUBLIC_Marshal(public, blob, max_size, &blob_size);
3840 if (rc != TSS2_RC_SUCCESS)
3841 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3842 "Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
3843
3844 *ret_blob = TAKE_PTR(blob);
3845 *ret_blob_size = blob_size;
3846
3847 return 0;
3848}
3849
3850/* Unmarshal the 'blob' into public and private objects. This is not a (publicly) standard format, this is
3851 * specific to how we currently store the sealed object. This expects the 'blob' to have been created by
3852 * tpm2_marshal_blob(). */
3853int tpm2_unmarshal_blob(
3854 const void *blob,
3855 size_t blob_size,
3856 TPM2B_PUBLIC *ret_public,
3857 TPM2B_PRIVATE *ret_private) {
3858
3859 TSS2_RC rc;
3860
3861 assert(blob);
3862 assert(ret_public);
3863 assert(ret_private);
3864
3865 TPM2B_PRIVATE private = {};
3866 size_t offset = 0;
3867 rc = sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal(blob, blob_size, &offset, &private);
3868 if (rc != TSS2_RC_SUCCESS)
3869 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3870 "Failed to unmarshal private key: %s", sym_Tss2_RC_Decode(rc));
3871
3872 TPM2B_PUBLIC public = {};
3873 rc = sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal(blob, blob_size, &offset, &public);
3874 if (rc != TSS2_RC_SUCCESS)
3875 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
3876 "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc));
3877
3878 *ret_public = public;
3879 *ret_private = private;
3880
3881 return 0;
3882}
3883
1eff4242
DS
3884/* Serialize a handle. This produces a binary object that can be later deserialized (by the same TPM), even
3885 * across restarts of the TPM or reboots (assuming the handle is persistent). */
3886static int tpm2_serialize(
3887 Tpm2Context *c,
3888 const Tpm2Handle *handle,
3889 void **ret_serialized,
3890 size_t *ret_serialized_size) {
3891
3892 TSS2_RC rc;
3893
3894 assert(c);
3895 assert(handle);
3896 assert(ret_serialized);
3897 assert(ret_serialized_size);
3898
3899 _cleanup_(Esys_Freep) unsigned char *serialized = NULL;
3900 size_t size = 0;
3901 rc = sym_Esys_TR_Serialize(c->esys_context, handle->esys_handle, &serialized, &size);
3902 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3903 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1eff4242
DS
3904 "Failed to serialize: %s", sym_Tss2_RC_Decode(rc));
3905
3906 *ret_serialized = TAKE_PTR(serialized);
3907 *ret_serialized_size = size;
3908
3909 return 0;
3910}
3911
3912static int tpm2_deserialize(
3913 Tpm2Context *c,
3914 const void *serialized,
3915 size_t serialized_size,
3916 Tpm2Handle **ret_handle) {
3917
3918 TSS2_RC rc;
3919 int r;
3920
3921 assert(c);
3922 assert(serialized);
3923 assert(ret_handle);
3924
3925 _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
3926 r = tpm2_handle_new(c, &handle);
3927 if (r < 0)
3928 return r;
3929
3930 /* Since this is an existing handle in the TPM we should not implicitly flush it. */
3931 handle->flush = false;
3932
3933 rc = sym_Esys_TR_Deserialize(c->esys_context, serialized, serialized_size, &handle->esys_handle);
3934 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 3935 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
1eff4242
DS
3936 "Failed to deserialize: %s", sym_Tss2_RC_Decode(rc));
3937
3938 *ret_handle = TAKE_PTR(handle);
3939
3940 return 0;
3941}
3942
9e437994 3943int tpm2_seal(Tpm2Context *c,
382bfd90 3944 uint32_t seal_key_handle,
9e437994 3945 const TPM2B_DIGEST *policy,
d9b5841d
LP
3946 const char *pin,
3947 void **ret_secret,
3948 size_t *ret_secret_size,
3949 void **ret_blob,
3950 size_t *ret_blob_size,
acbb504e
WR
3951 uint16_t *ret_primary_alg,
3952 void **ret_srk_buf,
3953 size_t *ret_srk_buf_size) {
5e521624 3954
9e437994 3955 uint16_t primary_alg = 0;
5e521624
LP
3956 int r;
3957
3958 assert(ret_secret);
3959 assert(ret_secret_size);
3960 assert(ret_blob);
3961 assert(ret_blob_size);
5e521624
LP
3962
3963 /* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that
3964 * is randomized when the TPM2 is first initialized or reset and remains stable across boots. We
2b92a672
LP
3965 * generate a "primary" key pair derived from that (ECC if possible, RSA as fallback). Given the seed
3966 * remains fixed this will result in the same key pair whenever we specify the exact same parameters
3967 * for it. We then create a PCR-bound policy session, which calculates a hash on the current PCR
3968 * values of the indexes we specify. We then generate a randomized key on the host (which is the key
3969 * we actually enroll in the LUKS2 keyslots), which we upload into the TPM2, where it is encrypted
3970 * with the "primary" key, taking the PCR policy session into account. We then download the encrypted
3971 * key from the TPM2 ("sealing") and marshall it into binary form, which is ultimately placed in the
3972 * LUKS2 JSON header.
5e521624
LP
3973 *
3974 * The TPM2 "seed" key and "primary" keys never leave the TPM2 chip (and cannot be extracted at
3975 * all). The random key we enroll in LUKS2 we generate on the host using the Linux random device. It
3976 * is stored in the LUKS2 JSON only in encrypted form with the "primary" key of the TPM2 chip, thus
3977 * binding the unlocking to the TPM2 chip. */
3978
ee6a8713 3979 usec_t start = now(CLOCK_MONOTONIC);
692597c8 3980
5e521624
LP
3981 /* We use a keyed hash object (i.e. HMAC) to store the secret key we want to use for unlocking the
3982 * LUKS2 volume with. We don't ever use for HMAC/keyed hash operations however, we just use it
3983 * because it's a key type that is universally supported and suitable for symmetric binary blobs. */
e3f1f210
DS
3984 TPMT_PUBLIC hmac_template = {
3985 .type = TPM2_ALG_KEYEDHASH,
3986 .nameAlg = TPM2_ALG_SHA256,
3987 .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
3988 .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
3989 .unique.keyedHash.size = SHA256_DIGEST_SIZE,
9e437994 3990 .authPolicy = policy ? *policy : TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE),
5e521624
LP
3991 };
3992
e3f1f210
DS
3993 TPMS_SENSITIVE_CREATE hmac_sensitive = {
3994 .data.size = hmac_template.unique.keyedHash.size,
5e521624 3995 };
ee6a8713
DS
3996
3997 CLEANUP_ERASE(hmac_sensitive);
3998
94a4ff2d 3999 if (pin) {
f230572f 4000 r = tpm2_get_pin_auth(TPM2_ALG_SHA256, pin, &hmac_sensitive.userAuth);
94a4ff2d
DS
4001 if (r < 0)
4002 return r;
4003 }
0e15c14f 4004
e3f1f210 4005 assert(sizeof(hmac_sensitive.data.buffer) >= hmac_sensitive.data.size);
5e521624 4006
23e9ccc2 4007 (void) tpm2_credit_random(c);
5e521624
LP
4008
4009 log_debug("Generating secret key data.");
4010
e3f1f210 4011 r = crypto_random_bytes(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
16e16b8c 4012 if (r < 0)
f9a0ee75 4013 return log_debug_errno(r, "Failed to generate secret key: %m");
5e521624 4014
1dc8f518 4015 _cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
cea525a9 4016 if (ret_srk_buf) {
9e437994 4017 _cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
382bfd90
DS
4018
4019 if (IN_SET(seal_key_handle, 0, TPM2_SRK_HANDLE)) {
4020 r = tpm2_get_or_create_srk(
4021 c,
4022 /* session= */ NULL,
4023 &primary_public,
4024 /* ret_name= */ NULL,
4025 /* ret_qname= */ NULL,
4026 &primary_handle);
4027 if (r < 0)
4028 return r;
4029 } else if (IN_SET(TPM2_HANDLE_TYPE(seal_key_handle), TPM2_HT_TRANSIENT, TPM2_HT_PERSISTENT)) {
4030 r = tpm2_index_to_handle(
4031 c,
4032 seal_key_handle,
4033 /* session= */ NULL,
4034 &primary_public,
4035 /* ret_name= */ NULL,
4036 /* ret_qname= */ NULL,
4037 &primary_handle);
4038 if (r < 0)
4039 return r;
4040 if (r == 0)
4041 /* We do NOT automatically create anything other than the SRK */
4042 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
4043 "No handle found at index 0x%" PRIx32, seal_key_handle);
4044 } else
4045 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
4046 "Seal key handle 0x%" PRIx32 " is neither transient nor persistent.",
4047 seal_key_handle);
9e437994
DS
4048
4049 primary_alg = primary_public->publicArea.type;
cea525a9 4050 } else {
382bfd90
DS
4051 if (seal_key_handle != 0)
4052 log_debug("Using primary alg sealing, but seal key handle also provided; ignoring seal key handle.");
4053
cea525a9 4054 /* TODO: force all callers to provide ret_srk_buf, so we can stop sealing with the legacy templates. */
9e437994
DS
4055 primary_alg = TPM2_ALG_ECC;
4056
aff853f8 4057 TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
9e437994 4058 r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
cea525a9 4059 if (r < 0)
f9a0ee75 4060 return log_debug_errno(r, "Could not get legacy ECC template: %m");
cea525a9 4061
aff853f8 4062 if (!tpm2_supports_tpmt_public(c, &template.publicArea)) {
9e437994
DS
4063 primary_alg = TPM2_ALG_RSA;
4064
4065 r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
cea525a9 4066 if (r < 0)
f9a0ee75 4067 return log_debug_errno(r, "Could not get legacy RSA template: %m");
cea525a9 4068
aff853f8 4069 if (!tpm2_supports_tpmt_public(c, &template.publicArea))
f9a0ee75 4070 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
cea525a9
DS
4071 "TPM does not support either ECC or RSA legacy template.");
4072 }
4073
aff853f8 4074 r = tpm2_create_primary(
cea525a9 4075 c,
cea525a9
DS
4076 /* session= */ NULL,
4077 &template,
4078 /* sensitive= */ NULL,
9e437994 4079 /* ret_public= */ NULL,
cea525a9
DS
4080 &primary_handle);
4081 if (r < 0)
4082 return r;
4083 }
d9a1f1a7 4084
1dc8f518 4085 _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
73592a7c 4086 r = tpm2_make_encryption_session(c, primary_handle, /* bind_key= */ NULL, &encryption_session);
d9a1f1a7
DS
4087 if (r < 0)
4088 return r;
4089
ee6a8713
DS
4090 _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
4091 _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
e3f1f210
DS
4092 r = tpm2_create(c, primary_handle, encryption_session, &hmac_template, &hmac_sensitive, &public, &private);
4093 if (r < 0)
4094 return r;
5e521624 4095
ee6a8713 4096 _cleanup_(erase_and_freep) void *secret = NULL;
e3f1f210 4097 secret = memdup(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
16e16b8c 4098 if (!secret)
f9a0ee75 4099 return log_oom_debug();
5e521624
LP
4100
4101 log_debug("Marshalling private and public part of HMAC key.");
4102
e8858f11 4103 _cleanup_free_ void *blob = NULL;
653c3fe9
DS
4104 size_t blob_size;
4105 r = tpm2_marshal_blob(public, private, &blob, &blob_size);
4106 if (r < 0)
f9a0ee75 4107 return log_debug_errno(r, "Could not create sealed blob: %m");
5e521624 4108
5291f26d
ZJS
4109 if (DEBUG_LOGGING)
4110 log_debug("Completed TPM2 key sealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
5e521624 4111
1eff4242
DS
4112 _cleanup_free_ void *srk_buf = NULL;
4113 size_t srk_buf_size = 0;
acbb504e 4114 if (ret_srk_buf) {
1eff4242
DS
4115 _cleanup_(Esys_Freep) void *tmp = NULL;
4116 r = tpm2_serialize(c, primary_handle, &tmp, &srk_buf_size);
4117 if (r < 0)
4118 return r;
4119
acbb504e
WR
4120 /*
4121 * make a copy since we don't want the caller to understand that
4122 * ESYS allocated the pointer. It would make tracking what deallocator
4123 * to use for srk_buf in which context a PITA.
4124 */
1eff4242
DS
4125 srk_buf = memdup(tmp, srk_buf_size);
4126 if (!srk_buf)
f9a0ee75 4127 return log_oom_debug();
acbb504e 4128
1eff4242 4129 *ret_srk_buf = TAKE_PTR(srk_buf);
acbb504e
WR
4130 *ret_srk_buf_size = srk_buf_size;
4131 }
4132
5e521624 4133 *ret_secret = TAKE_PTR(secret);
e3f1f210 4134 *ret_secret_size = hmac_sensitive.data.size;
5e521624
LP
4135 *ret_blob = TAKE_PTR(blob);
4136 *ret_blob_size = blob_size;
9e437994
DS
4137
4138 if (ret_primary_alg)
4139 *ret_primary_alg = primary_alg;
5e521624 4140
16e16b8c 4141 return 0;
5e521624
LP
4142}
4143
0254e4d6
AAF
4144#define RETRY_UNSEAL_MAX 30u
4145
db7fdf15 4146int tpm2_unseal(Tpm2Context *c,
d9b5841d 4147 uint32_t hash_pcr_mask,
07697bfe 4148 uint16_t pcr_bank,
d9b5841d
LP
4149 const void *pubkey,
4150 size_t pubkey_size,
4151 uint32_t pubkey_pcr_mask,
4152 JsonVariant *signature,
4153 const char *pin,
2b92a672 4154 uint16_t primary_alg,
5e521624
LP
4155 const void *blob,
4156 size_t blob_size,
4157 const void *known_policy_hash,
4158 size_t known_policy_hash_size,
acbb504e
WR
4159 const void *srk_buf,
4160 size_t srk_buf_size,
5e521624
LP
4161 void **ret_secret,
4162 size_t *ret_secret_size) {
4163
5e521624 4164 TSS2_RC rc;
5e521624
LP
4165 int r;
4166
4167 assert(blob);
4168 assert(blob_size > 0);
4169 assert(known_policy_hash_size == 0 || known_policy_hash);
d9b5841d 4170 assert(pubkey_size == 0 || pubkey);
5e521624
LP
4171 assert(ret_secret);
4172 assert(ret_secret_size);
4173
d9b5841d
LP
4174 assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
4175 assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));
5e521624
LP
4176
4177 /* So here's what we do here: We connect to the TPM2 chip. As we do when sealing we generate a
dc176813
ZJS
4178 * "primary" key on the TPM2 chip, with the same parameters as well as a PCR-bound policy session.
4179 * Given we pass the same parameters, this will result in the same "primary" key, and same policy
4180 * hash (the latter of course, only if the PCR values didn't change in between). We unmarshal the
4181 * encrypted key we stored in the LUKS2 JSON token header and upload it into the TPM2, where it is
4182 * decrypted if the seed and the PCR policy were right ("unsealing"). We then download the result,
5e521624
LP
4183 * and use it to unlock the LUKS2 volume. */
4184
98497426 4185 usec_t start = now(CLOCK_MONOTONIC);
5e521624 4186
653c3fe9
DS
4187 TPM2B_PUBLIC public;
4188 TPM2B_PRIVATE private;
4189 r = tpm2_unmarshal_blob(blob, blob_size, &public, &private);
4190 if (r < 0)
f9a0ee75 4191 return log_debug_errno(r, "Could not extract parts from blob: %m");
5e521624 4192
730d6ab9
DS
4193 /* Older code did not save the pcr_bank, and unsealing needed to detect the best pcr bank to use,
4194 * so we need to handle that legacy situation. */
4195 if (pcr_bank == UINT16_MAX) {
4196 r = tpm2_get_best_pcr_bank(c, hash_pcr_mask|pubkey_pcr_mask, &pcr_bank);
4197 if (r < 0)
4198 return r;
4199 }
4200
20988602 4201 _cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
acbb504e 4202 if (srk_buf) {
1eff4242 4203 r = tpm2_deserialize(c, srk_buf, srk_buf_size, &primary_handle);
acbb504e
WR
4204 if (r < 0)
4205 return r;
20988602 4206 } else if (primary_alg != 0) {
aff853f8
DS
4207 TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
4208 r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
20988602 4209 if (r < 0)
f9a0ee75 4210 return log_debug_errno(r, "Could not get legacy template: %m");
20988602 4211
aff853f8 4212 r = tpm2_create_primary(
20988602 4213 c,
20988602
DS
4214 /* session= */ NULL,
4215 &template,
4216 /* sensitive= */ NULL,
4217 /* ret_public= */ NULL,
20988602 4218 &primary_handle);
acbb504e
WR
4219 if (r < 0)
4220 return r;
20988602 4221 } else
f9a0ee75 4222 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
20988602 4223 "No SRK or primary alg provided.");
da29de23 4224
5e521624
LP
4225 log_debug("Loading HMAC key into TPM.");
4226
0e15c14f
WR
4227 /*
4228 * Nothing sensitive on the bus, no need for encryption. Even if an attacker
acbb504e
WR
4229 * gives you back a different key, the session initiation will fail. In the
4230 * SRK model, the tpmKey is verified. In the non-srk model, with pin, the bindKey
4231 * provides protections.
0e15c14f 4232 */
1dc8f518 4233 _cleanup_(tpm2_handle_freep) Tpm2Handle *hmac_key = NULL;
20988602 4234 r = tpm2_load(c, primary_handle, NULL, &public, &private, &hmac_key);
16e16b8c
DS
4235 if (r < 0)
4236 return r;
4237
e3acb4d2 4238 TPM2B_PUBLIC pubkey_tpm2b;
524cef3f
DS
4239 _cleanup_free_ void *fp = NULL;
4240 size_t fp_size = 0;
4241 if (pubkey) {
e3acb4d2 4242 r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &pubkey_tpm2b);
524cef3f 4243 if (r < 0)
f9a0ee75 4244 return log_debug_errno(r, "Could not create TPMT_PUBLIC: %m");
e3acb4d2
DS
4245
4246 r = tpm2_tpm2b_public_to_fingerprint(&pubkey_tpm2b, &fp, &fp_size);
4247 if (r < 0)
f9a0ee75 4248 return log_debug_errno(r, "Could not get key fingerprint: %m");
524cef3f
DS
4249 }
4250
409a65f8
DS
4251 /*
4252 * if a pin is set for the seal object, use it to bind the session
4253 * key to that object. This prevents active bus interposers from
4254 * faking a TPM and seeing the unsealed value. An active interposer
4255 * could fake a TPM, satisfying the encrypted session, and just
4256 * forward everything to the *real* TPM.
4257 */
4258 r = tpm2_set_auth(c, hmac_key, pin);
4259 if (r < 0)
4260 return r;
4261
1dc8f518 4262 _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
20988602 4263 r = tpm2_make_encryption_session(c, primary_handle, hmac_key, &encryption_session);
0e15c14f 4264 if (r < 0)
16e16b8c 4265 return r;
2f5a892a 4266
98497426 4267 _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL;
0254e4d6 4268 for (unsigned i = RETRY_UNSEAL_MAX;; i--) {
1dc8f518 4269 _cleanup_(tpm2_handle_freep) Tpm2Handle *policy_session = NULL;
23b972d5 4270 _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
0254e4d6 4271 r = tpm2_make_policy_session(
23e9ccc2 4272 c,
20988602 4273 primary_handle,
2cd9d575 4274 encryption_session,
2cd9d575
DS
4275 &policy_session);
4276 if (r < 0)
4277 return r;
4278
4279 r = tpm2_build_sealing_policy(
4280 c,
4281 policy_session,
0254e4d6
AAF
4282 hash_pcr_mask,
4283 pcr_bank,
e3acb4d2 4284 pubkey ? &pubkey_tpm2b : NULL,
524cef3f 4285 fp, fp_size,
0254e4d6
AAF
4286 pubkey_pcr_mask,
4287 signature,
4288 !!pin,
2cd9d575 4289 &policy_digest);
0254e4d6 4290 if (r < 0)
16e16b8c 4291 return r;
2f5a892a 4292
0254e4d6
AAF
4293 /* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not
4294 * wait until the TPM2 tells us to go away. */
4295 if (known_policy_hash_size > 0 &&
4296 memcmp_nn(policy_digest->buffer, policy_digest->size, known_policy_hash, known_policy_hash_size) != 0)
f9a0ee75 4297 return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
0254e4d6
AAF
4298 "Current policy digest does not match stored policy digest, cancelling "
4299 "TPM2 authentication attempt.");
2f5a892a 4300
0254e4d6 4301 log_debug("Unsealing HMAC key.");
5e521624 4302
0254e4d6 4303 rc = sym_Esys_Unseal(
68d084ce 4304 c->esys_context,
16e16b8c
DS
4305 hmac_key->esys_handle,
4306 policy_session->esys_handle,
2cd9d575 4307 encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
0254e4d6
AAF
4308 ESYS_TR_NONE,
4309 &unsealed);
16e16b8c
DS
4310 if (rc == TSS2_RC_SUCCESS)
4311 break;
4312 if (rc != TPM2_RC_PCR_CHANGED || i == 0)
f9a0ee75 4313 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
16e16b8c
DS
4314 "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
4315 log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
5e521624
LP
4316 }
4317
98497426 4318 _cleanup_(erase_and_freep) char *secret = NULL;
5e521624
LP
4319 secret = memdup(unsealed->buffer, unsealed->size);
4320 explicit_bzero_safe(unsealed->buffer, unsealed->size);
16e16b8c 4321 if (!secret)
f9a0ee75 4322 return log_oom_debug();
5e521624 4323
5291f26d
ZJS
4324 if (DEBUG_LOGGING)
4325 log_debug("Completed TPM2 key unsealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
5e521624
LP
4326
4327 *ret_secret = TAKE_PTR(secret);
4328 *ret_secret_size = unsealed->size;
4329
16e16b8c 4330 return 0;
5e521624
LP
4331}
4332
4333#endif
4334
4335int tpm2_list_devices(void) {
4336#if HAVE_TPM2
4337 _cleanup_(table_unrefp) Table *t = NULL;
5d2a48da 4338 _cleanup_closedir_ DIR *d = NULL;
5e521624
LP
4339 int r;
4340
4341 r = dlopen_tpm2();
4342 if (r < 0)
4343 return log_error_errno(r, "TPM2 support is not installed.");
4344
4345 t = table_new("path", "device", "driver");
4346 if (!t)
4347 return log_oom();
4348
4349 d = opendir("/sys/class/tpmrm");
4350 if (!d) {
4351 log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open /sys/class/tpmrm: %m");
4352 if (errno != ENOENT)
4353 return -errno;
4354 } else {
4355 for (;;) {
4356 _cleanup_free_ char *device_path = NULL, *device = NULL, *driver_path = NULL, *driver = NULL, *node = NULL;
4357 struct dirent *de;
4358
4359 de = readdir_no_dot(d);
4360 if (!de)
4361 break;
4362
4363 device_path = path_join("/sys/class/tpmrm", de->d_name, "device");
4364 if (!device_path)
4365 return log_oom();
4366
4367 r = readlink_malloc(device_path, &device);
4368 if (r < 0)
4369 log_debug_errno(r, "Failed to read device symlink %s, ignoring: %m", device_path);
4370 else {
4371 driver_path = path_join(device_path, "driver");
4372 if (!driver_path)
4373 return log_oom();
4374
4375 r = readlink_malloc(driver_path, &driver);
4376 if (r < 0)
4377 log_debug_errno(r, "Failed to read driver symlink %s, ignoring: %m", driver_path);
4378 }
4379
4380 node = path_join("/dev", de->d_name);
4381 if (!node)
4382 return log_oom();
4383
4384 r = table_add_many(
4385 t,
4386 TABLE_PATH, node,
4387 TABLE_STRING, device ? last_path_component(device) : NULL,
4388 TABLE_STRING, driver ? last_path_component(driver) : NULL);
4389 if (r < 0)
4390 return table_log_add_error(r);
4391 }
4392 }
4393
4394 if (table_get_rows(t) <= 1) {
4395 log_info("No suitable TPM2 devices found.");
4396 return 0;
4397 }
4398
4399 r = table_print(t, stdout);
4400 if (r < 0)
4401 return log_error_errno(r, "Failed to show device table: %m");
4402
4403 return 0;
4404#else
4405 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
4406 "TPM2 not supported on this build.");
4407#endif
4408}
4409
f9a0ee75 4410int tpm2_find_device_auto(char **ret) {
5e521624 4411#if HAVE_TPM2
5d2a48da 4412 _cleanup_closedir_ DIR *d = NULL;
5e521624
LP
4413 int r;
4414
4415 r = dlopen_tpm2();
4416 if (r < 0)
f9a0ee75 4417 return log_debug_errno(r, "TPM2 support is not installed.");
5e521624
LP
4418
4419 d = opendir("/sys/class/tpmrm");
4420 if (!d) {
f9a0ee75 4421 log_debug_errno(errno, "Failed to open /sys/class/tpmrm: %m");
5e521624
LP
4422 if (errno != ENOENT)
4423 return -errno;
4424 } else {
4425 _cleanup_free_ char *node = NULL;
4426
4427 for (;;) {
4428 struct dirent *de;
4429
4430 de = readdir_no_dot(d);
4431 if (!de)
4432 break;
4433
4434 if (node)
f9a0ee75 4435 return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
5e521624
LP
4436 "More than one TPM2 (tpmrm) device found.");
4437
4438 node = path_join("/dev", de->d_name);
4439 if (!node)
f9a0ee75 4440 return log_oom_debug();
5e521624
LP
4441 }
4442
4443 if (node) {
4444 *ret = TAKE_PTR(node);
4445 return 0;
4446 }
4447 }
4448
f9a0ee75 4449 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "No TPM2 (tpmrm) device found.");
5e521624 4450#else
f9a0ee75 4451 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
5e521624
LP
4452 "TPM2 not supported on this build.");
4453#endif
4454}
4455
15c591d1 4456#if HAVE_TPM2
cb19bdae
LP
4457static const char* tpm2_userspace_event_type_table[_TPM2_USERSPACE_EVENT_TYPE_MAX] = {
4458 [TPM2_EVENT_PHASE] = "phase",
4459 [TPM2_EVENT_FILESYSTEM] = "filesystem",
4460 [TPM2_EVENT_VOLUME_KEY] = "volume-key",
4461 [TPM2_EVENT_MACHINE_ID] = "machine-id",
4462};
4463
4464DEFINE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);
4465
4466const char *tpm2_userspace_log_path(void) {
9551aa70 4467 return secure_getenv("SYSTEMD_MEASURE_LOG_USERSPACE") ?: "/run/log/systemd/tpm2-measure.log";
cb19bdae
LP
4468}
4469
4470static int tpm2_userspace_log_open(void) {
4471 _cleanup_close_ int fd = -EBADF;
4472 struct stat st;
4473 const char *e;
4474 int r;
4475
4476 e = tpm2_userspace_log_path();
4477 (void) mkdir_parents(e, 0755);
4478
4479 /* We use access mode 0600 here (even though the measurements should not strictly be confidential),
4480 * because we use BSD file locking on it, and if anyone but root can access the file they can also
4481 * lock it, which we want to avoid. */
4482 fd = open(e, O_CREAT|O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
4483 if (fd < 0)
f9a0ee75 4484 return log_debug_errno(errno, "Failed to open TPM log file '%s' for writing, ignoring: %m", e);
cb19bdae
LP
4485
4486 if (flock(fd, LOCK_EX) < 0)
f9a0ee75 4487 return log_debug_errno(errno, "Failed to lock TPM log file '%s', ignoring: %m", e);
cb19bdae
LP
4488
4489 if (fstat(fd, &st) < 0)
f9a0ee75 4490 return log_debug_errno(errno, "Failed to fstat TPM log file '%s', ignoring: %m", e);
cb19bdae
LP
4491
4492 r = stat_verify_regular(&st);
4493 if (r < 0)
f9a0ee75 4494 return log_debug_errno(r, "TPM log file '%s' is not regular, ignoring: %m", e);
cb19bdae
LP
4495
4496 /* We set the sticky bit when we are about to append to the log file. We'll unset it afterwards
4497 * again. If we manage to take a lock on a file that has it set we know we didn't write it fully and
4498 * it is corrupted. Ideally we'd like to use user xattrs for this, but unfortunately tmpfs (which is
4499 * our assumed backend fs) doesn't know user xattrs. */
4500 if (st.st_mode & S_ISVTX)
f9a0ee75 4501 return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "TPM log file '%s' aborted, ignoring.", e);
cb19bdae
LP
4502
4503 if (fchmod(fd, 0600 | S_ISVTX) < 0)
f9a0ee75 4504 return log_debug_errno(errno, "Failed to chmod() TPM log file '%s', ignoring: %m", e);
cb19bdae
LP
4505
4506 return TAKE_FD(fd);
4507}
4508
4509static int tpm2_userspace_log(
4510 int fd,
4511 unsigned pcr_index,
4512 const TPML_DIGEST_VALUES *values,
4513 Tpm2UserspaceEventType event_type,
4514 const char *description) {
4515
4516 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *array = NULL;
4517 _cleanup_free_ char *f = NULL;
4518 sd_id128_t boot_id;
4519 int r;
4520
4521 assert(values);
4522 assert(values->count > 0);
4523
4524 /* We maintain a local PCR measurement log. This implements a subset of the TCG Canonical Event Log
4525 * Format – the JSON flavour –
4526 * (https://trustedcomputinggroup.org/resource/canonical-event-log-format/), but departs in certain
4527 * ways from it, specifically:
4528 *
4529 * - We don't write out a recnum. It's a bit too vaguely defined which means we'd have to read
4530 * through the whole logs (include firmware logs) before knowing what the next value is we should
4531 * use. Hence we simply don't write this out as append-time, and instead expect a consumer to add
4532 * it in when it uses the data.
4533 *
4534 * - We write this out in RFC 7464 application/json-seq rather than as a JSON array. Writing this as
4535 * JSON array would mean that for each appending we'd have to read the whole log file fully into
4536 * memory before writing it out again. We prefer a strictly append-only write pattern however. (RFC
4537 * 7464 is what jq --seq eats.) Conversion into a proper JSON array is trivial.
4538 *
4539 * It should be possible to convert this format in a relatively straight-forward way into the
4540 * official TCG Canonical Event Log Format on read, by simply adding in a few more fields that can be
4541 * determined from the full dataset.
4542 *
4543 * We set the 'content_type' field to "systemd" to make clear this data is generated by us, and
4544 * include various interesting fields in the 'content' subobject, including a CLOCK_BOOTTIME
4545 * timestamp which can be used to order this measurement against possibly other measurements
4546 * independently done by other subsystems on the system.
4547 */
4548
4549 if (fd < 0) /* Apparently tpm2_local_log_open() failed earlier, let's not complain again */
4550 return 0;
4551
4552 for (size_t i = 0; i < values->count; i++) {
4553 const EVP_MD *implementation;
4554 const char *a;
4555
4556 assert_se(a = tpm2_hash_alg_to_string(values->digests[i].hashAlg));
4557 assert_se(implementation = EVP_get_digestbyname(a));
4558
4559 r = json_variant_append_arrayb(
4560 &array, JSON_BUILD_OBJECT(
4561 JSON_BUILD_PAIR_STRING("hashAlg", a),
4562 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(&values->digests[i].digest, EVP_MD_size(implementation)))));
4563 if (r < 0)
f9a0ee75 4564 return log_debug_errno(r, "Failed to append digest object to JSON array: %m");
cb19bdae
LP
4565 }
4566
4567 assert(array);
4568
4569 r = sd_id128_get_boot(&boot_id);
4570 if (r < 0)
f9a0ee75 4571 return log_debug_errno(r, "Failed to acquire boot ID: %m");
cb19bdae
LP
4572
4573 r = json_build(&v, JSON_BUILD_OBJECT(
4574 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(pcr_index)),
4575 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(array)),
4576 JSON_BUILD_PAIR("content_type", JSON_BUILD_STRING("systemd")),
4577 JSON_BUILD_PAIR("content", JSON_BUILD_OBJECT(
4578 JSON_BUILD_PAIR_CONDITION(description, "string", JSON_BUILD_STRING(description)),
4579 JSON_BUILD_PAIR("bootId", JSON_BUILD_ID128(boot_id)),
4580 JSON_BUILD_PAIR("timestamp", JSON_BUILD_UNSIGNED(now(CLOCK_BOOTTIME))),
4581 JSON_BUILD_PAIR_CONDITION(event_type >= 0, "eventType", JSON_BUILD_STRING(tpm2_userspace_event_type_to_string(event_type)))))));
4582 if (r < 0)
f9a0ee75 4583 return log_debug_errno(r, "Failed to build log record JSON: %m");
cb19bdae
LP
4584
4585 r = json_variant_format(v, JSON_FORMAT_SEQ, &f);
4586 if (r < 0)
f9a0ee75 4587 return log_debug_errno(r, "Failed to format JSON: %m");
cb19bdae 4588
86cbbc6d 4589 if (lseek(fd, 0, SEEK_END) < 0)
f9a0ee75 4590 return log_debug_errno(errno, "Failed to seek to end of JSON log: %m");
cb19bdae 4591
e22c60a9 4592 r = loop_write(fd, f, SIZE_MAX);
cb19bdae 4593 if (r < 0)
f9a0ee75 4594 return log_debug_errno(r, "Failed to write JSON data to log: %m");
cb19bdae
LP
4595
4596 if (fsync(fd) < 0)
f9a0ee75 4597 return log_debug_errno(errno, "Failed to sync JSON data: %m");
cb19bdae
LP
4598
4599 /* Unset S_ISVTX again */
4600 if (fchmod(fd, 0600) < 0)
f9a0ee75 4601 return log_debug_errno(errno, "Failed to chmod() TPM log file, ignoring: %m");
cb19bdae
LP
4602
4603 r = fsync_full(fd);
4604 if (r < 0)
f9a0ee75 4605 return log_debug_errno(r, "Failed to sync JSON log: %m");
cb19bdae
LP
4606
4607 return 1;
4608}
4609
15c591d1 4610int tpm2_extend_bytes(
23e9ccc2 4611 Tpm2Context *c,
15c591d1
LP
4612 char **banks,
4613 unsigned pcr_index,
4614 const void *data,
9885c874
LP
4615 size_t data_size,
4616 const void *secret,
cb19bdae
LP
4617 size_t secret_size,
4618 Tpm2UserspaceEventType event_type,
4619 const char *description) {
15c591d1
LP
4620
4621#if HAVE_OPENSSL
cb19bdae 4622 _cleanup_close_ int log_fd = -EBADF;
15c591d1
LP
4623 TPML_DIGEST_VALUES values = {};
4624 TSS2_RC rc;
4625
4626 assert(c);
9885c874
LP
4627 assert(data || data_size == 0);
4628 assert(secret || secret_size == 0);
4629
4630 if (data_size == SIZE_MAX)
4631 data_size = strlen(data);
4632 if (secret_size == SIZE_MAX)
4633 secret_size = strlen(secret);
15c591d1
LP
4634
4635 if (pcr_index >= TPM2_PCRS_MAX)
f9a0ee75 4636 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Can't measure into unsupported PCR %u, refusing.", pcr_index);
15c591d1
LP
4637
4638 if (strv_isempty(banks))
4639 return 0;
4640
4641 STRV_FOREACH(bank, banks) {
4642 const EVP_MD *implementation;
4643 int id;
4644
4645 assert_se(implementation = EVP_get_digestbyname(*bank));
4646
4647 if (values.count >= ELEMENTSOF(values.digests))
f9a0ee75 4648 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "Too many banks selected.");
15c591d1
LP
4649
4650 if ((size_t) EVP_MD_size(implementation) > sizeof(values.digests[values.count].digest))
f9a0ee75 4651 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "Hash result too large for TPM2.");
15c591d1 4652
7bfe0a48 4653 id = tpm2_hash_alg_from_string(EVP_MD_name(implementation));
15c591d1 4654 if (id < 0)
f9a0ee75 4655 return log_debug_errno(id, "Can't map hash name to TPM2.");
15c591d1
LP
4656
4657 values.digests[values.count].hashAlg = id;
4658
9885c874
LP
4659 /* So here's a twist: sometimes we want to measure secrets (e.g. root file system volume
4660 * key), but we'd rather not leak a literal hash of the secret to the TPM (given that the
4661 * wire is unprotected, and some other subsystem might use the simple, literal hash of the
4662 * secret for other purposes, maybe because it needs a shorter secret derived from it for
4663 * some unrelated purpose, who knows). Hence we instead measure an HMAC signature of a
4664 * private non-secret string instead. */
4665 if (secret_size > 0) {
4666 if (!HMAC(implementation, secret, secret_size, data, data_size, (unsigned char*) &values.digests[values.count].digest, NULL))
f9a0ee75 4667 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to calculate HMAC of data to measure.");
9885c874 4668 } else if (EVP_Digest(data, data_size, (unsigned char*) &values.digests[values.count].digest, NULL, implementation, NULL) != 1)
f9a0ee75 4669 return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash data to measure.");
15c591d1
LP
4670
4671 values.count++;
4672 }
4673
fcdd21ec 4674 /* Open + lock the log file *before* we start measuring, so that no one else can come between our log
cb19bdae
LP
4675 * and our measurement and change either */
4676 log_fd = tpm2_userspace_log_open();
4677
15c591d1 4678 rc = sym_Esys_PCR_Extend(
23e9ccc2 4679 c->esys_context,
15c591d1
LP
4680 ESYS_TR_PCR0 + pcr_index,
4681 ESYS_TR_PASSWORD,
4682 ESYS_TR_NONE,
4683 ESYS_TR_NONE,
4684 &values);
4685 if (rc != TSS2_RC_SUCCESS)
f9a0ee75 4686 return log_debug_errno(
15c591d1
LP
4687 SYNTHETIC_ERRNO(ENOTRECOVERABLE),
4688 "Failed to measure into PCR %u: %s",
4689 pcr_index,
4690 sym_Tss2_RC_Decode(rc));
4691
cb19bdae
LP
4692 /* Now, write what we just extended to the log, too. */
4693 (void) tpm2_userspace_log(log_fd, pcr_index, &values, event_type, description);
4694
15c591d1 4695 return 0;
0d7009d3 4696#else /* HAVE_OPENSSL */
f9a0ee75 4697 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
15c591d1
LP
4698#endif
4699}
4700#endif
4701
c69bd0ab
DS
4702char *tpm2_pcr_mask_to_string(uint32_t mask) {
4703 _cleanup_free_ char *s = NULL;
4704
4705 FOREACH_PCR_IN_MASK(n, mask)
4706 if (strextendf_with_separator(&s, "+", "%d", n) < 0)
4707 return NULL;
4708
4709 if (!s)
4710 return strdup("");
4711
4712 return TAKE_PTR(s);
4713}
4714
4436081e
LP
4715int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret) {
4716 _cleanup_(json_variant_unrefp) JsonVariant *a = NULL;
4436081e
LP
4717 int r;
4718
c22dcd67
YW
4719 assert(ret);
4720
4721 for (size_t i = 0; i < TPM2_PCRS_MAX; i++) {
4722 _cleanup_(json_variant_unrefp) JsonVariant *e = NULL;
4723
4436081e
LP
4724 if ((pcr_mask & (UINT32_C(1) << i)) == 0)
4725 continue;
4726
c22dcd67 4727 r = json_variant_new_integer(&e, i);
4436081e 4728 if (r < 0)
c22dcd67 4729 return r;
4436081e 4730
c22dcd67
YW
4731 r = json_variant_append_array(&a, e);
4732 if (r < 0)
4733 return r;
4436081e
LP
4734 }
4735
c22dcd67
YW
4736 if (!a)
4737 return json_variant_new_array(ret, NULL, 0);
4436081e 4738
c22dcd67
YW
4739 *ret = TAKE_PTR(a);
4740 return 0;
4436081e 4741}
8de8ec88
LP
4742
4743int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret) {
4744 JsonVariant *e;
4745 uint32_t mask = 0;
4746
4747 if (!json_variant_is_array(v))
4748 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR array is not a JSON array.");
4749
4750 JSON_VARIANT_ARRAY_FOREACH(e, v) {
4751 uint64_t u;
4752
4753 if (!json_variant_is_unsigned(e))
4754 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR is not an unsigned integer.");
4755
4756 u = json_variant_unsigned(e);
4757 if (u >= TPM2_PCRS_MAX)
4758 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR number out of range: %" PRIu64, u);
4759
4760 mask |= UINT32_C(1) << u;
4761 }
4762
4763 if (ret)
4764 *ret = mask;
4765
4766 return 0;
4767}
4436081e 4768
5e521624
LP
4769int tpm2_make_luks2_json(
4770 int keyslot,
f0f4fcae 4771 uint32_t hash_pcr_mask,
07697bfe 4772 uint16_t pcr_bank,
f0f4fcae
LP
4773 const void *pubkey,
4774 size_t pubkey_size,
4775 uint32_t pubkey_pcr_mask,
2b92a672 4776 uint16_t primary_alg,
5e521624
LP
4777 const void *blob,
4778 size_t blob_size,
4779 const void *policy_hash,
4780 size_t policy_hash_size,
aae6eb96
WR
4781 const void *salt,
4782 size_t salt_size,
acbb504e
WR
4783 const void *srk_buf,
4784 size_t srk_buf_size,
6c7a1681 4785 TPM2Flags flags,
5e521624
LP
4786 JsonVariant **ret) {
4787
f0f4fcae 4788 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *hmj = NULL, *pkmj = NULL;
5e521624 4789 _cleanup_free_ char *keyslot_as_string = NULL;
5e521624
LP
4790 int r;
4791
4792 assert(blob || blob_size == 0);
4793 assert(policy_hash || policy_hash_size == 0);
f0f4fcae 4794 assert(pubkey || pubkey_size == 0);
5e521624
LP
4795
4796 if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
4797 return -ENOMEM;
4798
f0f4fcae 4799 r = tpm2_make_pcr_json_array(hash_pcr_mask, &hmj);
5e521624 4800 if (r < 0)
4436081e 4801 return r;
5e521624 4802
f0f4fcae
LP
4803 if (pubkey_pcr_mask != 0) {
4804 r = tpm2_make_pcr_json_array(pubkey_pcr_mask, &pkmj);
4805 if (r < 0)
4806 return r;
4807 }
4808
4809 /* Note: We made the mistake of using "-" in the field names, which isn't particular compatible with
4810 * other programming languages. Let's not make things worse though, i.e. future additions to the JSON
4811 * object should use "_" rather than "-" in field names. */
4812
5e521624
LP
4813 r = json_build(&v,
4814 JSON_BUILD_OBJECT(
0cdf6b14 4815 JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-tpm2")),
5e521624
LP
4816 JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
4817 JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)),
f0f4fcae 4818 JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(hmj)),
7bfe0a48
DS
4819 JSON_BUILD_PAIR_CONDITION(!!tpm2_hash_alg_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_hash_alg_to_string(pcr_bank))),
4820 JSON_BUILD_PAIR_CONDITION(!!tpm2_asym_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_asym_alg_to_string(primary_alg))),
6c7a1681 4821 JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)),
f0f4fcae
LP
4822 JSON_BUILD_PAIR("tpm2-pin", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PIN)),
4823 JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey_pcrs", JSON_BUILD_VARIANT(pkmj)),
aae6eb96 4824 JSON_BUILD_PAIR_CONDITION(pubkey_pcr_mask != 0, "tpm2_pubkey", JSON_BUILD_BASE64(pubkey, pubkey_size)),
acbb504e
WR
4825 JSON_BUILD_PAIR_CONDITION(salt, "tpm2_salt", JSON_BUILD_BASE64(salt, salt_size)),
4826 JSON_BUILD_PAIR_CONDITION(srk_buf, "tpm2_srk", JSON_BUILD_BASE64(srk_buf, srk_buf_size))));
5e521624
LP
4827 if (r < 0)
4828 return r;
4829
4830 if (ret)
4831 *ret = TAKE_PTR(v);
4832
4833 return keyslot;
4834}
07697bfe 4835
fdf6c27c
LP
4836int tpm2_parse_luks2_json(
4837 JsonVariant *v,
4838 int *ret_keyslot,
4839 uint32_t *ret_hash_pcr_mask,
4840 uint16_t *ret_pcr_bank,
4841 void **ret_pubkey,
4842 size_t *ret_pubkey_size,
4843 uint32_t *ret_pubkey_pcr_mask,
4844 uint16_t *ret_primary_alg,
4845 void **ret_blob,
4846 size_t *ret_blob_size,
4847 void **ret_policy_hash,
4848 size_t *ret_policy_hash_size,
aae6eb96
WR
4849 void **ret_salt,
4850 size_t *ret_salt_size,
acbb504e
WR
4851 void **ret_srk_buf,
4852 size_t *ret_srk_buf_size,
fdf6c27c
LP
4853 TPM2Flags *ret_flags) {
4854
acbb504e
WR
4855 _cleanup_free_ void *blob = NULL, *policy_hash = NULL, *pubkey = NULL, *salt = NULL, *srk_buf = NULL;
4856 size_t blob_size = 0, policy_hash_size = 0, pubkey_size = 0, salt_size = 0, srk_buf_size = 0;
fdf6c27c
LP
4857 uint32_t hash_pcr_mask = 0, pubkey_pcr_mask = 0;
4858 uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */
4859 uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */
4860 int r, keyslot = -1;
4861 TPM2Flags flags = 0;
4862 JsonVariant *w;
4863
4864 assert(v);
4865
4866 if (ret_keyslot) {
4867 keyslot = cryptsetup_get_keyslot_from_token(v);
4868 if (keyslot < 0) {
4869 /* Return a recognizable error when parsing this field, so that callers can handle parsing
4870 * errors of the keyslots field gracefully, since it's not 'owned' by us, but by the LUKS2
4871 * spec */
4872 log_debug_errno(keyslot, "Failed to extract keyslot index from TPM2 JSON data token, skipping: %m");
4873 return -EUCLEAN;
4874 }
4875 }
4876
4877 w = json_variant_by_key(v, "tpm2-pcrs");
4878 if (!w)
4879 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-pcrs' field.");
4880
4881 r = tpm2_parse_pcr_json_array(w, &hash_pcr_mask);
4882 if (r < 0)
4883 return log_debug_errno(r, "Failed to parse TPM2 PCR mask: %m");
4884
4885 /* The bank field is optional, since it was added in systemd 250 only. Before the bank was hardcoded
4886 * to SHA256. */
4887 w = json_variant_by_key(v, "tpm2-pcr-bank");
4888 if (w) {
4889 /* The PCR bank field is optional */
4890
4891 if (!json_variant_is_string(w))
4892 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PCR bank is not a string.");
4893
7bfe0a48 4894 r = tpm2_hash_alg_from_string(json_variant_string(w));
fdf6c27c
LP
4895 if (r < 0)
4896 return log_debug_errno(r, "TPM2 PCR bank invalid or not supported: %s", json_variant_string(w));
4897
4898 pcr_bank = r;
4899 }
4900
4901 /* The primary key algorithm field is optional, since it was also added in systemd 250 only. Before
4902 * the algorithm was hardcoded to ECC. */
4903 w = json_variant_by_key(v, "tpm2-primary-alg");
4904 if (w) {
4905 /* The primary key algorithm is optional */
4906
4907 if (!json_variant_is_string(w))
4908 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 primary key algorithm is not a string.");
4909
7bfe0a48 4910 r = tpm2_asym_alg_from_string(json_variant_string(w));
fdf6c27c 4911 if (r < 0)
7bfe0a48 4912 return log_debug_errno(r, "TPM2 asymmetric algorithm invalid or not supported: %s", json_variant_string(w));
fdf6c27c
LP
4913
4914 primary_alg = r;
4915 }
4916
4917 w = json_variant_by_key(v, "tpm2-blob");
4918 if (!w)
4919 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-blob' field.");
4920
4921 r = json_variant_unbase64(w, &blob, &blob_size);
4922 if (r < 0)
4923 return log_debug_errno(r, "Invalid base64 data in 'tpm2-blob' field.");
4924
4925 w = json_variant_by_key(v, "tpm2-policy-hash");
4926 if (!w)
4927 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 token data lacks 'tpm2-policy-hash' field.");
4928
4929 r = json_variant_unhex(w, &policy_hash, &policy_hash_size);
4930 if (r < 0)
4931 return log_debug_errno(r, "Invalid base64 data in 'tpm2-policy-hash' field.");
4932
4933 w = json_variant_by_key(v, "tpm2-pin");
4934 if (w) {
4935 if (!json_variant_is_boolean(w))
4936 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 PIN policy is not a boolean.");
4937
4938 SET_FLAG(flags, TPM2_FLAGS_USE_PIN, json_variant_boolean(w));
4939 }
4940
aae6eb96
WR
4941 w = json_variant_by_key(v, "tpm2_salt");
4942 if (w) {
4943 r = json_variant_unbase64(w, &salt, &salt_size);
4944 if (r < 0)
4945 return log_debug_errno(r, "Invalid base64 data in 'tpm2_salt' field.");
4946 }
4947
fdf6c27c
LP
4948 w = json_variant_by_key(v, "tpm2_pubkey_pcrs");
4949 if (w) {
4950 r = tpm2_parse_pcr_json_array(w, &pubkey_pcr_mask);
4951 if (r < 0)
4952 return r;
4953 }
4954
4955 w = json_variant_by_key(v, "tpm2_pubkey");
4956 if (w) {
4957 r = json_variant_unbase64(w, &pubkey, &pubkey_size);
4958 if (r < 0)
4959 return log_debug_errno(r, "Failed to decode PCR public key.");
4960 } else if (pubkey_pcr_mask != 0)
4961 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Public key PCR mask set, but not public key included in JSON data, refusing.");
4962
acbb504e
WR
4963 w = json_variant_by_key(v, "tpm2_srk");
4964 if (w) {
4965 r = json_variant_unbase64(w, &srk_buf, &srk_buf_size);
4966 if (r < 0)
4967 return log_debug_errno(r, "Invalid base64 data in 'tpm2_srk' field.");
4968 }
4969
fdf6c27c
LP
4970 if (ret_keyslot)
4971 *ret_keyslot = keyslot;
4972 if (ret_hash_pcr_mask)
4973 *ret_hash_pcr_mask = hash_pcr_mask;
4974 if (ret_pcr_bank)
4975 *ret_pcr_bank = pcr_bank;
4976 if (ret_pubkey)
4977 *ret_pubkey = TAKE_PTR(pubkey);
4978 if (ret_pubkey_size)
4979 *ret_pubkey_size = pubkey_size;
4980 if (ret_pubkey_pcr_mask)
4981 *ret_pubkey_pcr_mask = pubkey_pcr_mask;
4982 if (ret_primary_alg)
4983 *ret_primary_alg = primary_alg;
4984 if (ret_blob)
4985 *ret_blob = TAKE_PTR(blob);
4986 if (ret_blob_size)
4987 *ret_blob_size = blob_size;
4988 if (ret_policy_hash)
4989 *ret_policy_hash = TAKE_PTR(policy_hash);
4990 if (ret_policy_hash_size)
4991 *ret_policy_hash_size = policy_hash_size;
aae6eb96
WR
4992 if (ret_salt)
4993 *ret_salt = TAKE_PTR(salt);
4994 if (ret_salt_size)
4995 *ret_salt_size = salt_size;
fdf6c27c
LP
4996 if (ret_flags)
4997 *ret_flags = flags;
acbb504e
WR
4998 if (ret_srk_buf)
4999 *ret_srk_buf = TAKE_PTR(srk_buf);
5000 if (ret_srk_buf_size)
5001 *ret_srk_buf_size = srk_buf_size;
fdf6c27c
LP
5002
5003 return 0;
5004}
5005
c9df1fb1 5006int tpm2_hash_alg_to_size(uint16_t alg) {
7354a7cc
DS
5007 switch (alg) {
5008 case TPM2_ALG_SHA1:
c9df1fb1 5009 return 20;
7354a7cc 5010 case TPM2_ALG_SHA256:
c9df1fb1 5011 return 32;
7354a7cc 5012 case TPM2_ALG_SHA384:
c9df1fb1 5013 return 48;
7354a7cc 5014 case TPM2_ALG_SHA512:
c9df1fb1 5015 return 64;
7354a7cc
DS
5016 default:
5017 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown hash algorithm id 0x%" PRIx16, alg);
5018 }
c9df1fb1
DS
5019}
5020
7bfe0a48 5021const char *tpm2_hash_alg_to_string(uint16_t alg) {
7354a7cc
DS
5022 switch (alg) {
5023 case TPM2_ALG_SHA1:
07697bfe 5024 return "sha1";
7354a7cc 5025 case TPM2_ALG_SHA256:
98193c39 5026 return "sha256";
7354a7cc 5027 case TPM2_ALG_SHA384:
98193c39 5028 return "sha384";
7354a7cc 5029 case TPM2_ALG_SHA512:
98193c39 5030 return "sha512";
7354a7cc
DS
5031 default:
5032 log_debug("Unknown hash algorithm id 0x%" PRIx16, alg);
5033 return NULL;
5034 }
07697bfe
LP
5035}
5036
7bfe0a48
DS
5037int tpm2_hash_alg_from_string(const char *alg) {
5038 if (strcaseeq_ptr(alg, "sha1"))
07697bfe 5039 return TPM2_ALG_SHA1;
7bfe0a48 5040 if (strcaseeq_ptr(alg, "sha256"))
98193c39 5041 return TPM2_ALG_SHA256;
7bfe0a48 5042 if (strcaseeq_ptr(alg, "sha384"))
98193c39 5043 return TPM2_ALG_SHA384;
7bfe0a48 5044 if (strcaseeq_ptr(alg, "sha512"))
98193c39 5045 return TPM2_ALG_SHA512;
240774f5 5046 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown hash algorithm name '%s'", alg);
07697bfe 5047}
2b92a672 5048
7bfe0a48 5049const char *tpm2_asym_alg_to_string(uint16_t alg) {
7354a7cc
DS
5050 switch (alg) {
5051 case TPM2_ALG_ECC:
2b92a672 5052 return "ecc";
7354a7cc 5053 case TPM2_ALG_RSA:
2b92a672 5054 return "rsa";
7354a7cc
DS
5055 default:
5056 log_debug("Unknown asymmetric algorithm id 0x%" PRIx16, alg);
5057 return NULL;
5058 }
2b92a672
LP
5059}
5060
7bfe0a48 5061int tpm2_asym_alg_from_string(const char *alg) {
f92ebc86 5062 if (strcaseeq_ptr(alg, "ecc"))
2b92a672 5063 return TPM2_ALG_ECC;
f92ebc86 5064 if (strcaseeq_ptr(alg, "rsa"))
2b92a672 5065 return TPM2_ALG_RSA;
240774f5 5066 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown asymmetric algorithm name '%s'", alg);
2b92a672 5067}
ba578556
LP
5068
5069Tpm2Support tpm2_support(void) {
5070 Tpm2Support support = TPM2_SUPPORT_NONE;
5071 int r;
5072
44d5dd65
LP
5073 if (detect_container() <= 0) {
5074 /* Check if there's a /dev/tpmrm* device via sysfs. If we run in a container we likely just
5075 * got the host sysfs mounted. Since devices are generally not virtualized for containers,
5076 * let's assume containers never have a TPM, at least for now. */
5077
db55bbf2 5078 r = dir_is_empty("/sys/class/tpmrm", /* ignore_hidden_or_backup= */ false);
44d5dd65
LP
5079 if (r < 0) {
5080 if (r != -ENOENT)
5081 log_debug_errno(r, "Unable to test whether /sys/class/tpmrm/ exists and is populated, assuming it is not: %m");
5082 } else if (r == 0) /* populated! */
300bba79
DDM
5083 support |= TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_DRIVER;
5084 else
5085 /* If the directory exists but is empty, we know the subsystem is enabled but no
5086 * driver has been loaded yet. */
5087 support |= TPM2_SUPPORT_SUBSYSTEM;
44d5dd65 5088 }
ba578556
LP
5089
5090 if (efi_has_tpm2())
5091 support |= TPM2_SUPPORT_FIRMWARE;
5092
5093#if HAVE_TPM2
5094 support |= TPM2_SUPPORT_SYSTEM;
33931049
DDM
5095
5096 r = dlopen_tpm2();
5097 if (r >= 0)
5098 support |= TPM2_SUPPORT_LIBRARIES;
ba578556
LP
5099#endif
5100
5101 return support;
5102}
222a951f 5103
07c04061
DS
5104#if HAVE_TPM2
5105static void tpm2_pcr_values_apply_default_hash_alg(Tpm2PCRValue *pcr_values, size_t n_pcr_values) {
5106 TPMI_ALG_HASH default_hash = 0;
193fd573
DS
5107 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
5108 if (v->hash != 0) {
5109 default_hash = v->hash;
07c04061
DS
5110 break;
5111 }
5112
5113 if (default_hash != 0)
193fd573
DS
5114 FOREACH_ARRAY(v, pcr_values, n_pcr_values)
5115 if (v->hash == 0)
5116 v->hash = default_hash;
07c04061
DS
5117}
5118#endif
5119
f9a0ee75
DS
5120/* The following tpm2_parse_pcr_argument*() functions all log errors, to match the behavior of system-wide
5121 * parse_*_argument() functions. */
5122
07c04061
DS
5123/* Parse the PCR selection/value arg(s) and return a corresponding array of Tpm2PCRValue objects.
5124 *
5125 * The format is the same as tpm2_pcr_values_from_string(). The first provided entry with a hash algorithm
5126 * set will be used as the 'default' hash algorithm. All entries with an unset hash algorithm will be updated
5127 * with the 'default' hash algorithm. The resulting array will be sorted and checked for validity.
5128 *
5129 * This will replace *ret_pcr_values with the new array of pcr values; to append to an existing array, use
5130 * tpm2_parse_pcr_argument_append(). */
5131int tpm2_parse_pcr_argument(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values) {
5132#if HAVE_TPM2
222a951f
LP
5133 int r;
5134
07c04061
DS
5135 assert(arg);
5136 assert(ret_pcr_values);
5137 assert(ret_n_pcr_values);
222a951f 5138
07c04061
DS
5139 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
5140 size_t n_pcr_values = 0;
5141 r = tpm2_pcr_values_from_string(arg, &pcr_values, &n_pcr_values);
5142 if (r < 0)
f9a0ee75 5143 return log_error_errno(r, "Could not parse PCR values from '%s': %m", arg);
07c04061
DS
5144
5145 tpm2_pcr_values_apply_default_hash_alg(pcr_values, n_pcr_values);
5146
5147 tpm2_sort_pcr_values(pcr_values, n_pcr_values);
5148
cc1a78d5 5149 if (!tpm2_pcr_values_valid(pcr_values, n_pcr_values))
07c04061
DS
5150 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parsed PCR values are not valid.");
5151
5152 *ret_pcr_values = TAKE_PTR(pcr_values);
5153 *ret_n_pcr_values = n_pcr_values;
222a951f 5154
07c04061
DS
5155 return 0;
5156#else
5157 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support is disabled.");
5158#endif
5159}
5160
5161/* Same as tpm2_parse_pcr_argument(), but the pcr values array is appended to. If the provided pcr values
5162 * array is not NULL, it must point to an allocated pcr values array and the provided number of pcr values
5163 * must be correct.
5164 *
5165 * Note that 'arg' is parsed into a new array of pcr values independently of any previous pcr values,
5166 * including application of the default hash algorithm. Then the two arrays are combined, the default hash
5167 * algorithm check applied again (in case either the previous or current array had no default hash
5168 * algorithm), and then the resulting array is sorted and rechecked for validity. */
ae2b38e4 5169int tpm2_parse_pcr_argument_append(const char *arg, Tpm2PCRValue **pcr_values, size_t *n_pcr_values) {
07c04061
DS
5170#if HAVE_TPM2
5171 int r;
5172
5173 assert(arg);
ae2b38e4
DS
5174 assert(pcr_values);
5175 assert(n_pcr_values);
07c04061 5176
ae2b38e4
DS
5177 _cleanup_free_ Tpm2PCRValue *more_pcr_values = NULL;
5178 size_t n_more_pcr_values;
5179 r = tpm2_parse_pcr_argument(arg, &more_pcr_values, &n_more_pcr_values);
07c04061
DS
5180 if (r < 0)
5181 return r;
5182
5183 /* If we got previous values, append them. */
ae2b38e4 5184 if (*pcr_values && !GREEDY_REALLOC_APPEND(more_pcr_values, n_more_pcr_values, *pcr_values, *n_pcr_values))
07c04061
DS
5185 return log_oom();
5186
ae2b38e4 5187 tpm2_pcr_values_apply_default_hash_alg(more_pcr_values, n_more_pcr_values);
07c04061 5188
ae2b38e4 5189 tpm2_sort_pcr_values(more_pcr_values, n_more_pcr_values);
07c04061 5190
ae2b38e4 5191 if (!tpm2_pcr_values_valid(more_pcr_values, n_more_pcr_values))
07c04061
DS
5192 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parsed PCR values are not valid.");
5193
ae2b38e4
DS
5194 SWAP_TWO(*pcr_values, more_pcr_values);
5195 *n_pcr_values = n_more_pcr_values;
07c04061
DS
5196
5197 return 0;
5198#else
5199 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support is disabled.");
5200#endif
5201}
5202
5203/* Same as tpm2_parse_pcr_argument() but converts the pcr values to a pcr mask. If more than one hash
5204 * algorithm is included in the pcr values array this results in error. This retains the previous behavior of
5205 * tpm2_parse_pcr_argument() of clearing the mask if 'arg' is empty, replacing the mask if it is set to
5206 * UINT32_MAX, and or-ing the mask otherwise. */
5207int tpm2_parse_pcr_argument_to_mask(const char *arg, uint32_t *ret_mask) {
5208#if HAVE_TPM2
5209 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
5210 size_t n_pcr_values;
5211 int r;
5212
5213 assert(arg);
5214 assert(ret_mask);
5215
5216 r = tpm2_parse_pcr_argument(arg, &pcr_values, &n_pcr_values);
5217 if (r < 0)
5218 return r;
5219
5220 if (n_pcr_values == 0) {
5221 /* This retains the previous behavior of clearing the mask if the arg is empty */
5222 *ret_mask = 0;
222a951f
LP
5223 return 0;
5224 }
5225
07c04061
DS
5226 size_t hash_count;
5227 r = tpm2_pcr_values_hash_count(pcr_values, n_pcr_values, &hash_count);
222a951f 5228 if (r < 0)
07c04061
DS
5229 return log_error_errno(r, "Could not get hash count from pcr values: %m");
5230
5231 if (hash_count > 1)
5232 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR hash banks selected.");
5233
5234 uint32_t new_mask;
5235 r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, pcr_values[0].hash, &new_mask);
5236 if (r < 0)
5237 return log_error_errno(r, "Could not get pcr values mask: %m");
222a951f 5238
07c04061
DS
5239 if (*ret_mask == UINT32_MAX)
5240 *ret_mask = new_mask;
222a951f 5241 else
07c04061 5242 *ret_mask |= new_mask;
222a951f
LP
5243
5244 return 0;
07c04061
DS
5245#else
5246 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support is disabled.");
5247#endif
222a951f 5248}
6a0779cb
LP
5249
5250int tpm2_load_pcr_signature(const char *path, JsonVariant **ret) {
6270b2e6 5251 _cleanup_strv_free_ char **search = NULL;
6a0779cb
LP
5252 _cleanup_free_ char *discovered_path = NULL;
5253 _cleanup_fclose_ FILE *f = NULL;
5254 int r;
5255
5256 /* Tries to load a JSON PCR signature file. Takes an absolute path, a simple file name or NULL. In
5257 * the latter two cases searches in /etc/, /usr/lib/, /run/, as usual. */
5258
6270b2e6
LP
5259 search = strv_split_nulstr(CONF_PATHS_NULSTR("systemd"));
5260 if (!search)
f9a0ee75 5261 return log_oom_debug();
6270b2e6
LP
5262
5263 if (!path) {
5264 /* If no path is specified, then look for "tpm2-pcr-signature.json" automatically. Also, in
5265 * this case include /.extra/ in the search path, but only in this case, and if we run in the
5266 * initrd. We don't want to be too eager here, after all /.extra/ is untrusted territory. */
5267
6a0779cb
LP
5268 path = "tpm2-pcr-signature.json";
5269
6270b2e6
LP
5270 if (in_initrd())
5271 if (strv_extend(&search, "/.extra") < 0)
f9a0ee75 5272 return log_oom_debug();
6270b2e6
LP
5273 }
5274
5275 r = search_and_fopen(path, "re", NULL, (const char**) search, &f, &discovered_path);
6a0779cb
LP
5276 if (r < 0)
5277 return log_debug_errno(r, "Failed to find TPM PCR signature file '%s': %m", path);
5278
5279 r = json_parse_file(f, discovered_path, 0, ret, NULL, NULL);
5280 if (r < 0)
5281 return log_debug_errno(r, "Failed to parse TPM PCR signature JSON object '%s': %m", discovered_path);
5282
5283 return 0;
5284}
5285
5286int tpm2_load_pcr_public_key(const char *path, void **ret_pubkey, size_t *ret_pubkey_size) {
5287 _cleanup_free_ char *discovered_path = NULL;
5288 _cleanup_fclose_ FILE *f = NULL;
5289 int r;
5290
5291 /* Tries to load a PCR public key file. Takes an absolute path, a simple file name or NULL. In the
5292 * latter two cases searches in /etc/, /usr/lib/, /run/, as usual. */
5293
5294 if (!path)
5295 path = "tpm2-pcr-public-key.pem";
5296
5297 r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("systemd"), &f, &discovered_path);
5298 if (r < 0)
5299 return log_debug_errno(r, "Failed to find TPM PCR public key file '%s': %m", path);
5300
5301 r = read_full_stream(f, (char**) ret_pubkey, ret_pubkey_size);
5302 if (r < 0)
5303 return log_debug_errno(r, "Failed to load TPM PCR public key PEM file '%s': %m", discovered_path);
5304
5305 return 0;
5306}
4d5cc0d4 5307
aae6eb96
WR
5308#define PBKDF2_HMAC_SHA256_ITERATIONS 10000
5309
5310/*
5311 * Implements PBKDF2 HMAC SHA256 for a derived keylen of 32
5312 * bytes and for PBKDF2_HMAC_SHA256_ITERATIONS count.
5313 * I found the wikipedia entry relevant and it contains links to
5314 * relevant RFCs:
5315 * - https://en.wikipedia.org/wiki/PBKDF2
5316 * - https://www.rfc-editor.org/rfc/rfc2898#section-5.2
5317 */
5318int tpm2_util_pbkdf2_hmac_sha256(const void *pass,
5319 size_t passlen,
5320 const void *salt,
5321 size_t saltlen,
5322 uint8_t ret_key[static SHA256_DIGEST_SIZE]) {
5323
5324 uint8_t _cleanup_(erase_and_freep) *buffer = NULL;
5325 uint8_t u[SHA256_DIGEST_SIZE];
5326
5327 /* To keep this simple, since derived KeyLen (dkLen in docs)
5328 * Is the same as the hash output, we don't need multiple
5329 * blocks. Part of the algorithm is to add the block count
5330 * in, but this can be hardcoded to 1.
5331 */
5332 static const uint8_t block_cnt[] = { 0, 0, 0, 1 };
5333
504d0acf 5334 assert (salt);
aae6eb96
WR
5335 assert (saltlen > 0);
5336 assert (saltlen <= (SIZE_MAX - sizeof(block_cnt)));
5337 assert (passlen > 0);
5338
5339 /*
5340 * Build a buffer of salt + block_cnt and hmac_sha256 it we
5341 * do this as we don't have a context builder for HMAC_SHA256.
5342 */
5343 buffer = malloc(saltlen + sizeof(block_cnt));
5344 if (!buffer)
5345 return -ENOMEM;
5346
5347 memcpy(buffer, salt, saltlen);
5348 memcpy(&buffer[saltlen], block_cnt, sizeof(block_cnt));
5349
5350 hmac_sha256(pass, passlen, buffer, saltlen + sizeof(block_cnt), u);
5351
5352 /* dk needs to be an unmodified u as u gets modified in the loop */
5353 memcpy(ret_key, u, SHA256_DIGEST_SIZE);
5354 uint8_t *dk = ret_key;
5355
5356 for (size_t i = 1; i < PBKDF2_HMAC_SHA256_ITERATIONS; i++) {
5357 hmac_sha256(pass, passlen, u, sizeof(u), u);
5358
5359 for (size_t j=0; j < sizeof(u); j++)
5360 dk[j] ^= u[j];
5361 }
5362
5363 return 0;
5364}
96ead603 5365
2099cd62
LP
5366static const char* const tpm2_pcr_index_table[_TPM2_PCR_INDEX_MAX_DEFINED] = {
5367 [TPM2_PCR_PLATFORM_CODE] = "platform-code",
5368 [TPM2_PCR_PLATFORM_CONFIG] = "platform-config",
5369 [TPM2_PCR_EXTERNAL_CODE] = "external-code",
5370 [TPM2_PCR_EXTERNAL_CONFIG] = "external-config",
5371 [TPM2_PCR_BOOT_LOADER_CODE] = "boot-loader-code",
5372 [TPM2_PCR_BOOT_LOADER_CONFIG] = "boot-loader-config",
5373 [TPM2_PCR_HOST_PLATFORM] = "host-platform",
5374 [TPM2_PCR_SECURE_BOOT_POLICY] = "secure-boot-policy",
5375 [TPM2_PCR_KERNEL_INITRD] = "kernel-initrd",
5376 [TPM2_PCR_IMA] = "ima",
5377 [TPM2_PCR_KERNEL_BOOT] = "kernel-boot",
5378 [TPM2_PCR_KERNEL_CONFIG] = "kernel-config",
5379 [TPM2_PCR_SYSEXTS] = "sysexts",
5380 [TPM2_PCR_SHIM_POLICY] = "shim-policy",
5381 [TPM2_PCR_SYSTEM_IDENTITY] = "system-identity",
5382 [TPM2_PCR_DEBUG] = "debug",
5383 [TPM2_PCR_APPLICATION_SUPPORT] = "application-support",
96ead603
OJ
5384};
5385
2099cd62
LP
5386DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_FALLBACK(tpm2_pcr_index, int, TPM2_PCRS_MAX - 1);
5387DEFINE_STRING_TABLE_LOOKUP_TO_STRING(tpm2_pcr_index, int);