]> git.sur5r.net Git - u-boot/blob - lib/tpm.c
Merge branch 'master' of git://git.denx.de/u-boot-rockchip
[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         uint8_t response[COMMAND_BUFFER_SIZE];
611         size_t response_length = sizeof(response);
612         uint32_t err;
613
614         err = tpm_sendrecv_command(command, response, &response_length);
615         if (err)
616                 return err;
617         memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
618
619         return 0;
620 }
621
622 uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
623 {
624         const uint8_t command[22] = {
625                 0x0, 0xc1,              /* TPM_TAG */
626                 0x0, 0x0, 0x0, 0x16,    /* parameter size */
627                 0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
628                 0x0, 0x0, 0x0, 0x11,
629                 0x0, 0x0, 0x0, 0x4,
630         };
631         const size_t index_offset = 18;
632         const size_t perm_offset = 60;
633         uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
634         size_t response_length = sizeof(response);
635         uint32_t err;
636
637         if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
638                              index_offset, index))
639                 return TPM_LIB_ERROR;
640         err = tpm_sendrecv_command(buf, response, &response_length);
641         if (err)
642                 return err;
643         if (unpack_byte_string(response, response_length, "d",
644                                perm_offset, perm))
645                 return TPM_LIB_ERROR;
646
647         return 0;
648 }
649
650 #ifdef CONFIG_TPM_FLUSH_RESOURCES
651 uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type)
652 {
653         const uint8_t command[18] = {
654                 0x00, 0xc1,             /* TPM_TAG */
655                 0x00, 0x00, 0x00, 0x12, /* parameter size */
656                 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
657                 0x00, 0x00, 0x00, 0x00, /* key handle */
658                 0x00, 0x00, 0x00, 0x00, /* resource type */
659         };
660         const size_t key_handle_offset = 10;
661         const size_t resource_type_offset = 14;
662         uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
663         size_t response_length = sizeof(response);
664         uint32_t err;
665
666         if (pack_byte_string(buf, sizeof(buf), "sdd",
667                              0, command, sizeof(command),
668                              key_handle_offset, key_handle,
669                              resource_type_offset, resource_type))
670                 return TPM_LIB_ERROR;
671
672         err = tpm_sendrecv_command(buf, response, &response_length);
673         if (err)
674                 return err;
675         return 0;
676 }
677 #endif /* CONFIG_TPM_FLUSH_RESOURCES */
678
679 #ifdef CONFIG_TPM_AUTH_SESSIONS
680
681 /**
682  * Fill an authentication block in a request.
683  * This func can create the first as well as the second auth block (for
684  * double authorized commands).
685  *
686  * @param request       pointer to the request (w/ uninitialised auth data)
687  * @param request_len0  length of the request without auth data
688  * @param handles_len   length of the handles area in request
689  * @param auth_session  pointer to the (valid) auth session to be used
690  * @param request_auth  pointer to the auth block of the request to be filled
691  * @param auth          authentication data (HMAC key)
692  */
693 static uint32_t create_request_auth(const void *request, size_t request_len0,
694         size_t handles_len,
695         struct session_data *auth_session,
696         void *request_auth, const void *auth)
697 {
698         uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
699         sha1_context hash_ctx;
700         const size_t command_code_offset = 6;
701         const size_t auth_nonce_odd_offset = 4;
702         const size_t auth_continue_offset = 24;
703         const size_t auth_auth_offset = 25;
704
705         if (!auth_session || !auth_session->valid)
706                 return TPM_LIB_ERROR;
707
708         sha1_starts(&hash_ctx);
709         sha1_update(&hash_ctx, request + command_code_offset, 4);
710         if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
711                 sha1_update(&hash_ctx,
712                             request + TPM_REQUEST_HEADER_LENGTH + handles_len,
713                             request_len0 - TPM_REQUEST_HEADER_LENGTH
714                             - handles_len);
715         sha1_finish(&hash_ctx, hmac_data);
716
717         sha1_starts(&hash_ctx);
718         sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
719         sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
720         sha1_finish(&hash_ctx, auth_session->nonce_odd);
721
722         if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
723                              0, auth_session->handle,
724                              auth_nonce_odd_offset, auth_session->nonce_odd,
725                              DIGEST_LENGTH,
726                              auth_continue_offset, 1))
727                 return TPM_LIB_ERROR;
728         if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
729                              DIGEST_LENGTH,
730                              auth_session->nonce_even,
731                              DIGEST_LENGTH,
732                              2 * DIGEST_LENGTH,
733                              request_auth + auth_nonce_odd_offset,
734                              DIGEST_LENGTH + 1))
735                 return TPM_LIB_ERROR;
736         sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
737                   request_auth + auth_auth_offset);
738
739         return TPM_SUCCESS;
740 }
741
742 /**
743  * Verify an authentication block in a response.
744  * Since this func updates the nonce_even in the session data it has to be
745  * called when receiving a succesfull AUTH response.
746  * This func can verify the first as well as the second auth block (for
747  * double authorized commands).
748  *
749  * @param command_code  command code of the request
750  * @param response      pointer to the request (w/ uninitialised auth data)
751  * @param handles_len   length of the handles area in response
752  * @param auth_session  pointer to the (valid) auth session to be used
753  * @param response_auth pointer to the auth block of the response to be verified
754  * @param auth          authentication data (HMAC key)
755  */
756 static uint32_t verify_response_auth(uint32_t command_code,
757         const void *response, size_t response_len0,
758         size_t handles_len,
759         struct session_data *auth_session,
760         const void *response_auth, const void *auth)
761 {
762         uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
763         uint8_t computed_auth[DIGEST_LENGTH];
764         sha1_context hash_ctx;
765         const size_t return_code_offset = 6;
766         const size_t auth_continue_offset = 20;
767         const size_t auth_auth_offset = 21;
768         uint8_t auth_continue;
769
770         if (!auth_session || !auth_session->valid)
771                 return TPM_AUTHFAIL;
772         if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
773                              0, command_code))
774                 return TPM_LIB_ERROR;
775         if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
776                 return TPM_LIB_ERROR;
777
778         sha1_starts(&hash_ctx);
779         sha1_update(&hash_ctx, response + return_code_offset, 4);
780         sha1_update(&hash_ctx, hmac_data, 4);
781         if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
782                 sha1_update(&hash_ctx,
783                             response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
784                             response_len0 - TPM_RESPONSE_HEADER_LENGTH
785                             - handles_len);
786         sha1_finish(&hash_ctx, hmac_data);
787
788         memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
789         auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
790         if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
791                              DIGEST_LENGTH,
792                              response_auth,
793                              DIGEST_LENGTH,
794                              2 * DIGEST_LENGTH,
795                              auth_session->nonce_odd,
796                              DIGEST_LENGTH,
797                              3 * DIGEST_LENGTH,
798                              auth_continue))
799                 return TPM_LIB_ERROR;
800
801         sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
802                   computed_auth);
803
804         if (memcmp(computed_auth, response_auth + auth_auth_offset,
805                    DIGEST_LENGTH))
806                 return TPM_AUTHFAIL;
807
808         return TPM_SUCCESS;
809 }
810
811
812 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
813 {
814         const uint8_t command[18] = {
815                 0x00, 0xc1,             /* TPM_TAG */
816                 0x00, 0x00, 0x00, 0x00, /* parameter size */
817                 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
818                 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
819                 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
820         };
821         const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
822         uint8_t request[COMMAND_BUFFER_SIZE];
823
824         if (pack_byte_string(request, sizeof(request), "sd",
825                              0, command, sizeof(command),
826                              req_handle_offset, auth_handle))
827                 return TPM_LIB_ERROR;
828         if (oiap_session.valid && oiap_session.handle == auth_handle)
829                 oiap_session.valid = 0;
830
831         return tpm_sendrecv_command(request, NULL, NULL);
832 }
833
834 uint32_t tpm_end_oiap(void)
835 {
836         uint32_t err = TPM_SUCCESS;
837         if (oiap_session.valid)
838                 err = tpm_terminate_auth_session(oiap_session.handle);
839         return err;
840 }
841
842 uint32_t tpm_oiap(uint32_t *auth_handle)
843 {
844         const uint8_t command[10] = {
845                 0x00, 0xc1,             /* TPM_TAG */
846                 0x00, 0x00, 0x00, 0x0a, /* parameter size */
847                 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
848         };
849         const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
850         const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
851         uint8_t response[COMMAND_BUFFER_SIZE];
852         size_t response_length = sizeof(response);
853         uint32_t err;
854
855         if (oiap_session.valid)
856                 tpm_terminate_auth_session(oiap_session.handle);
857
858         err = tpm_sendrecv_command(command, response, &response_length);
859         if (err)
860                 return err;
861         if (unpack_byte_string(response, response_length, "ds",
862                                res_auth_handle_offset, &oiap_session.handle,
863                                res_nonce_even_offset, &oiap_session.nonce_even,
864                                (uint32_t)DIGEST_LENGTH))
865                 return TPM_LIB_ERROR;
866         oiap_session.valid = 1;
867         if (auth_handle)
868                 *auth_handle = oiap_session.handle;
869         return 0;
870 }
871
872 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
873                 const void *key, size_t key_length,
874                 const void *parent_key_usage_auth,
875                 uint32_t *key_handle)
876 {
877         const uint8_t command[14] = {
878                 0x00, 0xc2,             /* TPM_TAG */
879                 0x00, 0x00, 0x00, 0x00, /* parameter size */
880                 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
881                 0x00, 0x00, 0x00, 0x00, /* parent handle */
882         };
883         const size_t req_size_offset = 2;
884         const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
885         const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
886         const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
887         uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
888                         + TPM_REQUEST_AUTH_LENGTH];
889         uint8_t response[COMMAND_BUFFER_SIZE];
890         size_t response_length = sizeof(response);
891         uint32_t err;
892
893         if (!oiap_session.valid) {
894                 err = tpm_oiap(NULL);
895                 if (err)
896                         return err;
897         }
898         if (pack_byte_string(request, sizeof(request), "sdds",
899                              0, command, sizeof(command),
900                              req_size_offset,
901                              sizeof(command) + key_length
902                              + TPM_REQUEST_AUTH_LENGTH,
903                              req_parent_handle_offset, parent_handle,
904                              req_key_offset, key, key_length
905                 ))
906                 return TPM_LIB_ERROR;
907
908         err = create_request_auth(request, sizeof(command) + key_length, 4,
909                                 &oiap_session,
910                                 request + sizeof(command) + key_length,
911                                 parent_key_usage_auth);
912         if (err)
913                 return err;
914         err = tpm_sendrecv_command(request, response, &response_length);
915         if (err) {
916                 if (err == TPM_AUTHFAIL)
917                         oiap_session.valid = 0;
918                 return err;
919         }
920
921         err = verify_response_auth(0x00000041, response,
922                         response_length - TPM_RESPONSE_AUTH_LENGTH,
923                         4, &oiap_session,
924                         response + response_length - TPM_RESPONSE_AUTH_LENGTH,
925                         parent_key_usage_auth);
926         if (err)
927                 return err;
928
929         if (key_handle) {
930                 if (unpack_byte_string(response, response_length, "d",
931                                        res_handle_offset, key_handle))
932                         return TPM_LIB_ERROR;
933         }
934
935         return 0;
936 }
937
938 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
939                         void *pubkey, size_t *pubkey_len)
940 {
941         const uint8_t command[14] = {
942                 0x00, 0xc2,             /* TPM_TAG */
943                 0x00, 0x00, 0x00, 0x00, /* parameter size */
944                 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
945                 0x00, 0x00, 0x00, 0x00, /* key handle */
946         };
947         const size_t req_size_offset = 2;
948         const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
949         const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
950         uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
951         uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
952                         + TPM_RESPONSE_AUTH_LENGTH];
953         size_t response_length = sizeof(response);
954         uint32_t err;
955
956         if (!oiap_session.valid) {
957                 err = tpm_oiap(NULL);
958                 if (err)
959                         return err;
960         }
961         if (pack_byte_string(request, sizeof(request), "sdd",
962                              0, command, sizeof(command),
963                              req_size_offset,
964                              (uint32_t)(sizeof(command)
965                              + TPM_REQUEST_AUTH_LENGTH),
966                              req_key_handle_offset, key_handle
967                 ))
968                 return TPM_LIB_ERROR;
969         err = create_request_auth(request, sizeof(command), 4, &oiap_session,
970                         request + sizeof(command), usage_auth);
971         if (err)
972                 return err;
973         err = tpm_sendrecv_command(request, response, &response_length);
974         if (err) {
975                 if (err == TPM_AUTHFAIL)
976                         oiap_session.valid = 0;
977                 return err;
978         }
979         err = verify_response_auth(0x00000021, response,
980                         response_length - TPM_RESPONSE_AUTH_LENGTH,
981                         0, &oiap_session,
982                         response + response_length - TPM_RESPONSE_AUTH_LENGTH,
983                         usage_auth);
984         if (err)
985                 return err;
986
987         if (pubkey) {
988                 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
989                         - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
990                         return TPM_LIB_ERROR;
991                 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
992                         - TPM_RESPONSE_AUTH_LENGTH;
993                 memcpy(pubkey, response + res_pubkey_offset,
994                        response_length - TPM_RESPONSE_HEADER_LENGTH
995                        - TPM_RESPONSE_AUTH_LENGTH);
996         }
997
998         return 0;
999 }
1000
1001 #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
1002 uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
1003                            pubkey_digest[20], uint32_t *handle)
1004 {
1005         uint16_t key_count;
1006         uint32_t key_handles[10];
1007         uint8_t buf[288];
1008         uint8_t *ptr;
1009         uint32_t err;
1010         uint8_t digest[20];
1011         size_t buf_len;
1012         unsigned int i;
1013
1014         /* fetch list of already loaded keys in the TPM */
1015         err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
1016         if (err)
1017                 return -1;
1018         key_count = get_unaligned_be16(buf);
1019         ptr = buf + 2;
1020         for (i = 0; i < key_count; ++i, ptr += 4)
1021                 key_handles[i] = get_unaligned_be32(ptr);
1022
1023         /* now search a(/ the) key which we can access with the given auth */
1024         for (i = 0; i < key_count; ++i) {
1025                 buf_len = sizeof(buf);
1026                 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
1027                 if (err && err != TPM_AUTHFAIL)
1028                         return -1;
1029                 if (err)
1030                         continue;
1031                 sha1_csum(buf, buf_len, digest);
1032                 if (!memcmp(digest, pubkey_digest, 20)) {
1033                         *handle = key_handles[i];
1034                         return 0;
1035                 }
1036         }
1037         return 1;
1038 }
1039 #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
1040
1041 #endif /* CONFIG_TPM_AUTH_SESSIONS */