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