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