1 /* Software-based Trusted Platform Module (TPM) Emulator
2  * Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net>
3  *
4  * This module is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  *
9  * This module is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * $Id: tpm_transport.c 367 2010-02-13 15:52:18Z mast $
15  */
16 
17 /*
18  * Thanks go to Edison Su (<sudison@gmail.com>) for providing
19  * the initial Transport Session patch.
20  */
21 
22 #include "tpm_emulator.h"
23 #include "tpm_commands.h"
24 #include "tpm_handles.h"
25 #include "tpm_marshalling.h"
26 #include "tpm_data.h"
27 #include "crypto/rsa.h"
28 #include "crypto/sha1.h"
29 
30 /*
31  * Transport Sessions ([TPM_Part3], Section 24)
32  */
33 
debug_buf(const char * str,uint8_t * buf,size_t buf_len)34 static void debug_buf(const char *str, uint8_t *buf, size_t buf_len)
35 {
36   static char map[] = "0123456789abcdef";
37   char hex[buf_len * 3];
38   size_t i;
39   for (i = 0; i < buf_len; i++) {
40     hex[i*3 + 0] = map[buf[i] >> 4];
41     hex[i*3 + 1] = map[buf[i] & 0x0f];
42     hex[i*3 + 2] = ' ';
43   }
44   hex[sizeof(hex) - 1] = 0;
45   debug("%s%s", str, hex);
46 }
47 
decrypt_transport_auth(TPM_KEY_DATA * key,BYTE * enc,UINT32 enc_size,TPM_TRANSPORT_AUTH * trans_auth)48 static int decrypt_transport_auth(TPM_KEY_DATA *key, BYTE *enc, UINT32 enc_size,
49                                   TPM_TRANSPORT_AUTH *trans_auth)
50 {
51   BYTE *buf;
52   size_t buf_size;
53   int scheme;
54   switch (key->encScheme) {
55     case TPM_ES_RSAESOAEP_SHA1_MGF1: scheme = RSA_ES_OAEP_SHA1; break;
56     case TPM_ES_RSAESPKCSv15: scheme = RSA_ES_PKCSV15; break;
57     default: return -1;
58   }
59   buf = tpm_malloc(key->key.size);
60   if (buf == NULL
61       || tpm_rsa_decrypt(&key->key, scheme, enc, enc_size, buf, &buf_size)
62       || buf_size != sizeof_TPM_TRANSPORT_AUTH(x)
63       || (((UINT16)buf[0] << 8) | buf[1]) != TPM_TAG_TRANSPORT_AUTH) {
64     tpm_free(buf);
65     return -1;
66   }
67   trans_auth->tag = TPM_TAG_TRANSPORT_AUTH;
68   memcpy(trans_auth->authData, &buf[2], sizeof(TPM_AUTHDATA));
69   tpm_free(buf);
70   return 0;
71 }
72 
transport_log_in(BYTE * params,BYTE * pubKeyHash,TPM_DIGEST * transDigest)73 static void transport_log_in(BYTE *params, BYTE *pubKeyHash,
74                              TPM_DIGEST *transDigest)
75 {
76   BYTE *ptr, buf[sizeof_TPM_TRANSPORT_LOG_IN(x)];
77   UINT32 len;
78   tpm_sha1_ctx_t sha1;
79 
80   ptr = buf; len = sizeof(buf);
81   tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_TRANSPORT_LOG_IN);
82   tpm_marshal_BLOB(&ptr, &len, params, SHA1_DIGEST_LENGTH);
83   tpm_marshal_BLOB(&ptr, &len, pubKeyHash, SHA1_DIGEST_LENGTH);
84   tpm_sha1_init(&sha1);
85   tpm_sha1_update(&sha1, transDigest->digest, sizeof(transDigest->digest));
86   tpm_sha1_update(&sha1, buf, sizeof(buf));
87   tpm_sha1_final(&sha1, transDigest->digest);
88   debug_buf("LogIn: transDigest: ", transDigest->digest, sizeof(transDigest->digest));
89 }
90 
transport_log_out(BYTE * params,TPM_DIGEST * transDigest)91 static void transport_log_out(BYTE *params, TPM_DIGEST *transDigest)
92 {
93   BYTE *ptr, buf[sizeof_TPM_TRANSPORT_LOG_OUT(x)];
94   UINT32 len;
95   tpm_sha1_ctx_t sha1;
96 
97   ptr = buf; len = sizeof(buf);
98   tpm_marshal_TPM_TAG(&ptr, &len, TPM_TAG_TRANSPORT_LOG_OUT);
99   tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, &tpmData.stany.data.currentTicks);
100   tpm_marshal_BLOB(&ptr, &len, params, SHA1_DIGEST_LENGTH);
101   tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, tpmData.stany.flags.localityModifier);
102   tpm_sha1_init(&sha1);
103   tpm_sha1_update(&sha1, transDigest->digest, sizeof(transDigest->digest));
104   tpm_sha1_update(&sha1, buf, sizeof(buf));
105   tpm_sha1_final(&sha1, transDigest->digest);
106   debug_buf("LogOut: transDigest: ", transDigest->digest, sizeof(transDigest->digest));
107 }
108 
TPM_EstablishTransport(TPM_KEY_HANDLE encHandle,TPM_TRANSPORT_PUBLIC * transPublic,UINT32 secretSize,BYTE * secret,TPM_AUTH * auth1,TPM_TRANSHANDLE * transHandle,TPM_MODIFIER_INDICATOR * locality,TPM_CURRENT_TICKS * currentTicks,TPM_NONCE * transNonceEven)109 TPM_RESULT TPM_EstablishTransport(TPM_KEY_HANDLE encHandle,
110                                   TPM_TRANSPORT_PUBLIC *transPublic,
111                                   UINT32 secretSize, BYTE *secret,
112                                   TPM_AUTH *auth1,
113                                   TPM_TRANSHANDLE *transHandle,
114                                   TPM_MODIFIER_INDICATOR *locality,
115                                   TPM_CURRENT_TICKS *currentTicks,
116                                   TPM_NONCE *transNonceEven)
117 {
118   TPM_RESULT res;
119   TPM_KEY_DATA *key;
120   TPM_TRANSPORT_AUTH trans_auth;
121   TPM_SESSION_DATA *session;
122 
123   info("TPM_EstablishTransport()");
124   /* setup authorization data */
125   if (encHandle == TPM_KH_TRANSPORT) {
126     if (auth1->authHandle != TPM_INVALID_HANDLE) return TPM_BADTAG;
127     if (transPublic->transAttributes & TPM_TRANSPORT_ENCRYPT) return TPM_BAD_SCHEME;
128     if (secretSize != 20) return TPM_BAD_PARAM_SIZE;
129     memcpy(trans_auth.authData, secret, 20);
130   } else {
131     /* get key and verify its usage */
132     key = tpm_get_key(encHandle);
133     if (key == NULL) return TPM_INVALID_KEYHANDLE;
134     if (key->keyUsage != TPM_KEY_STORAGE && key->keyUsage != TPM_KEY_LEGACY)
135         return TPM_INVALID_KEYUSAGE;
136     /* verify authorization */
137     if (key->authDataUsage != TPM_AUTH_NEVER) {
138       res = tpm_verify_auth(auth1, key->usageAuth, encHandle);
139       if (res != TPM_SUCCESS) return res;
140       if (decrypt_transport_auth(key, secret, secretSize, &trans_auth))
141         return TPM_DECRYPT_ERROR;
142     }
143   }
144   /* check whether the transport has to be encrypted */
145   if (transPublic->transAttributes & TPM_TRANSPORT_ENCRYPT) {
146     if (tpmData.permanent.flags.FIPS
147         && transPublic->algID == TPM_ALG_MGF1) return TPM_INAPPROPRIATE_ENC;
148     /* until now, only MGF1 is supported */
149     if (transPublic->algID != TPM_ALG_MGF1) return TPM_BAD_KEY_PROPERTY;
150   }
151   /* initialize transport session */
152   tpm_get_random_bytes(transNonceEven->nonce, sizeof(transNonceEven->nonce));
153   *transHandle = tpm_get_free_session(TPM_ST_TRANSPORT);
154   session = tpm_get_transport(*transHandle);
155   if (session == NULL) return TPM_RESOURCES;
156   session->transInternal.transHandle = *transHandle;
157   memset(&session->transInternal.transDigest, 0, sizeof(TPM_DIGEST));
158   memcpy(&session->transInternal.transPublic, transPublic,
159     sizeof_TPM_TRANSPORT_PUBLIC((*transPublic)));
160   memcpy(&session->transInternal.transNonceEven, transNonceEven, sizeof(TPM_NONCE));
161   memcpy(&session->nonceEven, transNonceEven, sizeof(TPM_NONCE));
162   memcpy(&session->transInternal.authData, trans_auth.authData, sizeof(TPM_AUTHDATA));
163   *locality = tpmData.stany.flags.localityModifier;
164   memcpy(currentTicks, &tpmData.stany.data.currentTicks, sizeof(TPM_CURRENT_TICKS));
165   /* perform transport logging */
166   if (transPublic->transAttributes & TPM_TRANSPORT_LOG) {
167     tpm_sha1_ctx_t sha1;
168     BYTE *ptr, buf[4 + 4 + 4 + sizeof_TPM_CURRENT_TICKS(x) + 20];
169     UINT32 len;
170     /* log input */
171     memset(buf, 0, sizeof(buf));
172     transport_log_in(auth1->digest, buf, &session->transInternal.transDigest);
173     /* compute digest of output parameters and log output */
174     ptr = buf; len = sizeof(buf);
175     tpm_marshal_UINT32(&ptr, &len, TPM_SUCCESS);
176     tpm_marshal_TPM_COMMAND_CODE(&ptr, &len, TPM_ORD_EstablishTransport);
177     tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, *locality);
178     tpm_marshal_TPM_CURRENT_TICKS(&ptr, &len, currentTicks);
179     tpm_marshal_TPM_NONCE(&ptr, &len, transNonceEven);
180     tpm_sha1_init(&sha1);
181     tpm_sha1_update(&sha1, buf, sizeof(buf));
182     tpm_sha1_final(&sha1, buf);
183     transport_log_out(buf, &session->transInternal.transDigest);
184   }
185   /* check whether this is a exclusive transport session */
186   if (transPublic->transAttributes & TPM_TRANSPORT_EXCLUSIVE) {
187     tpmData.stany.flags.transportExclusive = TRUE;
188     tpmData.stany.data.transExclusive = *transHandle;
189   }
190   auth1->continueAuthSession = FALSE;
191   return TPM_SUCCESS;
192 }
193 
194 extern UINT32 tpm_get_in_param_offset(TPM_COMMAND_CODE ordinal);
195 extern UINT32 tpm_get_out_param_offset(TPM_COMMAND_CODE ordinal);
196 extern void tpm_compute_in_param_digest(TPM_REQUEST *req);
197 extern void tpm_execute_command(TPM_REQUEST *req, TPM_RESPONSE *rsp);
198 extern void tpm_compute_out_param_digest(TPM_COMMAND_CODE ordinal, TPM_RESPONSE *rsp);
199 
decrypt_wrapped_command(BYTE * buf,UINT32 buf_len,TPM_AUTH * auth,TPM_SESSION_DATA * session)200 static void decrypt_wrapped_command(BYTE *buf, UINT32 buf_len, TPM_AUTH *auth,
201                                     TPM_SESSION_DATA *session)
202 
203 {
204   UINT32 i, j;
205   BYTE mask[SHA1_DIGEST_LENGTH];
206   tpm_sha1_ctx_t sha1;
207   for (i = 0; buf_len > 0; i++) {
208     tpm_sha1_init(&sha1);
209     tpm_sha1_update(&sha1, session->nonceEven.nonce, sizeof(session->nonceEven.nonce));
210     tpm_sha1_update(&sha1, auth->nonceOdd.nonce, sizeof(auth->nonceOdd.nonce));
211     tpm_sha1_update(&sha1, (uint8_t*)"in", 2);
212     tpm_sha1_update(&sha1, session->transInternal.authData, sizeof(TPM_SECRET));
213     tpm_sha1_update_be32(&sha1, i);
214     tpm_sha1_final(&sha1, mask);
215     for (j = 0; j < sizeof(mask) && buf_len > 0; j++) {
216       *buf++ ^= mask[j];
217       buf_len--;
218     }
219   }
220 }
221 
encrypt_wrapped_command(BYTE * buf,UINT32 buf_len,TPM_AUTH * auth,TPM_SESSION_DATA * session)222 static void encrypt_wrapped_command(BYTE *buf, UINT32 buf_len, TPM_AUTH *auth,
223                                     TPM_SESSION_DATA *session)
224 {
225   UINT32 i, j;
226   BYTE mask[SHA1_DIGEST_LENGTH];
227   tpm_sha1_ctx_t sha1;
228   for (i = 0; buf_len > 0; i++) {
229     tpm_sha1_init(&sha1);
230     tpm_sha1_update(&sha1, session->nonceEven.nonce, sizeof(session->nonceEven.nonce));
231     tpm_sha1_update(&sha1, auth->nonceOdd.nonce, sizeof(auth->nonceOdd.nonce));
232     tpm_sha1_update(&sha1, (uint8_t*)"out", 3);
233     tpm_sha1_update(&sha1, session->transInternal.authData, sizeof(TPM_SECRET));
234     tpm_sha1_update_be32(&sha1, i);
235     tpm_sha1_final(&sha1, mask);
236     for (j = 0; j < sizeof(mask) && buf_len > 0; j++) {
237       *buf++ ^= mask[j];
238       buf_len--;
239     }
240   }
241 }
242 
compute_key_digest(TPM_REQUEST * req,TPM_DIGEST * digest)243 static void compute_key_digest(TPM_REQUEST *req, TPM_DIGEST *digest)
244 {
245   tpm_sha1_ctx_t ctx;
246   TPM_HANDLE h1, h2;
247   TPM_KEY_DATA *k1, *k2;
248   BYTE *ptr;
249   UINT32 len, offset = tpm_get_in_param_offset(req->ordinal);
250   /* handle some exceptions */
251   if (req->ordinal == TPM_ORD_FlushSpecific) offset = 0;
252   else if (req->ordinal == TPM_ORD_OwnerReadInternalPub) offset = 4;
253   /* compute public key digests */
254   if (offset == 0) {
255     debug("no handles");
256     memset(digest, 0, sizeof(TPM_DIGEST));
257   } else if (offset == 4) {
258     debug("one handle");
259     ptr = req->param; len = 4;
260     tpm_unmarshal_TPM_HANDLE(&ptr, &len, &h1);
261     k1 = tpm_get_key(h1);
262     if (k1 != NULL && tpm_compute_key_data_digest(k1, digest) == 0) {
263       debug("key found");
264       /* compute outer hash */
265       tpm_sha1_init(&ctx);
266       tpm_sha1_update(&ctx, digest->digest, sizeof(digest->digest));
267       tpm_sha1_final(&ctx, digest->digest);
268     } else {
269       memset(digest, 0, sizeof(TPM_DIGEST));
270     }
271   } else if (offset == 8) {
272     TPM_DIGEST digest2;
273     debug("two handles");
274     ptr = req->param; len = 8;
275     tpm_unmarshal_TPM_HANDLE(&ptr, &len, &h1);
276     tpm_unmarshal_TPM_HANDLE(&ptr, &len, &h2);
277     k1 = tpm_get_key(h1);
278     k2 = tpm_get_key(h2);
279     if (k1 != NULL && tpm_compute_key_data_digest(k1, digest) == 0
280         && k2 != NULL && tpm_compute_key_data_digest(k2, &digest2) == 0) {
281       debug("two keys found");
282       /* compute outer hash */
283       tpm_sha1_init(&ctx);
284       tpm_sha1_update(&ctx, digest->digest, sizeof(digest->digest));
285       tpm_sha1_update(&ctx, digest2.digest, sizeof(digest2.digest));
286       tpm_sha1_final(&ctx, digest->digest);
287     } else {
288       memset(digest, 0, sizeof(TPM_DIGEST));
289     }
290   } else {
291     memset(digest, 0, sizeof(TPM_DIGEST));
292   }
293 }
294 
TPM_ExecuteTransport(UINT32 inWrappedCmdSize,BYTE * inWrappedCmd,TPM_AUTH * auth1,UINT64 * currentTicks,TPM_MODIFIER_INDICATOR * locality,UINT32 * outWrappedCmdSize,BYTE ** outWrappedCmd)295 TPM_RESULT TPM_ExecuteTransport(UINT32 inWrappedCmdSize, BYTE *inWrappedCmd,
296                                 TPM_AUTH *auth1, UINT64 *currentTicks,
297                                 TPM_MODIFIER_INDICATOR *locality,
298                                 UINT32 *outWrappedCmdSize, BYTE **outWrappedCmd)
299 {
300   TPM_RESULT res;
301   TPM_SESSION_DATA *session;
302   TPM_REQUEST req;
303   TPM_RESPONSE rsp;
304   BYTE *ptr, buf[4 * 4 + 8 + 20];
305   UINT32 len, offset;
306   tpm_sha1_ctx_t sha1;
307   info("TPM_ExecuteTransport()");
308   /* get transport session */
309   session = tpm_get_transport(auth1->authHandle);
310   if (session == NULL) return TPM_BAD_PARAMETER;
311   /* unmarshal wrapped command */
312   len = inWrappedCmdSize;
313   ptr = inWrappedCmd;
314   if (tpm_unmarshal_TPM_REQUEST(&ptr, &len, &req)) return TPM_FAIL;
315   /* decrypt wrapped command if needed */
316   ptr = tpm_malloc(req.paramSize);
317   if (ptr == NULL) return TPM_FAIL;
318   memcpy(ptr, req.param, req.paramSize);
319   if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) {
320     if (req.ordinal == TPM_ORD_OIAP || req.ordinal == TPM_ORD_OSAP) {
321       offset = req.paramSize;
322     } else if (req.ordinal == TPM_ORD_DSAP) {
323       offset = 30;
324     } else {
325       offset = tpm_get_in_param_offset(req.ordinal);
326     }
327     debug("decrypting %d bytes, starting at pos %d", req.paramSize - offset, offset);
328     decrypt_wrapped_command(ptr + offset, req.paramSize - offset, auth1, session);
329   }
330   req.param = ptr;
331   /* verify authorization */
332   tpm_compute_in_param_digest(&req);
333   tpm_sha1_init(&sha1);
334   tpm_sha1_update_be32(&sha1, TPM_ORD_ExecuteTransport);
335   tpm_sha1_update_be32(&sha1, inWrappedCmdSize);
336   tpm_sha1_update(&sha1, req.auth1.digest, sizeof(req.auth1.digest));
337   tpm_sha1_final(&sha1, auth1->digest);
338   res = tpm_verify_auth(auth1, session->transInternal.authData, TPM_INVALID_HANDLE);
339   if (res != TPM_SUCCESS) {
340     tpm_free(req.param);
341     return res;
342   }
343   /* nested transport sessions are not allowed */
344   if (req.ordinal == TPM_ORD_EstablishTransport
345       || req.ordinal == TPM_ORD_ExecuteTransport
346       || req.ordinal == TPM_ORD_ReleaseTransportSigned) {
347     tpm_free(req.param);
348     return TPM_NO_WRAP_TRANSPORT;
349   }
350   /* log input parameters */
351   if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_LOG) {
352     TPM_DIGEST keyDigest;
353     compute_key_digest(&req, &keyDigest);
354     transport_log_in(req.auth1.digest, keyDigest.digest,
355                      &session->transInternal.transDigest);
356   }
357   /* execute and audit command*/
358   tpm_audit_request(req.ordinal, &req);
359   tpm_execute_command(&req, &rsp);
360   tpm_audit_response(req.ordinal, &rsp);
361   tpm_free(req.param);
362   /* get locality and ticks */
363   *locality = tpmData.stany.flags.localityModifier;
364   *currentTicks = tpmData.stany.data.currentTicks.currentTicks;
365   /* if required, compute digest of internal output parameters */
366   debug("result = %d", rsp.result);
367   if (rsp.result == TPM_SUCCESS) {
368     if (rsp.tag == TPM_TAG_RSP_COMMAND) {
369       rsp.auth1 = &req.auth1;
370       tpm_compute_out_param_digest(req.ordinal, &rsp);
371     }
372     /* encrypt parameters */
373     if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) {
374       if (req.ordinal == TPM_ORD_OIAP || req.ordinal == TPM_ORD_OSAP) {
375         offset = rsp.paramSize;
376       } else if (req.ordinal == TPM_ORD_DSAP) {
377         offset = rsp.paramSize;
378       } else {
379         offset = tpm_get_out_param_offset(req.ordinal);
380       }
381       debug("encrypting %d bytes, starting at pos %d", rsp.paramSize - offset, offset);
382       encrypt_wrapped_command(rsp.param + offset, rsp.paramSize - offset, auth1, session);
383     }
384   } else {
385     rsp.auth1 = &req.auth1;
386     memset(rsp.auth1->digest, 0, sizeof(*rsp.auth1->digest));
387   }
388   /* marshal response */
389   *outWrappedCmdSize = len = rsp.size;
390   *outWrappedCmd = ptr = tpm_malloc(len);
391   if (ptr == NULL) {
392     tpm_free(rsp.param);
393     return TPM_FAIL;
394   }
395   tpm_marshal_TPM_RESPONSE(&ptr, &len, &rsp);
396   debug("marshalling done.");
397   /* log output parameters */
398   if (session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_LOG) {
399     transport_log_out(rsp.auth1->digest, &session->transInternal.transDigest);
400   }
401   tpm_free(rsp.param);
402   /* compute digest of output parameters */
403   ptr = buf; len = sizeof(buf);
404   tpm_marshal_UINT32(&ptr, &len, TPM_SUCCESS);
405   tpm_marshal_TPM_COMMAND_CODE(&ptr, &len, TPM_ORD_ExecuteTransport);
406   tpm_marshal_UINT64(&ptr, &len, *currentTicks);
407   tpm_marshal_TPM_MODIFIER_INDICATOR(&ptr, &len, *locality);
408   tpm_marshal_UINT32(&ptr, &len, *outWrappedCmdSize);
409   memcpy(ptr, rsp.auth1->digest, sizeof(rsp.auth1->digest));
410   tpm_sha1_init(&sha1);
411   tpm_sha1_update(&sha1, buf, sizeof(buf));
412   tpm_sha1_final(&sha1, auth1->digest);
413   return TPM_SUCCESS;
414 }
415 
TPM_ReleaseTransportSigned(TPM_KEY_HANDLE keyHandle,TPM_NONCE * antiReplay,TPM_AUTH * auth1,TPM_AUTH * auth2,TPM_MODIFIER_INDICATOR * locality,TPM_CURRENT_TICKS * currentTicks,UINT32 * sigSize,BYTE ** sig)416 TPM_RESULT TPM_ReleaseTransportSigned(TPM_KEY_HANDLE keyHandle,
417                                       TPM_NONCE *antiReplay,
418                                       TPM_AUTH *auth1, TPM_AUTH *auth2,
419                                       TPM_MODIFIER_INDICATOR *locality,
420                                       TPM_CURRENT_TICKS *currentTicks,
421                                       UINT32 *sigSize, BYTE **sig)
422 {
423   TPM_RESULT res;
424   TPM_KEY_DATA *key;
425   TPM_SESSION_DATA *session;
426   BYTE buf[30 + 20];
427   info("TPM_ReleaseTransportSigned()");
428   /* get key */
429   key = tpm_get_key(keyHandle);
430   if (key == NULL) return TPM_INVALID_KEYHANDLE;
431   /* verify authorization */
432   if (auth2->authHandle != TPM_INVALID_HANDLE
433       || key->authDataUsage != TPM_AUTH_NEVER) {
434     res = tpm_verify_auth(auth1, key->usageAuth, keyHandle);
435     if (res != TPM_SUCCESS) return res;
436     session = tpm_get_transport(auth2->authHandle);
437     if (session == NULL) return TPM_INVALID_AUTHHANDLE;
438     res = tpm_verify_auth(auth2, session->transInternal.authData, TPM_INVALID_HANDLE);
439     if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res;
440   } else {
441     session = tpm_get_transport(auth1->authHandle);
442     if (session == NULL) return TPM_INVALID_AUTHHANDLE;
443     res = tpm_verify_auth(auth1, session->transInternal.authData, TPM_INVALID_HANDLE);
444     if (res != TPM_SUCCESS) return res;
445   }
446   /* invalidate transport session */
447   auth1->continueAuthSession = FALSE;
448   /* logging must be enabled */
449   if (!(session->transInternal.transPublic.transAttributes & TPM_TRANSPORT_LOG))
450     return TPM_BAD_MODE;
451   *locality = tpmData.stany.flags.localityModifier;
452   memcpy(currentTicks, &tpmData.stany.data.currentTicks, sizeof(TPM_CURRENT_TICKS));
453   transport_log_out(auth1->digest, &session->transInternal.transDigest);
454   /* setup a TPM_SIGN_INFO structure */
455   memcpy(&buf[0], (uint8_t*)"\x00\x05TRAN", 6);
456   memcpy(&buf[6], antiReplay->nonce, 20);
457   memcpy(&buf[26], (uint8_t*)"\x00\x00\x00\x14", 4);
458   memcpy(&buf[30], session->transInternal.transDigest.digest, 20);
459   /* sign info structure */
460   if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) {
461     tpm_sha1_ctx_t ctx;
462     debug("TPM_SS_RSASSAPKCS1v15_SHA1");
463     tpm_sha1_init(&ctx);
464     tpm_sha1_update(&ctx, buf, sizeof(buf));
465     tpm_sha1_final(&ctx, buf);
466     res = tpm_sign(key, auth1, FALSE, buf, SHA1_DIGEST_LENGTH, sig, sigSize);
467   } else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) {
468     debug("TPM_SS_RSASSAPKCS1v15_INFO");
469     res = tpm_sign(key, auth1, TRUE, buf, sizeof(buf), sig, sigSize);
470   } else {
471     debug("unsupported signature scheme: %02x", key->sigScheme);
472     res = TPM_INVALID_KEYUSAGE;
473   }
474   return res;
475 }
476