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