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