]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - lib/tpm.c
dm: tpm: Convert I2C driver to driver model
[karo-tx-uboot.git] / lib / tpm.c
1 /*
2  * Copyright (c) 2013 The Chromium OS Authors.
3  * Coypright (c) 2013 Guntermann & Drunck GmbH
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <tis.h>
11 #include <tpm.h>
12 #include <asm/unaligned.h>
13 #include <u-boot/sha1.h>
14
15 /* Internal error of TPM command library */
16 #define TPM_LIB_ERROR   ((uint32_t)~0u)
17
18 /* Useful constants */
19 enum {
20         COMMAND_BUFFER_SIZE             = 256,
21         TPM_PUBEK_SIZE                  = 256,
22         TPM_REQUEST_HEADER_LENGTH       = 10,
23         TPM_RESPONSE_HEADER_LENGTH      = 10,
24         PCR_DIGEST_LENGTH               = 20,
25         DIGEST_LENGTH                   = 20,
26         TPM_REQUEST_AUTH_LENGTH         = 45,
27         TPM_RESPONSE_AUTH_LENGTH        = 41,
28         /* some max lengths, valid for RSA keys <= 2048 bits */
29         TPM_KEY12_MAX_LENGTH            = 618,
30         TPM_PUBKEY_MAX_LENGTH           = 288,
31 };
32
33 #ifdef CONFIG_TPM_AUTH_SESSIONS
34
35 #ifndef CONFIG_SHA1
36 #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
37 #endif /* !CONFIG_SHA1 */
38
39 struct session_data {
40         int             valid;
41         uint32_t        handle;
42         uint8_t         nonce_even[DIGEST_LENGTH];
43         uint8_t         nonce_odd[DIGEST_LENGTH];
44 };
45
46 static struct session_data oiap_session = {0, };
47
48 #endif /* CONFIG_TPM_AUTH_SESSIONS */
49
50 /**
51  * Pack data into a byte string.  The data types are specified in
52  * the format string: 'b' means unsigned byte, 'w' unsigned word,
53  * 'd' unsigned double word, and 's' byte string.  The data are a
54  * series of offsets and values (for type byte string there are also
55  * lengths).  The data values are packed into the byte string
56  * sequentially, and so a latter value could over-write a former
57  * value.
58  *
59  * @param str           output string
60  * @param size          size of output string
61  * @param format        format string
62  * @param ...           data points
63  * @return 0 on success, non-0 on error
64  */
65 int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
66 {
67         va_list args;
68         size_t offset = 0, length = 0;
69         uint8_t *data = NULL;
70         uint32_t value = 0;
71
72         va_start(args, format);
73         for (; *format; format++) {
74                 switch (*format) {
75                 case 'b':
76                         offset = va_arg(args, size_t);
77                         value = va_arg(args, int);
78                         length = 1;
79                         break;
80                 case 'w':
81                         offset = va_arg(args, size_t);
82                         value = va_arg(args, int);
83                         length = 2;
84                         break;
85                 case 'd':
86                         offset = va_arg(args, size_t);
87                         value = va_arg(args, uint32_t);
88                         length = 4;
89                         break;
90                 case 's':
91                         offset = va_arg(args, size_t);
92                         data = va_arg(args, uint8_t *);
93                         length = va_arg(args, uint32_t);
94                         break;
95                 default:
96                         debug("Couldn't recognize format string\n");
97                         return -1;
98                 }
99
100                 if (offset + length > size)
101                         return -1;
102
103                 switch (*format) {
104                 case 'b':
105                         str[offset] = value;
106                         break;
107                 case 'w':
108                         put_unaligned_be16(value, str + offset);
109                         break;
110                 case 'd':
111                         put_unaligned_be32(value, str + offset);
112                         break;
113                 case 's':
114                         memcpy(str + offset, data, length);
115                         break;
116                 }
117         }
118         va_end(args);
119
120         return 0;
121 }
122
123 /**
124  * Unpack data from a byte string.  The data types are specified in
125  * the format string: 'b' means unsigned byte, 'w' unsigned word,
126  * 'd' unsigned double word, and 's' byte string.  The data are a
127  * series of offsets and pointers (for type byte string there are also
128  * lengths).
129  *
130  * @param str           output string
131  * @param size          size of output string
132  * @param format        format string
133  * @param ...           data points
134  * @return 0 on success, non-0 on error
135  */
136 int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
137 {
138         va_list args;
139         size_t offset = 0, length = 0;
140         uint8_t *ptr8 = NULL;
141         uint16_t *ptr16 = NULL;
142         uint32_t *ptr32 = NULL;
143
144         va_start(args, format);
145         for (; *format; format++) {
146                 switch (*format) {
147                 case 'b':
148                         offset = va_arg(args, size_t);
149                         ptr8 = va_arg(args, uint8_t *);
150                         length = 1;
151                         break;
152                 case 'w':
153                         offset = va_arg(args, size_t);
154                         ptr16 = va_arg(args, uint16_t *);
155                         length = 2;
156                         break;
157                 case 'd':
158                         offset = va_arg(args, size_t);
159                         ptr32 = va_arg(args, uint32_t *);
160                         length = 4;
161                         break;
162                 case 's':
163                         offset = va_arg(args, size_t);
164                         ptr8 = va_arg(args, uint8_t *);
165                         length = va_arg(args, uint32_t);
166                         break;
167                 default:
168                         debug("Couldn't recognize format string\n");
169                         return -1;
170                 }
171
172                 if (offset + length > size)
173                         return -1;
174
175                 switch (*format) {
176                 case 'b':
177                         *ptr8 = str[offset];
178                         break;
179                 case 'w':
180                         *ptr16 = get_unaligned_be16(str + offset);
181                         break;
182                 case 'd':
183                         *ptr32 = get_unaligned_be32(str + offset);
184                         break;
185                 case 's':
186                         memcpy(ptr8, str + offset, length);
187                         break;
188                 }
189         }
190         va_end(args);
191
192         return 0;
193 }
194
195 /**
196  * Get TPM command size.
197  *
198  * @param command       byte string of TPM command
199  * @return command size of the TPM command
200  */
201 static uint32_t tpm_command_size(const void *command)
202 {
203         const size_t command_size_offset = 2;
204         return get_unaligned_be32(command + command_size_offset);
205 }
206
207 /**
208  * Get TPM response return code, which is one of TPM_RESULT values.
209  *
210  * @param response      byte string of TPM response
211  * @return return code of the TPM response
212  */
213 static uint32_t tpm_return_code(const void *response)
214 {
215         const size_t return_code_offset = 6;
216         return get_unaligned_be32(response + return_code_offset);
217 }
218
219 /**
220  * Send a TPM command and return response's return code, and optionally
221  * return response to caller.
222  *
223  * @param command       byte string of TPM command
224  * @param response      output buffer for TPM response, or NULL if the
225  *                      caller does not care about it
226  * @param size_ptr      output buffer size (input parameter) and TPM
227  *                      response length (output parameter); this parameter
228  *                      is a bidirectional
229  * @return return code of the TPM response
230  */
231 static uint32_t tpm_sendrecv_command(const void *command,
232                 void *response, size_t *size_ptr)
233 {
234         uint8_t response_buffer[COMMAND_BUFFER_SIZE];
235         size_t response_length;
236         uint32_t err;
237
238         if (response) {
239                 response_length = *size_ptr;
240         } else {
241                 response = response_buffer;
242                 response_length = sizeof(response_buffer);
243         }
244 #ifdef CONFIG_DM_TPM
245         struct udevice *dev;
246         int ret;
247
248         ret = uclass_first_device(UCLASS_TPM, &dev);
249         if (ret)
250                 return ret;
251         err = tpm_xfer(dev, command, tpm_command_size(command),
252                        response, &response_length);
253 #else
254         err = tis_sendrecv(command, tpm_command_size(command),
255                         response, &response_length);
256 #endif
257         if (err < 0)
258                 return TPM_LIB_ERROR;
259         if (size_ptr)
260                 *size_ptr = response_length;
261
262         return tpm_return_code(response);
263 }
264
265 int tpm_init(void)
266 {
267         int err;
268
269 #ifdef CONFIG_DM_TPM
270         struct udevice *dev;
271
272         err = uclass_first_device(UCLASS_TPM, &dev);
273         if (err)
274                 return err;
275         return tpm_open(dev);
276 #else
277         err = tis_init();
278         if (err)
279                 return err;
280
281         return tis_open();
282 #endif
283 }
284
285 uint32_t tpm_startup(enum tpm_startup_type mode)
286 {
287         const uint8_t command[12] = {
288                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
289         };
290         const size_t mode_offset = 10;
291         uint8_t buf[COMMAND_BUFFER_SIZE];
292
293         if (pack_byte_string(buf, sizeof(buf), "sw",
294                                 0, command, sizeof(command),
295                                 mode_offset, mode))
296                 return TPM_LIB_ERROR;
297
298         return tpm_sendrecv_command(buf, NULL, NULL);
299 }
300
301 uint32_t tpm_self_test_full(void)
302 {
303         const uint8_t command[10] = {
304                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
305         };
306         return tpm_sendrecv_command(command, NULL, NULL);
307 }
308
309 uint32_t tpm_continue_self_test(void)
310 {
311         const uint8_t command[10] = {
312                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
313         };
314         return tpm_sendrecv_command(command, NULL, NULL);
315 }
316
317 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
318 {
319         const uint8_t command[101] = {
320                 0x0, 0xc1,              /* TPM_TAG */
321                 0x0, 0x0, 0x0, 0x65,    /* parameter size */
322                 0x0, 0x0, 0x0, 0xcc,    /* TPM_COMMAND_CODE */
323                 /* TPM_NV_DATA_PUBLIC->... */
324                 0x0, 0x18,              /* ...->TPM_STRUCTURE_TAG */
325                 0, 0, 0, 0,             /* ...->TPM_NV_INDEX */
326                 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
327                 0x0, 0x3,
328                 0, 0, 0,
329                 0x1f,
330                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
331                 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
332                 0x0, 0x3,
333                 0, 0, 0,
334                 0x1f,
335                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
336                 /* TPM_NV_ATTRIBUTES->... */
337                 0x0, 0x17,              /* ...->TPM_STRUCTURE_TAG */
338                 0, 0, 0, 0,             /* ...->attributes */
339                 /* End of TPM_NV_ATTRIBUTES */
340                 0,                      /* bReadSTClear */
341                 0,                      /* bWriteSTClear */
342                 0,                      /* bWriteDefine */
343                 0, 0, 0, 0,             /* size */
344         };
345         const size_t index_offset = 12;
346         const size_t perm_offset = 70;
347         const size_t size_offset = 77;
348         uint8_t buf[COMMAND_BUFFER_SIZE];
349
350         if (pack_byte_string(buf, sizeof(buf), "sddd",
351                                 0, command, sizeof(command),
352                                 index_offset, index,
353                                 perm_offset, perm,
354                                 size_offset, size))
355                 return TPM_LIB_ERROR;
356
357         return tpm_sendrecv_command(buf, NULL, NULL);
358 }
359
360 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
361 {
362         const uint8_t command[22] = {
363                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
364         };
365         const size_t index_offset = 10;
366         const size_t length_offset = 18;
367         const size_t data_size_offset = 10;
368         const size_t data_offset = 14;
369         uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
370         size_t response_length = sizeof(response);
371         uint32_t data_size;
372         uint32_t err;
373
374         if (pack_byte_string(buf, sizeof(buf), "sdd",
375                                 0, command, sizeof(command),
376                                 index_offset, index,
377                                 length_offset, count))
378                 return TPM_LIB_ERROR;
379         err = tpm_sendrecv_command(buf, response, &response_length);
380         if (err)
381                 return err;
382         if (unpack_byte_string(response, response_length, "d",
383                                 data_size_offset, &data_size))
384                 return TPM_LIB_ERROR;
385         if (data_size > count)
386                 return TPM_LIB_ERROR;
387         if (unpack_byte_string(response, response_length, "s",
388                                 data_offset, data, data_size))
389                 return TPM_LIB_ERROR;
390
391         return 0;
392 }
393
394 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
395 {
396         const uint8_t command[256] = {
397                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
398         };
399         const size_t command_size_offset = 2;
400         const size_t index_offset = 10;
401         const size_t length_offset = 18;
402         const size_t data_offset = 22;
403         const size_t write_info_size = 12;
404         const uint32_t total_length =
405                 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
406         uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
407         size_t response_length = sizeof(response);
408         uint32_t err;
409
410         if (pack_byte_string(buf, sizeof(buf), "sddds",
411                                 0, command, sizeof(command),
412                                 command_size_offset, total_length,
413                                 index_offset, index,
414                                 length_offset, length,
415                                 data_offset, data, length))
416                 return TPM_LIB_ERROR;
417         err = tpm_sendrecv_command(buf, response, &response_length);
418         if (err)
419                 return err;
420
421         return 0;
422 }
423
424 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
425 {
426         const uint8_t command[34] = {
427                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
428         };
429         const size_t index_offset = 10;
430         const size_t in_digest_offset = 14;
431         const size_t out_digest_offset = 10;
432         uint8_t buf[COMMAND_BUFFER_SIZE];
433         uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
434         size_t response_length = sizeof(response);
435         uint32_t err;
436
437         if (pack_byte_string(buf, sizeof(buf), "sds",
438                                 0, command, sizeof(command),
439                                 index_offset, index,
440                                 in_digest_offset, in_digest,
441                                 PCR_DIGEST_LENGTH))
442                 return TPM_LIB_ERROR;
443         err = tpm_sendrecv_command(buf, response, &response_length);
444         if (err)
445                 return err;
446
447         if (unpack_byte_string(response, response_length, "s",
448                                 out_digest_offset, out_digest,
449                                 PCR_DIGEST_LENGTH))
450                 return TPM_LIB_ERROR;
451
452         return 0;
453 }
454
455 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
456 {
457         const uint8_t command[14] = {
458                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
459         };
460         const size_t index_offset = 10;
461         const size_t out_digest_offset = 10;
462         uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
463         size_t response_length = sizeof(response);
464         uint32_t err;
465
466         if (count < PCR_DIGEST_LENGTH)
467                 return TPM_LIB_ERROR;
468
469         if (pack_byte_string(buf, sizeof(buf), "sd",
470                                 0, command, sizeof(command),
471                                 index_offset, index))
472                 return TPM_LIB_ERROR;
473         err = tpm_sendrecv_command(buf, response, &response_length);
474         if (err)
475                 return err;
476         if (unpack_byte_string(response, response_length, "s",
477                                 out_digest_offset, data, PCR_DIGEST_LENGTH))
478                 return TPM_LIB_ERROR;
479
480         return 0;
481 }
482
483 uint32_t tpm_tsc_physical_presence(uint16_t presence)
484 {
485         const uint8_t command[12] = {
486                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
487         };
488         const size_t presence_offset = 10;
489         uint8_t buf[COMMAND_BUFFER_SIZE];
490
491         if (pack_byte_string(buf, sizeof(buf), "sw",
492                                 0, command, sizeof(command),
493                                 presence_offset, presence))
494                 return TPM_LIB_ERROR;
495
496         return tpm_sendrecv_command(buf, NULL, NULL);
497 }
498
499 uint32_t tpm_read_pubek(void *data, size_t count)
500 {
501         const uint8_t command[30] = {
502                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
503         };
504         const size_t response_size_offset = 2;
505         const size_t data_offset = 10;
506         const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
507         uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
508         size_t response_length = sizeof(response);
509         uint32_t data_size;
510         uint32_t err;
511
512         err = tpm_sendrecv_command(command, response, &response_length);
513         if (err)
514                 return err;
515         if (unpack_byte_string(response, response_length, "d",
516                                 response_size_offset, &data_size))
517                 return TPM_LIB_ERROR;
518         if (data_size < header_and_checksum_size)
519                 return TPM_LIB_ERROR;
520         data_size -= header_and_checksum_size;
521         if (data_size > count)
522                 return TPM_LIB_ERROR;
523         if (unpack_byte_string(response, response_length, "s",
524                                 data_offset, data, data_size))
525                 return TPM_LIB_ERROR;
526
527         return 0;
528 }
529
530 uint32_t tpm_force_clear(void)
531 {
532         const uint8_t command[10] = {
533                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
534         };
535
536         return tpm_sendrecv_command(command, NULL, NULL);
537 }
538
539 uint32_t tpm_physical_enable(void)
540 {
541         const uint8_t command[10] = {
542                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
543         };
544
545         return tpm_sendrecv_command(command, NULL, NULL);
546 }
547
548 uint32_t tpm_physical_disable(void)
549 {
550         const uint8_t command[10] = {
551                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
552         };
553
554         return tpm_sendrecv_command(command, NULL, NULL);
555 }
556
557 uint32_t tpm_physical_set_deactivated(uint8_t state)
558 {
559         const uint8_t command[11] = {
560                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
561         };
562         const size_t state_offset = 10;
563         uint8_t buf[COMMAND_BUFFER_SIZE];
564
565         if (pack_byte_string(buf, sizeof(buf), "sb",
566                                 0, command, sizeof(command),
567                                 state_offset, state))
568                 return TPM_LIB_ERROR;
569
570         return tpm_sendrecv_command(buf, NULL, NULL);
571 }
572
573 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
574                 void *cap, size_t count)
575 {
576         const uint8_t command[22] = {
577                 0x0, 0xc1,              /* TPM_TAG */
578                 0x0, 0x0, 0x0, 0x16,    /* parameter size */
579                 0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
580                 0x0, 0x0, 0x0, 0x0,     /* TPM_CAPABILITY_AREA */
581                 0x0, 0x0, 0x0, 0x4,     /* subcap size */
582                 0x0, 0x0, 0x0, 0x0,     /* subcap value */
583         };
584         const size_t cap_area_offset = 10;
585         const size_t sub_cap_offset = 18;
586         const size_t cap_offset = 14;
587         const size_t cap_size_offset = 10;
588         uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
589         size_t response_length = sizeof(response);
590         uint32_t cap_size;
591         uint32_t err;
592
593         if (pack_byte_string(buf, sizeof(buf), "sdd",
594                                 0, command, sizeof(command),
595                                 cap_area_offset, cap_area,
596                                 sub_cap_offset, sub_cap))
597                 return TPM_LIB_ERROR;
598         err = tpm_sendrecv_command(buf, response, &response_length);
599         if (err)
600                 return err;
601         if (unpack_byte_string(response, response_length, "d",
602                                 cap_size_offset, &cap_size))
603                 return TPM_LIB_ERROR;
604         if (cap_size > response_length || cap_size > count)
605                 return TPM_LIB_ERROR;
606         if (unpack_byte_string(response, response_length, "s",
607                                 cap_offset, cap, cap_size))
608                 return TPM_LIB_ERROR;
609
610         return 0;
611 }
612
613 #ifdef CONFIG_TPM_AUTH_SESSIONS
614
615 /**
616  * Fill an authentication block in a request.
617  * This func can create the first as well as the second auth block (for
618  * double authorized commands).
619  *
620  * @param request       pointer to the request (w/ uninitialised auth data)
621  * @param request_len0  length of the request without auth data
622  * @param handles_len   length of the handles area in request
623  * @param auth_session  pointer to the (valid) auth session to be used
624  * @param request_auth  pointer to the auth block of the request to be filled
625  * @param auth          authentication data (HMAC key)
626  */
627 static uint32_t create_request_auth(const void *request, size_t request_len0,
628         size_t handles_len,
629         struct session_data *auth_session,
630         void *request_auth, const void *auth)
631 {
632         uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
633         sha1_context hash_ctx;
634         const size_t command_code_offset = 6;
635         const size_t auth_nonce_odd_offset = 4;
636         const size_t auth_continue_offset = 24;
637         const size_t auth_auth_offset = 25;
638
639         if (!auth_session || !auth_session->valid)
640                 return TPM_LIB_ERROR;
641
642         sha1_starts(&hash_ctx);
643         sha1_update(&hash_ctx, request + command_code_offset, 4);
644         if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
645                 sha1_update(&hash_ctx,
646                             request + TPM_REQUEST_HEADER_LENGTH + handles_len,
647                             request_len0 - TPM_REQUEST_HEADER_LENGTH
648                             - handles_len);
649         sha1_finish(&hash_ctx, hmac_data);
650
651         sha1_starts(&hash_ctx);
652         sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
653         sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
654         sha1_finish(&hash_ctx, auth_session->nonce_odd);
655
656         if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
657                              0, auth_session->handle,
658                              auth_nonce_odd_offset, auth_session->nonce_odd,
659                              DIGEST_LENGTH,
660                              auth_continue_offset, 1))
661                 return TPM_LIB_ERROR;
662         if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
663                              DIGEST_LENGTH,
664                              auth_session->nonce_even,
665                              DIGEST_LENGTH,
666                              2 * DIGEST_LENGTH,
667                              request_auth + auth_nonce_odd_offset,
668                              DIGEST_LENGTH + 1))
669                 return TPM_LIB_ERROR;
670         sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
671                   request_auth + auth_auth_offset);
672
673         return TPM_SUCCESS;
674 }
675
676 /**
677  * Verify an authentication block in a response.
678  * Since this func updates the nonce_even in the session data it has to be
679  * called when receiving a succesfull AUTH response.
680  * This func can verify the first as well as the second auth block (for
681  * double authorized commands).
682  *
683  * @param command_code  command code of the request
684  * @param response      pointer to the request (w/ uninitialised auth data)
685  * @param handles_len   length of the handles area in response
686  * @param auth_session  pointer to the (valid) auth session to be used
687  * @param response_auth pointer to the auth block of the response to be verified
688  * @param auth          authentication data (HMAC key)
689  */
690 static uint32_t verify_response_auth(uint32_t command_code,
691         const void *response, size_t response_len0,
692         size_t handles_len,
693         struct session_data *auth_session,
694         const void *response_auth, const void *auth)
695 {
696         uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
697         uint8_t computed_auth[DIGEST_LENGTH];
698         sha1_context hash_ctx;
699         const size_t return_code_offset = 6;
700         const size_t auth_continue_offset = 20;
701         const size_t auth_auth_offset = 21;
702         uint8_t auth_continue;
703
704         if (!auth_session || !auth_session->valid)
705                 return TPM_AUTHFAIL;
706         if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
707                              0, command_code))
708                 return TPM_LIB_ERROR;
709         if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
710                 return TPM_LIB_ERROR;
711
712         sha1_starts(&hash_ctx);
713         sha1_update(&hash_ctx, response + return_code_offset, 4);
714         sha1_update(&hash_ctx, hmac_data, 4);
715         if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
716                 sha1_update(&hash_ctx,
717                             response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
718                             response_len0 - TPM_RESPONSE_HEADER_LENGTH
719                             - handles_len);
720         sha1_finish(&hash_ctx, hmac_data);
721
722         memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
723         auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
724         if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
725                              DIGEST_LENGTH,
726                              response_auth,
727                              DIGEST_LENGTH,
728                              2 * DIGEST_LENGTH,
729                              auth_session->nonce_odd,
730                              DIGEST_LENGTH,
731                              3 * DIGEST_LENGTH,
732                              auth_continue))
733                 return TPM_LIB_ERROR;
734
735         sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
736                   computed_auth);
737
738         if (memcmp(computed_auth, response_auth + auth_auth_offset,
739                    DIGEST_LENGTH))
740                 return TPM_AUTHFAIL;
741
742         return TPM_SUCCESS;
743 }
744
745
746 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
747 {
748         const uint8_t command[18] = {
749                 0x00, 0xc1,             /* TPM_TAG */
750                 0x00, 0x00, 0x00, 0x00, /* parameter size */
751                 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
752                 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
753                 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
754         };
755         const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
756         uint8_t request[COMMAND_BUFFER_SIZE];
757
758         if (pack_byte_string(request, sizeof(request), "sd",
759                              0, command, sizeof(command),
760                              req_handle_offset, auth_handle))
761                 return TPM_LIB_ERROR;
762         if (oiap_session.valid && oiap_session.handle == auth_handle)
763                 oiap_session.valid = 0;
764
765         return tpm_sendrecv_command(request, NULL, NULL);
766 }
767
768 uint32_t tpm_end_oiap(void)
769 {
770         uint32_t err = TPM_SUCCESS;
771         if (oiap_session.valid)
772                 err = tpm_terminate_auth_session(oiap_session.handle);
773         return err;
774 }
775
776 uint32_t tpm_oiap(uint32_t *auth_handle)
777 {
778         const uint8_t command[10] = {
779                 0x00, 0xc1,             /* TPM_TAG */
780                 0x00, 0x00, 0x00, 0x0a, /* parameter size */
781                 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
782         };
783         const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
784         const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
785         uint8_t response[COMMAND_BUFFER_SIZE];
786         size_t response_length = sizeof(response);
787         uint32_t err;
788
789         if (oiap_session.valid)
790                 tpm_terminate_auth_session(oiap_session.handle);
791
792         err = tpm_sendrecv_command(command, response, &response_length);
793         if (err)
794                 return err;
795         if (unpack_byte_string(response, response_length, "ds",
796                                res_auth_handle_offset, &oiap_session.handle,
797                                res_nonce_even_offset, &oiap_session.nonce_even,
798                                (uint32_t)DIGEST_LENGTH))
799                 return TPM_LIB_ERROR;
800         oiap_session.valid = 1;
801         if (auth_handle)
802                 *auth_handle = oiap_session.handle;
803         return 0;
804 }
805
806 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
807                 const void *key, size_t key_length,
808                 const void *parent_key_usage_auth,
809                 uint32_t *key_handle)
810 {
811         const uint8_t command[14] = {
812                 0x00, 0xc2,             /* TPM_TAG */
813                 0x00, 0x00, 0x00, 0x00, /* parameter size */
814                 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
815                 0x00, 0x00, 0x00, 0x00, /* parent handle */
816         };
817         const size_t req_size_offset = 2;
818         const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
819         const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
820         const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
821         uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
822                         + TPM_REQUEST_AUTH_LENGTH];
823         uint8_t response[COMMAND_BUFFER_SIZE];
824         size_t response_length = sizeof(response);
825         uint32_t err;
826
827         if (!oiap_session.valid) {
828                 err = tpm_oiap(NULL);
829                 if (err)
830                         return err;
831         }
832         if (pack_byte_string(request, sizeof(request), "sdds",
833                              0, command, sizeof(command),
834                              req_size_offset,
835                              sizeof(command) + key_length
836                              + TPM_REQUEST_AUTH_LENGTH,
837                              req_parent_handle_offset, parent_handle,
838                              req_key_offset, key, key_length
839                 ))
840                 return TPM_LIB_ERROR;
841
842         err = create_request_auth(request, sizeof(command) + key_length, 4,
843                                 &oiap_session,
844                                 request + sizeof(command) + key_length,
845                                 parent_key_usage_auth);
846         if (err)
847                 return err;
848         err = tpm_sendrecv_command(request, response, &response_length);
849         if (err) {
850                 if (err == TPM_AUTHFAIL)
851                         oiap_session.valid = 0;
852                 return err;
853         }
854
855         err = verify_response_auth(0x00000041, response,
856                         response_length - TPM_RESPONSE_AUTH_LENGTH,
857                         4, &oiap_session,
858                         response + response_length - TPM_RESPONSE_AUTH_LENGTH,
859                         parent_key_usage_auth);
860         if (err)
861                 return err;
862
863         if (key_handle) {
864                 if (unpack_byte_string(response, response_length, "d",
865                                        res_handle_offset, key_handle))
866                         return TPM_LIB_ERROR;
867         }
868
869         return 0;
870 }
871
872 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
873                         void *pubkey, size_t *pubkey_len)
874 {
875         const uint8_t command[14] = {
876                 0x00, 0xc2,             /* TPM_TAG */
877                 0x00, 0x00, 0x00, 0x00, /* parameter size */
878                 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
879                 0x00, 0x00, 0x00, 0x00, /* key handle */
880         };
881         const size_t req_size_offset = 2;
882         const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
883         const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
884         uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
885         uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
886                         + TPM_RESPONSE_AUTH_LENGTH];
887         size_t response_length = sizeof(response);
888         uint32_t err;
889
890         if (!oiap_session.valid) {
891                 err = tpm_oiap(NULL);
892                 if (err)
893                         return err;
894         }
895         if (pack_byte_string(request, sizeof(request), "sdd",
896                              0, command, sizeof(command),
897                              req_size_offset,
898                              (uint32_t)(sizeof(command)
899                              + TPM_REQUEST_AUTH_LENGTH),
900                              req_key_handle_offset, key_handle
901                 ))
902                 return TPM_LIB_ERROR;
903         err = create_request_auth(request, sizeof(command), 4, &oiap_session,
904                         request + sizeof(command), usage_auth);
905         if (err)
906                 return err;
907         err = tpm_sendrecv_command(request, response, &response_length);
908         if (err) {
909                 if (err == TPM_AUTHFAIL)
910                         oiap_session.valid = 0;
911                 return err;
912         }
913         err = verify_response_auth(0x00000021, response,
914                         response_length - TPM_RESPONSE_AUTH_LENGTH,
915                         0, &oiap_session,
916                         response + response_length - TPM_RESPONSE_AUTH_LENGTH,
917                         usage_auth);
918         if (err)
919                 return err;
920
921         if (pubkey) {
922                 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
923                         - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
924                         return TPM_LIB_ERROR;
925                 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
926                         - TPM_RESPONSE_AUTH_LENGTH;
927                 memcpy(pubkey, response + res_pubkey_offset,
928                        response_length - TPM_RESPONSE_HEADER_LENGTH
929                        - TPM_RESPONSE_AUTH_LENGTH);
930         }
931
932         return 0;
933 }
934
935 #endif /* CONFIG_TPM_AUTH_SESSIONS */