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