Modify 'tpmc block' to lock only the FW index
[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
269 static void marshal_session_header(void **buffer,
270                                    struct tpm2_session_header *session_header,
271                                    int *buffer_space)
272 {
273         int base_size;
274         void *size_location = *buffer;
275
276         /* Skip room for the session header size. */
277         *buffer_space -= sizeof(uint32_t);
278         *buffer = (void *)(((uintptr_t) *buffer) + sizeof(uint32_t));
279
280         base_size = *buffer_space;
281
282         marshal_u32(buffer, session_header->session_handle, buffer_space);
283         marshal_u16(buffer, session_header->nonce_size, buffer_space);
284         marshal_blob(buffer, session_header->nonce,
285                      session_header->nonce_size, buffer_space);
286         marshal_u8(buffer, session_header->session_attrs, buffer_space);
287         marshal_u16(buffer, session_header->auth_size, buffer_space);
288         marshal_blob(buffer, session_header->auth,
289                      session_header->auth_size, buffer_space);
290
291         if (*buffer_space < 0)
292                 return;  /* The structure did not fit. */
293
294         /* Paste in the session size. */
295         marshal_u32(&size_location, base_size - *buffer_space, &base_size);
296 }
297
298 static void marshal_TPM2B(void **buffer,
299                           TPM2B *data,
300                           int *buffer_space)
301 {
302         size_t total_size = data->size + sizeof(data->size);
303
304         if (total_size > *buffer_space) {
305                 *buffer_space = -1;
306                 return;
307         }
308         marshal_u16(buffer, data->size, buffer_space);
309         Memcpy(*buffer, data->buffer, data->size);
310         *buffer = ((uint8_t *)(*buffer)) + data->size;
311         *buffer_space -= data->size;
312 }
313
314 static void marshal_nv_write(void **buffer,
315                              struct tpm2_nv_write_cmd *command_body,
316                              int *buffer_space)
317 {
318         struct tpm2_session_header session_header;
319
320         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
321         marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
322         Memset(&session_header, 0, sizeof(session_header));
323         session_header.session_handle = TPM_RS_PW;
324         marshal_session_header(buffer, &session_header, buffer_space);
325         tpm_tag = TPM_ST_SESSIONS;
326
327         marshal_TPM2B(buffer, &command_body->data.b, buffer_space);
328         marshal_u16(buffer, command_body->offset, buffer_space);
329 }
330
331 static void marshal_nv_read(void **buffer,
332                             struct tpm2_nv_read_cmd *command_body,
333                             int *buffer_space)
334 {
335         struct tpm2_session_header session_header;
336
337         /* Use empty password auth if platform hierarchy is disabled */
338         if (ph_disabled)
339                 marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
340         else
341                 marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
342         marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
343         Memset(&session_header, 0, sizeof(session_header));
344         session_header.session_handle = TPM_RS_PW;
345         marshal_session_header(buffer, &session_header, buffer_space);
346         tpm_tag = TPM_ST_SESSIONS;
347         marshal_u16(buffer, command_body->size, buffer_space);
348         marshal_u16(buffer, command_body->offset, buffer_space);
349 }
350
351 static void marshal_nv_write_lock(void **buffer,
352                                   struct tpm2_nv_write_lock_cmd *command_body,
353                                   int *buffer_space)
354 {
355         struct tpm2_session_header session_header;
356
357         tpm_tag = TPM_ST_SESSIONS;
358         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
359         marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
360         Memset(&session_header, 0, sizeof(session_header));
361         session_header.session_handle = TPM_RS_PW;
362         marshal_session_header(buffer, &session_header, buffer_space);
363 }
364
365 static void marshal_hierarchy_control(void **buffer,
366                                       struct tpm2_hierarchy_control_cmd
367                                           *command_body,
368                                       int *buffer_space)
369 {
370         struct tpm2_session_header session_header;
371
372         tpm_tag = TPM_ST_SESSIONS;
373         marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
374         Memset(&session_header, 0, sizeof(session_header));
375         session_header.session_handle = TPM_RS_PW;
376         marshal_session_header(buffer, &session_header, buffer_space);
377
378         marshal_TPM_HANDLE(buffer, command_body->enable, buffer_space);
379         marshal_u8(buffer, command_body->state, buffer_space);
380 }
381
382 static void marshal_get_capability(void **buffer,
383                                    struct tpm2_get_capability_cmd
384                                        *command_body,
385                                    int *buffer_space)
386 {
387         tpm_tag = TPM_ST_NO_SESSIONS;
388
389         marshal_u32(buffer, command_body->capability, buffer_space);
390         marshal_u32(buffer, command_body->property, buffer_space);
391         marshal_u32(buffer, command_body->property_count, buffer_space);
392 }
393
394 int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
395                         void *buffer, int buffer_size)
396 {
397         void *cmd_body = (uint8_t *)buffer + sizeof(struct tpm_header);
398         int max_body_size = buffer_size - sizeof(struct tpm_header);
399         int body_size = max_body_size;
400
401         /* Will be modified when marshaling some commands. */
402         tpm_tag = TPM_ST_NO_SESSIONS;
403
404         switch (command) {
405
406         case TPM2_NV_Read:
407                 marshal_nv_read(&cmd_body, tpm_command_body, &body_size);
408                 break;
409
410         case TPM2_NV_Write:
411                 marshal_nv_write(&cmd_body, tpm_command_body, &body_size);
412                 break;
413
414         case TPM2_NV_WriteLock:
415                 marshal_nv_write_lock(&cmd_body, tpm_command_body, &body_size);
416                 break;
417
418         case TPM2_Hierarchy_Control:
419                 marshal_hierarchy_control(&cmd_body,
420                                           tpm_command_body, &body_size);
421                 break;
422
423         case TPM2_GetCapability:
424                 marshal_get_capability(&cmd_body, tpm_command_body, &body_size);
425                 break;
426
427         default:
428                 body_size = -1;
429                 VBDEBUG(("%s:%d:Request to marshal unsupported command %#x\n",
430                          __FILE__, __LINE__, command));
431         }
432
433         if (body_size > 0) {
434
435                 /* See how much room was taken by marshaling. */
436                 body_size = max_body_size - body_size;
437
438                 body_size += sizeof(struct tpm_header);
439
440                 marshal_u16(&buffer, tpm_tag, &max_body_size);
441                 marshal_u32(&buffer, body_size, &max_body_size);
442                 marshal_u32(&buffer, command, &max_body_size);
443         }
444
445         return body_size;
446 }
447
448 struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
449                                              void *response_body,
450                                              int cr_size)
451 {
452         static struct tpm2_response tpm2_resp;
453
454         if (cr_size < sizeof(struct tpm_header))
455                 return NULL;
456
457         tpm2_resp.hdr.tpm_tag = unmarshal_u16(&response_body, &cr_size);
458         tpm2_resp.hdr.tpm_size = unmarshal_u32(&response_body, &cr_size);
459         tpm2_resp.hdr.tpm_code = unmarshal_TPM_CC(&response_body, &cr_size);
460
461         if (!cr_size) {
462                 if (tpm2_resp.hdr.tpm_size != sizeof(tpm2_resp.hdr))
463                         VBDEBUG(("%s: size mismatch in response to command %#x\n",
464                                  __func__, command));
465                 return &tpm2_resp;
466         }
467
468         switch (command) {
469         case TPM2_NV_Read:
470                 unmarshal_nv_read(&response_body, &cr_size,
471                                   &tpm2_resp.nvr);
472                 break;
473
474         case TPM2_GetCapability:
475                 unmarshal_get_capability(&response_body, &cr_size,
476                                          &tpm2_resp.cap);
477                 break;
478
479         case TPM2_Hierarchy_Control:
480         case TPM2_NV_Write:
481         case TPM2_NV_WriteLock:
482                 /* Session data included in response can be safely ignored. */
483                 cr_size = 0;
484                 break;
485
486         default:
487                 {
488                         int i;
489
490                         VBDEBUG(("%s:%d:"
491                                "Request to unmarshal unexpected command %#x,"
492                                " code %#x",
493                                __func__, __LINE__, command,
494                                  tpm2_resp.hdr.tpm_code));
495
496                         for (i = 0; i < cr_size; i++) {
497                                 if (!(i % 16))
498                                         VBDEBUG(("\n"));
499                                 VBDEBUG(("%2.2x ",
500                                          ((uint8_t *)response_body)[i]));
501                         }
502                 }
503                 VBDEBUG(("\n"));
504                 return NULL;
505         }
506
507         if (cr_size) {
508                 VBDEBUG(("%s:%d got %d bytes back in response to %#x,"
509                          " failed to parse (%d)\n",
510                          __func__, __LINE__, tpm2_resp.hdr.tpm_size,
511                          command, cr_size));
512                 return NULL;
513         }
514
515         /* The entire message have been parsed. */
516         return &tpm2_resp;
517 }
518
519 void tpm_set_ph_disabled(int flag)
520 {
521         ph_disabled = flag;
522 }
523
524 int tpm_is_ph_disabled(void)
525 {
526         return ph_disabled;
527 }