]> git.sur5r.net Git - u-boot/blob - lib/tpm-v1.c
serial: Add Actions Semi OWL UART support
[u-boot] / lib / tpm-v1.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013 The Chromium OS Authors.
4  * Coypright (c) 2013 Guntermann & Drunck GmbH
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <asm/unaligned.h>
10 #include <u-boot/sha1.h>
11 #include <tpm-common.h>
12 #include <tpm-v1.h>
13 #include "tpm-utils.h"
14
15 #ifdef CONFIG_TPM_AUTH_SESSIONS
16
17 #ifndef CONFIG_SHA1
18 #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
19 #endif /* !CONFIG_SHA1 */
20
21 struct session_data {
22         int             valid;
23         u32     handle;
24         u8              nonce_even[DIGEST_LENGTH];
25         u8              nonce_odd[DIGEST_LENGTH];
26 };
27
28 static struct session_data oiap_session = {0, };
29
30 #endif /* CONFIG_TPM_AUTH_SESSIONS */
31
32 u32 tpm_startup(enum tpm_startup_type mode)
33 {
34         const u8 command[12] = {
35                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
36         };
37         const size_t mode_offset = 10;
38         u8 buf[COMMAND_BUFFER_SIZE];
39
40         if (pack_byte_string(buf, sizeof(buf), "sw",
41                              0, command, sizeof(command),
42                              mode_offset, mode))
43                 return TPM_LIB_ERROR;
44
45         return tpm_sendrecv_command(buf, NULL, NULL);
46 }
47
48 u32 tpm_self_test_full(void)
49 {
50         const u8 command[10] = {
51                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
52         };
53         return tpm_sendrecv_command(command, NULL, NULL);
54 }
55
56 u32 tpm_continue_self_test(void)
57 {
58         const u8 command[10] = {
59                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
60         };
61         return tpm_sendrecv_command(command, NULL, NULL);
62 }
63
64 u32 tpm_nv_define_space(u32 index, u32 perm, u32 size)
65 {
66         const u8 command[101] = {
67                 0x0, 0xc1,              /* TPM_TAG */
68                 0x0, 0x0, 0x0, 0x65,    /* parameter size */
69                 0x0, 0x0, 0x0, 0xcc,    /* TPM_COMMAND_CODE */
70                 /* TPM_NV_DATA_PUBLIC->... */
71                 0x0, 0x18,              /* ...->TPM_STRUCTURE_TAG */
72                 0, 0, 0, 0,             /* ...->TPM_NV_INDEX */
73                 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
74                 0x0, 0x3,
75                 0, 0, 0,
76                 0x1f,
77                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78                 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
79                 0x0, 0x3,
80                 0, 0, 0,
81                 0x1f,
82                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83                 /* TPM_NV_ATTRIBUTES->... */
84                 0x0, 0x17,              /* ...->TPM_STRUCTURE_TAG */
85                 0, 0, 0, 0,             /* ...->attributes */
86                 /* End of TPM_NV_ATTRIBUTES */
87                 0,                      /* bReadSTClear */
88                 0,                      /* bWriteSTClear */
89                 0,                      /* bWriteDefine */
90                 0, 0, 0, 0,             /* size */
91         };
92         const size_t index_offset = 12;
93         const size_t perm_offset = 70;
94         const size_t size_offset = 77;
95         u8 buf[COMMAND_BUFFER_SIZE];
96
97         if (pack_byte_string(buf, sizeof(buf), "sddd",
98                              0, command, sizeof(command),
99                              index_offset, index,
100                              perm_offset, perm,
101                              size_offset, size))
102                 return TPM_LIB_ERROR;
103
104         return tpm_sendrecv_command(buf, NULL, NULL);
105 }
106
107 u32 tpm_nv_read_value(u32 index, void *data, u32 count)
108 {
109         const u8 command[22] = {
110                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
111         };
112         const size_t index_offset = 10;
113         const size_t length_offset = 18;
114         const size_t data_size_offset = 10;
115         const size_t data_offset = 14;
116         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
117         size_t response_length = sizeof(response);
118         u32 data_size;
119         u32 err;
120
121         if (pack_byte_string(buf, sizeof(buf), "sdd",
122                              0, command, sizeof(command),
123                              index_offset, index,
124                              length_offset, count))
125                 return TPM_LIB_ERROR;
126         err = tpm_sendrecv_command(buf, response, &response_length);
127         if (err)
128                 return err;
129         if (unpack_byte_string(response, response_length, "d",
130                                data_size_offset, &data_size))
131                 return TPM_LIB_ERROR;
132         if (data_size > count)
133                 return TPM_LIB_ERROR;
134         if (unpack_byte_string(response, response_length, "s",
135                                data_offset, data, data_size))
136                 return TPM_LIB_ERROR;
137
138         return 0;
139 }
140
141 u32 tpm_nv_write_value(u32 index, const void *data, u32 length)
142 {
143         const u8 command[256] = {
144                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
145         };
146         const size_t command_size_offset = 2;
147         const size_t index_offset = 10;
148         const size_t length_offset = 18;
149         const size_t data_offset = 22;
150         const size_t write_info_size = 12;
151         const u32 total_length =
152                 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
153         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
154         size_t response_length = sizeof(response);
155         u32 err;
156
157         if (pack_byte_string(buf, sizeof(buf), "sddds",
158                              0, command, sizeof(command),
159                              command_size_offset, total_length,
160                              index_offset, index,
161                              length_offset, length,
162                              data_offset, data, length))
163                 return TPM_LIB_ERROR;
164         err = tpm_sendrecv_command(buf, response, &response_length);
165         if (err)
166                 return err;
167
168         return 0;
169 }
170
171 u32 tpm_extend(u32 index, const void *in_digest, void *out_digest)
172 {
173         const u8 command[34] = {
174                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
175         };
176         const size_t index_offset = 10;
177         const size_t in_digest_offset = 14;
178         const size_t out_digest_offset = 10;
179         u8 buf[COMMAND_BUFFER_SIZE];
180         u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
181         size_t response_length = sizeof(response);
182         u32 err;
183
184         if (pack_byte_string(buf, sizeof(buf), "sds",
185                              0, command, sizeof(command),
186                              index_offset, index,
187                              in_digest_offset, in_digest,
188                              PCR_DIGEST_LENGTH))
189                 return TPM_LIB_ERROR;
190         err = tpm_sendrecv_command(buf, response, &response_length);
191         if (err)
192                 return err;
193
194         if (unpack_byte_string(response, response_length, "s",
195                                out_digest_offset, out_digest,
196                                PCR_DIGEST_LENGTH))
197                 return TPM_LIB_ERROR;
198
199         return 0;
200 }
201
202 u32 tpm_pcr_read(u32 index, void *data, size_t count)
203 {
204         const u8 command[14] = {
205                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
206         };
207         const size_t index_offset = 10;
208         const size_t out_digest_offset = 10;
209         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
210         size_t response_length = sizeof(response);
211         u32 err;
212
213         if (count < PCR_DIGEST_LENGTH)
214                 return TPM_LIB_ERROR;
215
216         if (pack_byte_string(buf, sizeof(buf), "sd",
217                              0, command, sizeof(command),
218                              index_offset, index))
219                 return TPM_LIB_ERROR;
220         err = tpm_sendrecv_command(buf, response, &response_length);
221         if (err)
222                 return err;
223         if (unpack_byte_string(response, response_length, "s",
224                                out_digest_offset, data, PCR_DIGEST_LENGTH))
225                 return TPM_LIB_ERROR;
226
227         return 0;
228 }
229
230 u32 tpm_tsc_physical_presence(u16 presence)
231 {
232         const u8 command[12] = {
233                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
234         };
235         const size_t presence_offset = 10;
236         u8 buf[COMMAND_BUFFER_SIZE];
237
238         if (pack_byte_string(buf, sizeof(buf), "sw",
239                              0, command, sizeof(command),
240                              presence_offset, presence))
241                 return TPM_LIB_ERROR;
242
243         return tpm_sendrecv_command(buf, NULL, NULL);
244 }
245
246 u32 tpm_read_pubek(void *data, size_t count)
247 {
248         const u8 command[30] = {
249                 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
250         };
251         const size_t response_size_offset = 2;
252         const size_t data_offset = 10;
253         const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
254         u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
255         size_t response_length = sizeof(response);
256         u32 data_size;
257         u32 err;
258
259         err = tpm_sendrecv_command(command, response, &response_length);
260         if (err)
261                 return err;
262         if (unpack_byte_string(response, response_length, "d",
263                                response_size_offset, &data_size))
264                 return TPM_LIB_ERROR;
265         if (data_size < header_and_checksum_size)
266                 return TPM_LIB_ERROR;
267         data_size -= header_and_checksum_size;
268         if (data_size > count)
269                 return TPM_LIB_ERROR;
270         if (unpack_byte_string(response, response_length, "s",
271                                data_offset, data, data_size))
272                 return TPM_LIB_ERROR;
273
274         return 0;
275 }
276
277 u32 tpm_force_clear(void)
278 {
279         const u8 command[10] = {
280                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
281         };
282
283         return tpm_sendrecv_command(command, NULL, NULL);
284 }
285
286 u32 tpm_physical_enable(void)
287 {
288         const u8 command[10] = {
289                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
290         };
291
292         return tpm_sendrecv_command(command, NULL, NULL);
293 }
294
295 u32 tpm_physical_disable(void)
296 {
297         const u8 command[10] = {
298                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
299         };
300
301         return tpm_sendrecv_command(command, NULL, NULL);
302 }
303
304 u32 tpm_physical_set_deactivated(u8 state)
305 {
306         const u8 command[11] = {
307                 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
308         };
309         const size_t state_offset = 10;
310         u8 buf[COMMAND_BUFFER_SIZE];
311
312         if (pack_byte_string(buf, sizeof(buf), "sb",
313                              0, command, sizeof(command),
314                              state_offset, state))
315                 return TPM_LIB_ERROR;
316
317         return tpm_sendrecv_command(buf, NULL, NULL);
318 }
319
320 u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count)
321 {
322         const u8 command[22] = {
323                 0x0, 0xc1,              /* TPM_TAG */
324                 0x0, 0x0, 0x0, 0x16,    /* parameter size */
325                 0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
326                 0x0, 0x0, 0x0, 0x0,     /* TPM_CAPABILITY_AREA */
327                 0x0, 0x0, 0x0, 0x4,     /* subcap size */
328                 0x0, 0x0, 0x0, 0x0,     /* subcap value */
329         };
330         const size_t cap_area_offset = 10;
331         const size_t sub_cap_offset = 18;
332         const size_t cap_offset = 14;
333         const size_t cap_size_offset = 10;
334         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
335         size_t response_length = sizeof(response);
336         u32 cap_size;
337         u32 err;
338
339         if (pack_byte_string(buf, sizeof(buf), "sdd",
340                              0, command, sizeof(command),
341                              cap_area_offset, cap_area,
342                              sub_cap_offset, sub_cap))
343                 return TPM_LIB_ERROR;
344         err = tpm_sendrecv_command(buf, response, &response_length);
345         if (err)
346                 return err;
347         if (unpack_byte_string(response, response_length, "d",
348                                cap_size_offset, &cap_size))
349                 return TPM_LIB_ERROR;
350         if (cap_size > response_length || cap_size > count)
351                 return TPM_LIB_ERROR;
352         if (unpack_byte_string(response, response_length, "s",
353                                cap_offset, cap, cap_size))
354                 return TPM_LIB_ERROR;
355
356         return 0;
357 }
358
359 u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
360 {
361         const u8 command[22] = {
362                 0x0, 0xc1,              /* TPM_TAG */
363                 0x0, 0x0, 0x0, 0x16,    /* parameter size */
364                 0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
365                 0x0, 0x0, 0x0, 0x4,     /* TPM_CAP_FLAG_PERM */
366                 0x0, 0x0, 0x0, 0x4,     /* subcap size */
367                 0x0, 0x0, 0x1, 0x8,     /* subcap value */
368         };
369         const size_t data_size_offset = TPM_HEADER_SIZE;
370         const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
371         u8 response[COMMAND_BUFFER_SIZE];
372         size_t response_length = sizeof(response);
373         u32 err;
374         u32 data_size;
375
376         err = tpm_sendrecv_command(command, response, &response_length);
377         if (err)
378                 return err;
379         if (unpack_byte_string(response, response_length, "d",
380                                data_size_offset, &data_size))
381                 return TPM_LIB_ERROR;
382         if (data_size < sizeof(*pflags))
383                 return TPM_LIB_ERROR;
384         if (unpack_byte_string(response, response_length, "s",
385                                data_offset, pflags, sizeof(*pflags)))
386                 return TPM_LIB_ERROR;
387
388         return 0;
389 }
390
391 u32 tpm_get_permissions(u32 index, u32 *perm)
392 {
393         const u8 command[22] = {
394                 0x0, 0xc1,              /* TPM_TAG */
395                 0x0, 0x0, 0x0, 0x16,    /* parameter size */
396                 0x0, 0x0, 0x0, 0x65,    /* TPM_COMMAND_CODE */
397                 0x0, 0x0, 0x0, 0x11,
398                 0x0, 0x0, 0x0, 0x4,
399         };
400         const size_t index_offset = 18;
401         const size_t perm_offset = 60;
402         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
403         size_t response_length = sizeof(response);
404         u32 err;
405
406         if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
407                              index_offset, index))
408                 return TPM_LIB_ERROR;
409         err = tpm_sendrecv_command(buf, response, &response_length);
410         if (err)
411                 return err;
412         if (unpack_byte_string(response, response_length, "d",
413                                perm_offset, perm))
414                 return TPM_LIB_ERROR;
415
416         return 0;
417 }
418
419 #ifdef CONFIG_TPM_FLUSH_RESOURCES
420 u32 tpm_flush_specific(u32 key_handle, u32 resource_type)
421 {
422         const u8 command[18] = {
423                 0x00, 0xc1,             /* TPM_TAG */
424                 0x00, 0x00, 0x00, 0x12, /* parameter size */
425                 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
426                 0x00, 0x00, 0x00, 0x00, /* key handle */
427                 0x00, 0x00, 0x00, 0x00, /* resource type */
428         };
429         const size_t key_handle_offset = 10;
430         const size_t resource_type_offset = 14;
431         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
432         size_t response_length = sizeof(response);
433         u32 err;
434
435         if (pack_byte_string(buf, sizeof(buf), "sdd",
436                              0, command, sizeof(command),
437                              key_handle_offset, key_handle,
438                              resource_type_offset, resource_type))
439                 return TPM_LIB_ERROR;
440
441         err = tpm_sendrecv_command(buf, response, &response_length);
442         if (err)
443                 return err;
444         return 0;
445 }
446 #endif /* CONFIG_TPM_FLUSH_RESOURCES */
447
448 #ifdef CONFIG_TPM_AUTH_SESSIONS
449
450 /**
451  * Fill an authentication block in a request.
452  * This func can create the first as well as the second auth block (for
453  * double authorized commands).
454  *
455  * @param request       pointer to the request (w/ uninitialised auth data)
456  * @param request_len0  length of the request without auth data
457  * @param handles_len   length of the handles area in request
458  * @param auth_session  pointer to the (valid) auth session to be used
459  * @param request_auth  pointer to the auth block of the request to be filled
460  * @param auth          authentication data (HMAC key)
461  */
462 static u32 create_request_auth(const void *request, size_t request_len0,
463                                size_t handles_len,
464                                struct session_data *auth_session,
465                                void *request_auth, const void *auth)
466 {
467         u8 hmac_data[DIGEST_LENGTH * 3 + 1];
468         sha1_context hash_ctx;
469         const size_t command_code_offset = 6;
470         const size_t auth_nonce_odd_offset = 4;
471         const size_t auth_continue_offset = 24;
472         const size_t auth_auth_offset = 25;
473
474         if (!auth_session || !auth_session->valid)
475                 return TPM_LIB_ERROR;
476
477         sha1_starts(&hash_ctx);
478         sha1_update(&hash_ctx, request + command_code_offset, 4);
479         if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
480                 sha1_update(&hash_ctx,
481                             request + TPM_REQUEST_HEADER_LENGTH + handles_len,
482                             request_len0 - TPM_REQUEST_HEADER_LENGTH
483                             - handles_len);
484         sha1_finish(&hash_ctx, hmac_data);
485
486         sha1_starts(&hash_ctx);
487         sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
488         sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
489         sha1_finish(&hash_ctx, auth_session->nonce_odd);
490
491         if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
492                              0, auth_session->handle,
493                              auth_nonce_odd_offset, auth_session->nonce_odd,
494                              DIGEST_LENGTH,
495                              auth_continue_offset, 1))
496                 return TPM_LIB_ERROR;
497         if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
498                              DIGEST_LENGTH,
499                              auth_session->nonce_even,
500                              DIGEST_LENGTH,
501                              2 * DIGEST_LENGTH,
502                              request_auth + auth_nonce_odd_offset,
503                              DIGEST_LENGTH + 1))
504                 return TPM_LIB_ERROR;
505         sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
506                   request_auth + auth_auth_offset);
507
508         return TPM_SUCCESS;
509 }
510
511 /**
512  * Verify an authentication block in a response.
513  * Since this func updates the nonce_even in the session data it has to be
514  * called when receiving a succesfull AUTH response.
515  * This func can verify the first as well as the second auth block (for
516  * double authorized commands).
517  *
518  * @param command_code  command code of the request
519  * @param response      pointer to the request (w/ uninitialised auth data)
520  * @param handles_len   length of the handles area in response
521  * @param auth_session  pointer to the (valid) auth session to be used
522  * @param response_auth pointer to the auth block of the response to be verified
523  * @param auth          authentication data (HMAC key)
524  */
525 static u32 verify_response_auth(u32 command_code, const void *response,
526                                 size_t response_len0, size_t handles_len,
527                                 struct session_data *auth_session,
528                                 const void *response_auth, const void *auth)
529 {
530         u8 hmac_data[DIGEST_LENGTH * 3 + 1];
531         u8 computed_auth[DIGEST_LENGTH];
532         sha1_context hash_ctx;
533         const size_t return_code_offset = 6;
534         const size_t auth_continue_offset = 20;
535         const size_t auth_auth_offset = 21;
536         u8 auth_continue;
537
538         if (!auth_session || !auth_session->valid)
539                 return TPM_AUTHFAIL;
540         if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
541                              0, command_code))
542                 return TPM_LIB_ERROR;
543         if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
544                 return TPM_LIB_ERROR;
545
546         sha1_starts(&hash_ctx);
547         sha1_update(&hash_ctx, response + return_code_offset, 4);
548         sha1_update(&hash_ctx, hmac_data, 4);
549         if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
550                 sha1_update(&hash_ctx,
551                             response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
552                             response_len0 - TPM_RESPONSE_HEADER_LENGTH
553                             - handles_len);
554         sha1_finish(&hash_ctx, hmac_data);
555
556         memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
557         auth_continue = ((u8 *)response_auth)[auth_continue_offset];
558         if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
559                              DIGEST_LENGTH,
560                              response_auth,
561                              DIGEST_LENGTH,
562                              2 * DIGEST_LENGTH,
563                              auth_session->nonce_odd,
564                              DIGEST_LENGTH,
565                              3 * DIGEST_LENGTH,
566                              auth_continue))
567                 return TPM_LIB_ERROR;
568
569         sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
570                   computed_auth);
571
572         if (memcmp(computed_auth, response_auth + auth_auth_offset,
573                    DIGEST_LENGTH))
574                 return TPM_AUTHFAIL;
575
576         return TPM_SUCCESS;
577 }
578
579 u32 tpm_terminate_auth_session(u32 auth_handle)
580 {
581         const u8 command[18] = {
582                 0x00, 0xc1,             /* TPM_TAG */
583                 0x00, 0x00, 0x00, 0x00, /* parameter size */
584                 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
585                 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
586                 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
587         };
588         const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
589         u8 request[COMMAND_BUFFER_SIZE];
590
591         if (pack_byte_string(request, sizeof(request), "sd",
592                              0, command, sizeof(command),
593                              req_handle_offset, auth_handle))
594                 return TPM_LIB_ERROR;
595         if (oiap_session.valid && oiap_session.handle == auth_handle)
596                 oiap_session.valid = 0;
597
598         return tpm_sendrecv_command(request, NULL, NULL);
599 }
600
601 u32 tpm_end_oiap(void)
602 {
603         u32 err = TPM_SUCCESS;
604
605         if (oiap_session.valid)
606                 err = tpm_terminate_auth_session(oiap_session.handle);
607         return err;
608 }
609
610 u32 tpm_oiap(u32 *auth_handle)
611 {
612         const u8 command[10] = {
613                 0x00, 0xc1,             /* TPM_TAG */
614                 0x00, 0x00, 0x00, 0x0a, /* parameter size */
615                 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
616         };
617         const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
618         const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
619         u8 response[COMMAND_BUFFER_SIZE];
620         size_t response_length = sizeof(response);
621         u32 err;
622
623         if (oiap_session.valid)
624                 tpm_terminate_auth_session(oiap_session.handle);
625
626         err = tpm_sendrecv_command(command, response, &response_length);
627         if (err)
628                 return err;
629         if (unpack_byte_string(response, response_length, "ds",
630                                res_auth_handle_offset, &oiap_session.handle,
631                                res_nonce_even_offset, &oiap_session.nonce_even,
632                                (u32)DIGEST_LENGTH))
633                 return TPM_LIB_ERROR;
634         oiap_session.valid = 1;
635         if (auth_handle)
636                 *auth_handle = oiap_session.handle;
637         return 0;
638 }
639
640 u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length,
641                        const void *parent_key_usage_auth, u32 *key_handle)
642 {
643         const u8 command[14] = {
644                 0x00, 0xc2,             /* TPM_TAG */
645                 0x00, 0x00, 0x00, 0x00, /* parameter size */
646                 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
647                 0x00, 0x00, 0x00, 0x00, /* parent handle */
648         };
649         const size_t req_size_offset = 2;
650         const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
651         const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
652         const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
653         u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
654                    TPM_REQUEST_AUTH_LENGTH];
655         u8 response[COMMAND_BUFFER_SIZE];
656         size_t response_length = sizeof(response);
657         u32 err;
658
659         if (!oiap_session.valid) {
660                 err = tpm_oiap(NULL);
661                 if (err)
662                         return err;
663         }
664         if (pack_byte_string(request, sizeof(request), "sdds",
665                              0, command, sizeof(command),
666                              req_size_offset,
667                              sizeof(command) + key_length
668                              + TPM_REQUEST_AUTH_LENGTH,
669                              req_parent_handle_offset, parent_handle,
670                              req_key_offset, key, key_length
671                 ))
672                 return TPM_LIB_ERROR;
673
674         err = create_request_auth(request, sizeof(command) + key_length, 4,
675                                   &oiap_session,
676                                   request + sizeof(command) + key_length,
677                                   parent_key_usage_auth);
678         if (err)
679                 return err;
680         err = tpm_sendrecv_command(request, response, &response_length);
681         if (err) {
682                 if (err == TPM_AUTHFAIL)
683                         oiap_session.valid = 0;
684                 return err;
685         }
686
687         err = verify_response_auth(0x00000041, response,
688                                    response_length - TPM_RESPONSE_AUTH_LENGTH,
689                                    4, &oiap_session,
690                                    response + response_length -
691                                    TPM_RESPONSE_AUTH_LENGTH,
692                                    parent_key_usage_auth);
693         if (err)
694                 return err;
695
696         if (key_handle) {
697                 if (unpack_byte_string(response, response_length, "d",
698                                        res_handle_offset, key_handle))
699                         return TPM_LIB_ERROR;
700         }
701
702         return 0;
703 }
704
705 u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey,
706                          size_t *pubkey_len)
707 {
708         const u8 command[14] = {
709                 0x00, 0xc2,             /* TPM_TAG */
710                 0x00, 0x00, 0x00, 0x00, /* parameter size */
711                 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
712                 0x00, 0x00, 0x00, 0x00, /* key handle */
713         };
714         const size_t req_size_offset = 2;
715         const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
716         const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
717         u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
718         u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
719                     TPM_RESPONSE_AUTH_LENGTH];
720         size_t response_length = sizeof(response);
721         u32 err;
722
723         if (!oiap_session.valid) {
724                 err = tpm_oiap(NULL);
725                 if (err)
726                         return err;
727         }
728         if (pack_byte_string(request, sizeof(request), "sdd",
729                              0, command, sizeof(command),
730                              req_size_offset,
731                              (u32)(sizeof(command)
732                              + TPM_REQUEST_AUTH_LENGTH),
733                              req_key_handle_offset, key_handle
734                 ))
735                 return TPM_LIB_ERROR;
736         err = create_request_auth(request, sizeof(command), 4, &oiap_session,
737                                   request + sizeof(command), usage_auth);
738         if (err)
739                 return err;
740         err = tpm_sendrecv_command(request, response, &response_length);
741         if (err) {
742                 if (err == TPM_AUTHFAIL)
743                         oiap_session.valid = 0;
744                 return err;
745         }
746         err = verify_response_auth(0x00000021, response,
747                                    response_length - TPM_RESPONSE_AUTH_LENGTH,
748                                    0, &oiap_session,
749                                    response + response_length -
750                                    TPM_RESPONSE_AUTH_LENGTH,
751                                    usage_auth);
752         if (err)
753                 return err;
754
755         if (pubkey) {
756                 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
757                      - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
758                         return TPM_LIB_ERROR;
759                 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
760                         - TPM_RESPONSE_AUTH_LENGTH;
761                 memcpy(pubkey, response + res_pubkey_offset,
762                        response_length - TPM_RESPONSE_HEADER_LENGTH
763                        - TPM_RESPONSE_AUTH_LENGTH);
764         }
765
766         return 0;
767 }
768
769 #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
770 u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20],
771                       u32 *handle)
772 {
773         u16 key_count;
774         u32 key_handles[10];
775         u8 buf[288];
776         u8 *ptr;
777         u32 err;
778         u8 digest[20];
779         size_t buf_len;
780         unsigned int i;
781
782         /* fetch list of already loaded keys in the TPM */
783         err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
784         if (err)
785                 return -1;
786         key_count = get_unaligned_be16(buf);
787         ptr = buf + 2;
788         for (i = 0; i < key_count; ++i, ptr += 4)
789                 key_handles[i] = get_unaligned_be32(ptr);
790
791         /* now search a(/ the) key which we can access with the given auth */
792         for (i = 0; i < key_count; ++i) {
793                 buf_len = sizeof(buf);
794                 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
795                 if (err && err != TPM_AUTHFAIL)
796                         return -1;
797                 if (err)
798                         continue;
799                 sha1_csum(buf, buf_len, digest);
800                 if (!memcmp(digest, pubkey_digest, 20)) {
801                         *handle = key_handles[i];
802                         return 0;
803                 }
804         }
805         return 1;
806 }
807 #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
808
809 #endif /* CONFIG_TPM_AUTH_SESSIONS */
810
811 u32 tpm_get_random(void *data, u32 count)
812 {
813         const u8 command[14] = {
814                 0x0, 0xc1,              /* TPM_TAG */
815                 0x0, 0x0, 0x0, 0xe,     /* parameter size */
816                 0x0, 0x0, 0x0, 0x46,    /* TPM_COMMAND_CODE */
817         };
818         const size_t length_offset = 10;
819         const size_t data_size_offset = 10;
820         const size_t data_offset = 14;
821         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
822         size_t response_length = sizeof(response);
823         u32 data_size;
824         u8 *out = data;
825
826         while (count > 0) {
827                 u32 this_bytes = min((size_t)count,
828                                      sizeof(response) - data_offset);
829                 u32 err;
830
831                 if (pack_byte_string(buf, sizeof(buf), "sd",
832                                      0, command, sizeof(command),
833                                      length_offset, this_bytes))
834                         return TPM_LIB_ERROR;
835                 err = tpm_sendrecv_command(buf, response, &response_length);
836                 if (err)
837                         return err;
838                 if (unpack_byte_string(response, response_length, "d",
839                                        data_size_offset, &data_size))
840                         return TPM_LIB_ERROR;
841                 if (data_size > count)
842                         return TPM_LIB_ERROR;
843                 if (unpack_byte_string(response, response_length, "s",
844                                        data_offset, out, data_size))
845                         return TPM_LIB_ERROR;
846
847                 count -= data_size;
848                 out += data_size;
849         }
850
851         return 0;
852 }