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