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