tlcl: implement clear, startup, shutdown, self test
[vboot.git] / firmware / lib / tpm2_lite / marshaling.c
1 /*
2  * Copyright 2016 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include "tpm2_marshaling.h"
8 #include "utility.h"
9
10 static uint16_t tpm_tag;  /* Depends on the command type. */
11 static int ph_disabled;   /* Platform hierarchy disabled. */
12
13 static void write_be16(void *dest, uint16_t val)
14 {
15         uint8_t *byte_dest = dest;
16
17         byte_dest[0] = val >> 8;
18         byte_dest[1] = val;
19 }
20
21 static void write_be32(void *dest, uint32_t val)
22 {
23         uint8_t *byte_dest = dest;
24
25         byte_dest[0] = val >> 24;
26         byte_dest[1] = val >> 16;
27         byte_dest[2] = val >> 8;
28         byte_dest[3] = val;
29 }
30
31 static uint16_t read_be16(const void *src)
32 {
33         const uint8_t *s = src;
34         return (((uint16_t)s[0]) << 8) | (((uint16_t)s[1]) << 0);
35 }
36
37 static inline uint32_t read_be32(const void *src)
38 {
39         const uint8_t *s = src;
40
41         return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) |
42                 (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0);
43 }
44
45 /*
46  * Each unmarshaling function receives a pointer to the buffer pointer and a
47  * pointer to the size of data still in the buffer. The function extracts data
48  * from the buffer and adjusts both buffer pointer and remaining data size.
49  *
50  * Should there be not enough data in the buffer to unmarshal the required
51  * object, the remaining data size is set to -1 to indicate the error. The
52  * remaining data size is expected to be set to zero once the last data item
53  * has been extracted from the buffer.
54  */
55
56 static uint8_t unmarshal_u8(void **buffer, int *buffer_space)
57 {
58         uint8_t value;
59
60         if (*buffer_space < sizeof(value)) {
61                 *buffer_space = -1; /* Indicate a failure. */
62                 return 0;
63         }
64
65         value = *(uint8_t *)(*buffer);
66         *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
67         *buffer_space -= sizeof(value);
68
69         return value;
70 }
71
72 static uint16_t unmarshal_u16(void **buffer, int *buffer_space)
73 {
74         uint16_t value;
75
76         if (*buffer_space < sizeof(value)) {
77                 *buffer_space = -1; /* Indicate a failure. */
78                 return 0;
79         }
80
81         value = read_be16(*buffer);
82         *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
83         *buffer_space -= sizeof(value);
84
85         return value;
86 }
87
88 static uint32_t unmarshal_u32(void **buffer, int *buffer_space)
89 {
90         uint32_t value;
91
92         if (*buffer_space < sizeof(value)) {
93                 *buffer_space = -1; /* Indicate a failure. */
94                 return 0;
95         }
96
97         value = read_be32(*buffer);
98         *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
99         *buffer_space -= sizeof(value);
100
101         return value;
102 }
103
104 static void unmarshal_TPM2B_MAX_NV_BUFFER(void **buffer,
105                                           int *size,
106                                           TPM2B_MAX_NV_BUFFER *nv_buffer)
107 {
108         nv_buffer->t.size = unmarshal_u16(buffer, size);
109         if (nv_buffer->t.size > *size) {
110                 VBDEBUG(("%s:%d - "
111                        "size mismatch: expected %d, remaining %d\n",
112                          __func__, __LINE__, nv_buffer->t.size, *size));
113                 return;
114         }
115
116         nv_buffer->t.buffer = *buffer;
117
118         *buffer = ((uint8_t *)(*buffer)) + nv_buffer->t.size;
119         *size -= nv_buffer->t.size;
120 }
121
122 static void unmarshal_authorization_section(void **buffer, int *size,
123                                             char *cmd_name)
124 {
125         /*
126          * Let's ignore the authorisation section. It should be 5 bytes total,
127          * just confirm that this is the case and report any discrepancy.
128          */
129         if (*size != 5)
130                 VBDEBUG(("%s:%d - unexpected authorisation section size %d "
131                          "for %s\n",
132                          __func__, __LINE__, *size, cmd_name));
133
134         *buffer = ((uint8_t *)(*buffer)) + *size;
135         *size = 0;
136 }
137
138 static void unmarshal_nv_read(void **buffer, int *size,
139                               struct nv_read_response *nvr)
140 {
141         /* Total size of the parameter field. */
142         nvr->params_size = unmarshal_u32(buffer, size);
143         unmarshal_TPM2B_MAX_NV_BUFFER(buffer, size, &nvr->buffer);
144
145         if (nvr->params_size !=
146             (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
147                 VBDEBUG(("%s:%d - parameter/buffer %d/%d size mismatch",
148                          __func__, __LINE__, nvr->params_size,
149                          nvr->buffer.t.size));
150                 return;
151         }
152
153         if (*size < 0)
154                 return;
155
156         unmarshal_authorization_section(buffer, size, "NV_Read");
157 }
158
159 static void unmarshal_TPML_TAGGED_TPM_PROPERTY(void **buffer, int *size,
160                                                TPML_TAGGED_TPM_PROPERTY *prop)
161 {
162         prop->count = unmarshal_u32(buffer, size);
163
164         if (prop->count != 1) {
165                 *size = -1;
166                 VBDEBUG(("%s:%d:Request to unmarshal unsupported "
167                          "number of properties: %u\n",
168                          __FILE__, __LINE__, prop->count));
169                 return;
170         }
171
172         prop->tpm_property[0].property = unmarshal_u32(buffer, size);
173         prop->tpm_property[0].value = unmarshal_u32(buffer, size);
174 }
175
176 static void unmarshal_TPMS_CAPABILITY_DATA(void **buffer, int *size,
177                                            TPMS_CAPABILITY_DATA *cap_data)
178 {
179         cap_data->capability = unmarshal_u32(buffer, size);
180
181         switch (cap_data->capability) {
182
183         case TPM_CAP_TPM_PROPERTIES:
184                 unmarshal_TPML_TAGGED_TPM_PROPERTY(buffer, size,
185                                                    &cap_data->data.
186                                                        tpm_properties);
187                 break;
188
189         default:
190                 *size = -1;
191                 VBDEBUG(("%s:%d:Request to unmarshal unsupported "
192                          "capability %#x\n",
193                          __FILE__, __LINE__, cap_data->capability));
194         }
195 }
196
197 static void unmarshal_get_capability(void **buffer, int *size,
198                                      struct get_capability_response *cap)
199 {
200         /* Total size of the parameter field. */
201         cap->more_data = unmarshal_u8(buffer, size);
202         unmarshal_TPMS_CAPABILITY_DATA(buffer, size, &cap->capability_data);
203 }
204
205
206 /*
207  * Each marshaling function receives a pointer to the buffer to marshal into,
208  * a pointer to the data item to be marshaled, and a pointer to the remaining
209  * room in the buffer.
210  */
211
212  /*
213   * Marshaling an arbitrary blob requires its size in addition to common
214   * parameter set.
215   */
216 static void marshal_blob(void **buffer, void *blob,
217                          size_t blob_size, int *buffer_space)
218 {
219         if (*buffer_space < blob_size) {
220                 *buffer_space = -1;
221                 return;
222         }
223
224         Memcpy(*buffer, blob, blob_size);
225         buffer_space -= blob_size;
226         *buffer = (void *)((uintptr_t)(*buffer) + blob_size);
227 }
228
229 static void marshal_u8(void **buffer, uint8_t value, int *buffer_space)
230 {
231         uint8_t *bp = *buffer;
232
233         if (*buffer_space < sizeof(value)) {
234                 *buffer_space = -1;
235                 return;
236         }
237
238         *bp++ = value;
239         *buffer = bp;
240         *buffer_space -= sizeof(value);
241 }
242
243 static void marshal_u16(void **buffer, uint16_t value, int *buffer_space)
244 {
245         if (*buffer_space < sizeof(value)) {
246                 *buffer_space = -1;
247                 return;
248         }
249         write_be16(*buffer, value);
250         *buffer = (void *)((uintptr_t)(*buffer) + sizeof(value));
251         *buffer_space -= sizeof(value);
252 }
253
254 static void marshal_u32(void **buffer, uint32_t value, int *buffer_space)
255 {
256         if (*buffer_space < sizeof(value)) {
257                 *buffer_space = -1;
258                 return;
259         }
260
261         write_be32(*buffer, value);
262         *buffer = (void *)((uintptr_t)(*buffer) + sizeof(value));
263         *buffer_space -= sizeof(value);
264 }
265
266 #define unmarshal_TPM_CC(a, b) unmarshal_u32(a, b)
267 #define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
268 #define marshal_TPM_SU(a, b, c) marshal_u16(a, b, c)
269
270 static void marshal_session_header(void **buffer,
271                                    struct tpm2_session_header *session_header,
272                                    int *buffer_space)
273 {
274         int base_size;
275         void *size_location = *buffer;
276
277         /* Skip room for the session header size. */
278         *buffer_space -= sizeof(uint32_t);
279         *buffer = (void *)(((uintptr_t) *buffer) + sizeof(uint32_t));
280
281         base_size = *buffer_space;
282
283         marshal_u32(buffer, session_header->session_handle, buffer_space);
284         marshal_u16(buffer, session_header->nonce_size, buffer_space);
285         marshal_blob(buffer, session_header->nonce,
286                      session_header->nonce_size, buffer_space);
287         marshal_u8(buffer, session_header->session_attrs, buffer_space);
288         marshal_u16(buffer, session_header->auth_size, buffer_space);
289         marshal_blob(buffer, session_header->auth,
290                      session_header->auth_size, buffer_space);
291
292         if (*buffer_space < 0)
293                 return;  /* The structure did not fit. */
294
295         /* Paste in the session size. */
296         marshal_u32(&size_location, base_size - *buffer_space, &base_size);
297 }
298
299 static void marshal_TPM2B(void **buffer,
300                           TPM2B *data,
301                           int *buffer_space)
302 {
303         size_t total_size = data->size + sizeof(data->size);
304
305         if (total_size > *buffer_space) {
306                 *buffer_space = -1;
307                 return;
308         }
309         marshal_u16(buffer, data->size, buffer_space);
310         Memcpy(*buffer, data->buffer, data->size);
311         *buffer = ((uint8_t *)(*buffer)) + data->size;
312         *buffer_space -= data->size;
313 }
314
315 static void marshal_nv_write(void **buffer,
316                              struct tpm2_nv_write_cmd *command_body,
317                              int *buffer_space)
318 {
319         struct tpm2_session_header session_header;
320
321         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
322         marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
323         Memset(&session_header, 0, sizeof(session_header));
324         session_header.session_handle = TPM_RS_PW;
325         marshal_session_header(buffer, &session_header, buffer_space);
326         tpm_tag = TPM_ST_SESSIONS;
327
328         marshal_TPM2B(buffer, &command_body->data.b, buffer_space);
329         marshal_u16(buffer, command_body->offset, buffer_space);
330 }
331
332 static void marshal_nv_read(void **buffer,
333                             struct tpm2_nv_read_cmd *command_body,
334                             int *buffer_space)
335 {
336         struct tpm2_session_header session_header;
337
338         /* Use empty password auth if platform hierarchy is disabled */
339         if (ph_disabled)
340                 marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
341         else
342                 marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
343         marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
344         Memset(&session_header, 0, sizeof(session_header));
345         session_header.session_handle = TPM_RS_PW;
346         marshal_session_header(buffer, &session_header, buffer_space);
347         tpm_tag = TPM_ST_SESSIONS;
348         marshal_u16(buffer, command_body->size, buffer_space);
349         marshal_u16(buffer, command_body->offset, buffer_space);
350 }
351
352 static void marshal_nv_write_lock(void **buffer,
353                                   struct tpm2_nv_write_lock_cmd *command_body,
354                                   int *buffer_space)
355 {
356         struct tpm2_session_header session_header;
357
358         tpm_tag = TPM_ST_SESSIONS;
359         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
360         marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
361         Memset(&session_header, 0, sizeof(session_header));
362         session_header.session_handle = TPM_RS_PW;
363         marshal_session_header(buffer, &session_header, buffer_space);
364 }
365
366 static void marshal_hierarchy_control(void **buffer,
367                                       struct tpm2_hierarchy_control_cmd
368                                           *command_body,
369                                       int *buffer_space)
370 {
371         struct tpm2_session_header session_header;
372
373         tpm_tag = TPM_ST_SESSIONS;
374         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
375         Memset(&session_header, 0, sizeof(session_header));
376         session_header.session_handle = TPM_RS_PW;
377         marshal_session_header(buffer, &session_header, buffer_space);
378
379         marshal_TPM_HANDLE(buffer, command_body->enable, buffer_space);
380         marshal_u8(buffer, command_body->state, buffer_space);
381 }
382
383 static void marshal_get_capability(void **buffer,
384                                    struct tpm2_get_capability_cmd
385                                        *command_body,
386                                    int *buffer_space)
387 {
388         tpm_tag = TPM_ST_NO_SESSIONS;
389
390         marshal_u32(buffer, command_body->capability, buffer_space);
391         marshal_u32(buffer, command_body->property, buffer_space);
392         marshal_u32(buffer, command_body->property_count, buffer_space);
393 }
394
395 static void marshal_clear(void **buffer,
396                           void *command_body,
397                           int *buffer_space)
398 {
399         struct tpm2_session_header session_header;
400
401         tpm_tag = TPM_ST_SESSIONS;
402         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
403         Memset(&session_header, 0, sizeof(session_header));
404         session_header.session_handle = TPM_RS_PW;
405         marshal_session_header(buffer, &session_header, buffer_space);
406 }
407
408 static void marshal_self_test(void **buffer,
409                               struct tpm2_self_test_cmd *command_body,
410                               int *buffer_space)
411 {
412         tpm_tag = TPM_ST_NO_SESSIONS;
413
414         marshal_u8(buffer, command_body->full_test, buffer_space);
415 }
416
417 static void marshal_startup(void **buffer,
418                             struct tpm2_startup_cmd *command_body,
419                             int *buffer_space)
420 {
421         tpm_tag = TPM_ST_NO_SESSIONS;
422
423         marshal_TPM_SU(buffer, command_body->startup_type, buffer_space);
424 }
425
426 static void marshal_shutdown(void **buffer,
427                              struct tpm2_shutdown_cmd *command_body,
428                              int *buffer_space)
429 {
430         tpm_tag = TPM_ST_NO_SESSIONS;
431
432         marshal_TPM_SU(buffer, command_body->shutdown_type, buffer_space);
433 }
434
435 int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
436                         void *buffer, int buffer_size)
437 {
438         void *cmd_body = (uint8_t *)buffer + sizeof(struct tpm_header);
439         int max_body_size = buffer_size - sizeof(struct tpm_header);
440         int body_size = max_body_size;
441
442         /* Will be modified when marshaling some commands. */
443         tpm_tag = TPM_ST_NO_SESSIONS;
444
445         switch (command) {
446
447         case TPM2_NV_Read:
448                 marshal_nv_read(&cmd_body, tpm_command_body, &body_size);
449                 break;
450
451         case TPM2_NV_Write:
452                 marshal_nv_write(&cmd_body, tpm_command_body, &body_size);
453                 break;
454
455         case TPM2_NV_WriteLock:
456                 marshal_nv_write_lock(&cmd_body, tpm_command_body, &body_size);
457                 break;
458
459         case TPM2_Hierarchy_Control:
460                 marshal_hierarchy_control(&cmd_body,
461                                           tpm_command_body, &body_size);
462                 break;
463
464         case TPM2_GetCapability:
465                 marshal_get_capability(&cmd_body, tpm_command_body, &body_size);
466                 break;
467
468         case TPM2_Clear:
469                 marshal_clear(&cmd_body, tpm_command_body, &body_size);
470                 break;
471
472         case TPM2_SelfTest:
473                 marshal_self_test(&cmd_body, tpm_command_body, &body_size);
474                 break;
475
476         case TPM2_Startup:
477                 marshal_startup(&cmd_body, tpm_command_body, &body_size);
478                 break;
479
480         case TPM2_Shutdown:
481                 marshal_shutdown(&cmd_body, tpm_command_body, &body_size);
482                 break;
483
484         default:
485                 body_size = -1;
486                 VBDEBUG(("%s:%d:Request to marshal unsupported command %#x\n",
487                          __FILE__, __LINE__, command));
488         }
489
490         if (body_size > 0) {
491
492                 /* See how much room was taken by marshaling. */
493                 body_size = max_body_size - body_size;
494
495                 body_size += sizeof(struct tpm_header);
496
497                 marshal_u16(&buffer, tpm_tag, &max_body_size);
498                 marshal_u32(&buffer, body_size, &max_body_size);
499                 marshal_u32(&buffer, command, &max_body_size);
500         }
501
502         return body_size;
503 }
504
505 struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
506                                              void *response_body,
507                                              int cr_size)
508 {
509         static struct tpm2_response tpm2_resp;
510
511         if (cr_size < sizeof(struct tpm_header))
512                 return NULL;
513
514         tpm2_resp.hdr.tpm_tag = unmarshal_u16(&response_body, &cr_size);
515         tpm2_resp.hdr.tpm_size = unmarshal_u32(&response_body, &cr_size);
516         tpm2_resp.hdr.tpm_code = unmarshal_TPM_CC(&response_body, &cr_size);
517
518         if (!cr_size) {
519                 if (tpm2_resp.hdr.tpm_size != sizeof(tpm2_resp.hdr))
520                         VBDEBUG(("%s: size mismatch in response to command %#x\n",
521                                  __func__, command));
522                 return &tpm2_resp;
523         }
524
525         switch (command) {
526         case TPM2_NV_Read:
527                 unmarshal_nv_read(&response_body, &cr_size,
528                                   &tpm2_resp.nvr);
529                 break;
530
531         case TPM2_GetCapability:
532                 unmarshal_get_capability(&response_body, &cr_size,
533                                          &tpm2_resp.cap);
534                 break;
535
536         case TPM2_Hierarchy_Control:
537         case TPM2_NV_Write:
538         case TPM2_NV_WriteLock:
539         case TPM2_Clear:
540         case TPM2_SelfTest:
541         case TPM2_Startup:
542         case TPM2_Shutdown:
543                 /* Session data included in response can be safely ignored. */
544                 cr_size = 0;
545                 break;
546
547         default:
548                 {
549                         int i;
550
551                         VBDEBUG(("%s:%d:"
552                                "Request to unmarshal unexpected command %#x,"
553                                " code %#x",
554                                __func__, __LINE__, command,
555                                  tpm2_resp.hdr.tpm_code));
556
557                         for (i = 0; i < cr_size; i++) {
558                                 if (!(i % 16))
559                                         VBDEBUG(("\n"));
560                                 VBDEBUG(("%2.2x ",
561                                          ((uint8_t *)response_body)[i]));
562                         }
563                 }
564                 VBDEBUG(("\n"));
565                 return NULL;
566         }
567
568         if (cr_size) {
569                 VBDEBUG(("%s:%d got %d bytes back in response to %#x,"
570                          " failed to parse (%d)\n",
571                          __func__, __LINE__, tpm2_resp.hdr.tpm_size,
572                          command, cr_size));
573                 return NULL;
574         }
575
576         /* The entire message have been parsed. */
577         return &tpm2_resp;
578 }
579
580 uint32_t tpm_get_packet_size(const uint8_t *packet)
581 {
582         /* 0: tag (16 bit)
583          * 2: size (32 bit)
584          */
585         return read_be32(packet + 2);
586 }
587
588 uint32_t tpm_get_packet_response_code(const uint8_t *packet)
589 {
590         /* 0: tag (16 bit)
591          * 2: size (32 bit)
592          * 6: resp code (32 bit)
593          */
594         return read_be32(packet + 6);
595 }
596
597 void tpm_set_ph_disabled(int flag)
598 {
599         ph_disabled = flag;
600 }
601
602 int tpm_is_ph_disabled(void)
603 {
604         return ph_disabled;
605 }