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