1 /* ibm-tss.h - Supporting TPM routines for the IBM TSS
2 * Copyright (C) 2021 James Bottomley <James.Bottomley@HansenPartnership.com>
3 *
4 * This file is part of GnuPG.
5 *
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21 #ifndef _TPM2_IBM_TSS_H
22 #define _TPM2_IBM_TSS_H
23
24 #define TSSINCLUDE(x) < TSS_INCLUDE/x >
25 #include TSSINCLUDE(tss.h)
26 #include TSSINCLUDE(tssutils.h)
27 #include TSSINCLUDE(tssresponsecode.h)
28 #include TSSINCLUDE(tssmarshal.h)
29 #include TSSINCLUDE(Unmarshal_fp.h)
30 #include TSSINCLUDE(tsscryptoh.h)
31
32 #define EXT_TPM_RH_OWNER TPM_RH_OWNER
33
34 #define VAL(X) X.val
35 #define VAL_2B(X, MEMBER) X.t.MEMBER
36
37 static const char *tpm2_dir;
38
39 /* The TPM builds a small database of active files representing key
40 * parameters used for authentication and session encryption. Make sure
41 * they're contained in a separate directory to avoid stepping on any
42 * other application uses of the TPM */
43 static inline const char *
tpm2_set_unique_tssdir(void)44 tpm2_set_unique_tssdir (void)
45 {
46 char *prefix = getenv ("XDG_RUNTIME_DIR"), *template,
47 *dir;
48 int len = 0;
49
50 if (!prefix)
51 prefix = "/tmp";
52
53 len = snprintf (NULL, 0, "%s/tss2.XXXXXX", prefix);
54 if (len <= 0)
55 return NULL;
56 template = xtrymalloc (len + 1);
57 if (!template)
58 return NULL;
59
60 len++;
61 len = snprintf (template, len, "%s/tss2.XXXXXX", prefix);
62
63 dir = mkdtemp (template);
64
65 return dir;
66 }
67
68 static inline void
tpm2_error(TPM_RC rc,const char * prefix)69 tpm2_error (TPM_RC rc, const char *prefix)
70 {
71 const char *msg, *submsg, *num;
72
73 TSS_ResponseCode_toString (&msg, &submsg, &num, rc);
74 log_error ("%s gave TPM2 Error: %s%s%s", prefix, msg, submsg, num);
75 }
76
77 static inline int
TSS_start(TSS_CONTEXT ** tssc)78 TSS_start (TSS_CONTEXT **tssc)
79 {
80 TPM_RC rc;
81
82 tpm2_dir = tpm2_set_unique_tssdir ();
83 if (!tpm2_dir)
84 /* make this non fatal */
85 log_error ("Failed to set unique TPM directory\n");
86
87 rc = TSS_Create (tssc);
88 if (rc)
89 {
90 tpm2_error (rc, "TSS_Create");
91 return GPG_ERR_CARD;
92 }
93 rc = TSS_SetProperty (*tssc, TPM_DATA_DIR, tpm2_dir);
94 if (rc)
95 /* make this non fatal */
96 tpm2_error (rc, "TSS_SetProperty");
97
98 return 0;
99 }
100
101 static inline TPM_RC
tpm2_CreatePrimary(TSS_CONTEXT * tssContext,TPM_HANDLE primaryHandle,TPM2B_SENSITIVE_CREATE * inSensitive,TPM2B_PUBLIC * inPublic,TPM_HANDLE * objectHandle)102 tpm2_CreatePrimary (TSS_CONTEXT *tssContext, TPM_HANDLE primaryHandle,
103 TPM2B_SENSITIVE_CREATE *inSensitive,
104 TPM2B_PUBLIC *inPublic, TPM_HANDLE *objectHandle)
105 {
106 CreatePrimary_In in;
107 CreatePrimary_Out out;
108 TPM_RC rc;
109
110 in.primaryHandle = primaryHandle;
111 in.inSensitive = *inSensitive;
112 in.inPublic = *inPublic;
113 /* no outside info */
114 in.outsideInfo.t.size = 0;
115 /* no PCR state */
116 in.creationPCR.count = 0;
117
118 rc = TSS_Execute (tssContext,
119 (RESPONSE_PARAMETERS *)&out,
120 (COMMAND_PARAMETERS *)&in,
121 NULL,
122 TPM_CC_CreatePrimary,
123 TPM_RS_PW, NULL, 0,
124 TPM_RH_NULL, NULL, 0);
125
126 *objectHandle = out.objectHandle;
127
128 return rc;
129 }
130
131 static inline TPM_RC
tpm2_FlushContext(TSS_CONTEXT * tssContext,TPM_HANDLE flushHandle)132 tpm2_FlushContext (TSS_CONTEXT *tssContext, TPM_HANDLE flushHandle)
133 {
134 FlushContext_In in;
135 TPM_RC rc;
136
137 in.flushHandle = flushHandle;
138
139 rc = TSS_Execute (tssContext,
140 NULL,
141 (COMMAND_PARAMETERS *)&in,
142 NULL,
143 TPM_CC_FlushContext,
144 TPM_RH_NULL, NULL, 0);
145
146 return rc;
147 }
148
149 static inline TPM_RC
tpm2_ReadPublic(TSS_CONTEXT * tssContext,TPM_HANDLE objectHandle,TPMT_PUBLIC * pub,TPM_HANDLE auth)150 tpm2_ReadPublic (TSS_CONTEXT *tssContext, TPM_HANDLE objectHandle,
151 TPMT_PUBLIC *pub, TPM_HANDLE auth)
152 {
153 ReadPublic_In rin;
154 ReadPublic_Out rout;
155 TPM_RC rc;
156 UINT32 flags = 0;
157
158 if (auth != TPM_RH_NULL)
159 flags = TPMA_SESSION_ENCRYPT;
160
161 rin.objectHandle = objectHandle;
162
163 rc = TSS_Execute (tssContext,
164 (RESPONSE_PARAMETERS *)&rout,
165 (COMMAND_PARAMETERS *)&rin,
166 NULL,
167 TPM_CC_ReadPublic,
168 auth, NULL, flags,
169 TPM_RH_NULL, NULL, 0);
170
171 if (rc)
172 {
173 tpm2_error (rc, "TPM2_ReadPublic");
174 return rc;
175 }
176
177 if (pub)
178 *pub = rout.outPublic.publicArea;
179
180 return rc;
181 }
182
183 static inline TPM_RC
tpm2_StartAuthSession(TSS_CONTEXT * tssContext,TPM_HANDLE tpmKey,TPM_HANDLE bind,TPM_SE sessionType,TPMT_SYM_DEF * symmetric,TPMI_ALG_HASH authHash,TPM_HANDLE * sessionHandle,const char * bindPassword)184 tpm2_StartAuthSession (TSS_CONTEXT *tssContext, TPM_HANDLE tpmKey,
185 TPM_HANDLE bind, TPM_SE sessionType,
186 TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash,
187 TPM_HANDLE *sessionHandle,
188 const char *bindPassword)
189 {
190 StartAuthSession_In in;
191 StartAuthSession_Out out;
192 StartAuthSession_Extra extra;
193 TPM_RC rc;
194
195 memset (&in, 0, sizeof(in));
196 memset (&extra, 0 , sizeof(extra));
197
198 extra.bindPassword = bindPassword;
199
200 in.tpmKey = tpmKey;
201 in.bind = bind;
202 in.sessionType = sessionType;
203 in.symmetric = *symmetric;
204 in.authHash = authHash;
205
206 if (tpmKey != TPM_RH_NULL)
207 {
208 /*
209 * For the TSS to use a key as salt, it must have
210 * access to the public part. It does this by keeping
211 * key files, but request the public part just to make
212 * sure
213 */
214 tpm2_ReadPublic (tssContext, tpmKey, NULL, TPM_RH_NULL);
215 /*
216 * don't care what rout returns, the purpose of the
217 * operation was to get the public key parameters into
218 * the tss so it can construct the salt
219 */
220 }
221
222 rc = TSS_Execute (tssContext,
223 (RESPONSE_PARAMETERS *)&out,
224 (COMMAND_PARAMETERS *)&in,
225 (EXTRA_PARAMETERS *)&extra,
226 TPM_CC_StartAuthSession,
227 TPM_RH_NULL, NULL, 0);
228
229 *sessionHandle = out.sessionHandle;
230
231 return rc;
232 }
233
234 static inline TPM_RC
tpm2_Sign(TSS_CONTEXT * tssContext,TPM_HANDLE keyHandle,DIGEST_2B * digest,TPMT_SIG_SCHEME * inScheme,TPMT_SIGNATURE * signature,TPM_HANDLE auth,const char * authVal)235 tpm2_Sign (TSS_CONTEXT *tssContext, TPM_HANDLE keyHandle, DIGEST_2B *digest,
236 TPMT_SIG_SCHEME *inScheme, TPMT_SIGNATURE *signature,
237 TPM_HANDLE auth, const char *authVal)
238 {
239 Sign_In in;
240 Sign_Out out;
241 TPM_RC rc;
242
243 in.keyHandle = keyHandle;
244 in.digest.t = *digest;
245 in.inScheme = *inScheme;
246 in.validation.tag = TPM_ST_HASHCHECK;
247 in.validation.hierarchy = TPM_RH_NULL;
248 in.validation.digest.t.size = 0;
249
250 rc = TSS_Execute (tssContext,
251 (RESPONSE_PARAMETERS *)&out,
252 (COMMAND_PARAMETERS *)&in,
253 NULL,
254 TPM_CC_Sign,
255 auth, authVal, 0,
256 TPM_RH_NULL, NULL, 0);
257
258 *signature = out.signature;
259
260 return rc;
261 }
262
263 static inline TPM_RC
tpm2_ECDH_ZGen(TSS_CONTEXT * tssContext,TPM_HANDLE keyHandle,TPM2B_ECC_POINT * inPoint,TPM2B_ECC_POINT * outPoint,TPM_HANDLE auth,const char * authVal)264 tpm2_ECDH_ZGen (TSS_CONTEXT *tssContext, TPM_HANDLE keyHandle,
265 TPM2B_ECC_POINT *inPoint, TPM2B_ECC_POINT *outPoint,
266 TPM_HANDLE auth, const char *authVal)
267 {
268 ECDH_ZGen_In in;
269 ECDH_ZGen_Out out;
270 TPM_RC rc;
271
272 in.keyHandle = keyHandle;
273 in.inPoint = *inPoint;
274
275 rc = TSS_Execute (tssContext,
276 (RESPONSE_PARAMETERS *)&out,
277 (COMMAND_PARAMETERS *)&in,
278 NULL,
279 TPM_CC_ECDH_ZGen,
280 auth, authVal, TPMA_SESSION_ENCRYPT,
281 TPM_RH_NULL, NULL, 0);
282
283 *outPoint = out.outPoint;
284
285 return rc;
286 }
287
288 static inline TPM_RC
tpm2_RSA_Decrypt(TSS_CONTEXT * tssContext,TPM_HANDLE keyHandle,PUBLIC_KEY_RSA_2B * cipherText,TPMT_RSA_DECRYPT * inScheme,PUBLIC_KEY_RSA_2B * message,TPM_HANDLE auth,const char * authVal,int flags)289 tpm2_RSA_Decrypt (TSS_CONTEXT *tssContext, TPM_HANDLE keyHandle,
290 PUBLIC_KEY_RSA_2B *cipherText, TPMT_RSA_DECRYPT *inScheme,
291 PUBLIC_KEY_RSA_2B *message,
292 TPM_HANDLE auth, const char *authVal, int flags)
293 {
294 RSA_Decrypt_In in;
295 RSA_Decrypt_Out out;
296 TPM_RC rc;
297
298 in.keyHandle = keyHandle;
299 in.inScheme = *inScheme;
300 in.cipherText.t = *cipherText;
301 in.label.t.size = 0;
302
303 rc = TSS_Execute (tssContext,
304 (RESPONSE_PARAMETERS *)&out,
305 (COMMAND_PARAMETERS *)&in,
306 NULL,
307 TPM_CC_RSA_Decrypt,
308 auth, authVal, flags,
309 TPM_RH_NULL, NULL, 0);
310
311 *message = out.message.t;
312
313 return rc;
314 }
315
316 static inline TPM_RC
tpm2_Load(TSS_CONTEXT * tssContext,TPM_HANDLE parentHandle,PRIVATE_2B * inPrivate,TPM2B_PUBLIC * inPublic,TPM_HANDLE * objectHandle,TPM_HANDLE auth,const char * authVal)317 tpm2_Load (TSS_CONTEXT *tssContext, TPM_HANDLE parentHandle,
318 PRIVATE_2B *inPrivate, TPM2B_PUBLIC *inPublic,
319 TPM_HANDLE *objectHandle,
320 TPM_HANDLE auth, const char *authVal)
321 {
322 Load_In in;
323 Load_Out out;
324 TPM_RC rc;
325
326 in.parentHandle = parentHandle;
327 in.inPrivate.t = *inPrivate;
328 in.inPublic = *inPublic;
329
330 rc = TSS_Execute (tssContext,
331 (RESPONSE_PARAMETERS *)&out,
332 (COMMAND_PARAMETERS *)&in,
333 NULL,
334 TPM_CC_Load,
335 auth, authVal, 0,
336 TPM_RH_NULL, NULL, 0);
337
338 if (rc == TPM_RC_SUCCESS)
339 *objectHandle = out.objectHandle;
340
341 return rc;
342 }
343
344 static inline TPM_RC
tpm2_Import(TSS_CONTEXT * tssContext,TPM_HANDLE parentHandle,DATA_2B * encryptionKey,TPM2B_PUBLIC * objectPublic,PRIVATE_2B * duplicate,ENCRYPTED_SECRET_2B * inSymSeed,TPMT_SYM_DEF_OBJECT * symmetricAlg,PRIVATE_2B * outPrivate,TPM_HANDLE auth,const char * authVal)345 tpm2_Import (TSS_CONTEXT *tssContext, TPM_HANDLE parentHandle,
346 DATA_2B *encryptionKey, TPM2B_PUBLIC *objectPublic,
347 PRIVATE_2B *duplicate, ENCRYPTED_SECRET_2B *inSymSeed,
348 TPMT_SYM_DEF_OBJECT *symmetricAlg, PRIVATE_2B *outPrivate,
349 TPM_HANDLE auth, const char *authVal)
350 {
351 Import_In iin;
352 Import_Out iout;
353 TPM_RC rc;
354
355 iin.parentHandle = parentHandle;
356 iin.encryptionKey.t = *encryptionKey;
357 iin.objectPublic = *objectPublic;
358 iin.duplicate.t = *duplicate;
359 iin.inSymSeed.t = *inSymSeed;
360 iin.symmetricAlg = *symmetricAlg;
361
362 rc = TSS_Execute (tssContext,
363 (RESPONSE_PARAMETERS *)&iout,
364 (COMMAND_PARAMETERS *)&iin,
365 NULL,
366 TPM_CC_Import,
367 auth, authVal, TPMA_SESSION_DECRYPT,
368 TPM_RH_NULL, NULL, 0);
369
370 *outPrivate = iout.outPrivate.t;
371
372 return rc;
373 }
374
375 static inline TPM_HANDLE
tpm2_handle_int(TSS_CONTEXT * tssContext,TPM_HANDLE h)376 tpm2_handle_int (TSS_CONTEXT *tssContext, TPM_HANDLE h)
377 {
378 (void)tssContext;
379 return h;
380 }
381
382 static inline TPM_HANDLE
tpm2_handle_ext(TSS_CONTEXT * tssContext,TPM_HANDLE h)383 tpm2_handle_ext (TSS_CONTEXT *tssContext, TPM_HANDLE h)
384 {
385 (void)tssContext;
386 return h;
387 }
388
389 static inline int
tpm2_handle_mso(TSS_CONTEXT * tssContext,TPM_HANDLE h,UINT32 mso)390 tpm2_handle_mso (TSS_CONTEXT *tssContext, TPM_HANDLE h, UINT32 mso)
391 {
392 (void)tssContext;
393 return (h >> 24) == mso;
394 }
395
396 #endif
397