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