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.
7 #include "tpm2_marshaling.h"
10 static uint16_t tpm_tag; /* Depends on the command type. */
11 static int ph_disabled; /* Platform hierarchy disabled. */
13 static void write_be16(void *dest, uint16_t val)
15 uint8_t *byte_dest = dest;
17 byte_dest[0] = val >> 8;
21 static void write_be32(void *dest, uint32_t val)
23 uint8_t *byte_dest = dest;
25 byte_dest[0] = val >> 24;
26 byte_dest[1] = val >> 16;
27 byte_dest[2] = val >> 8;
31 static uint16_t read_be16(const void *src)
33 const uint8_t *s = src;
34 return (((uint16_t)s[0]) << 8) | (((uint16_t)s[1]) << 0);
37 static inline uint32_t read_be32(const void *src)
39 const uint8_t *s = src;
41 return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) |
42 (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0);
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.
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.
56 static uint8_t unmarshal_u8(void **buffer, int *buffer_space)
60 if (*buffer_space < sizeof(value)) {
61 *buffer_space = -1; /* Indicate a failure. */
65 value = *(uint8_t *)(*buffer);
66 *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
67 *buffer_space -= sizeof(value);
72 static uint16_t unmarshal_u16(void **buffer, int *buffer_space)
76 if (*buffer_space < sizeof(value)) {
77 *buffer_space = -1; /* Indicate a failure. */
81 value = read_be16(*buffer);
82 *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
83 *buffer_space -= sizeof(value);
88 static uint32_t unmarshal_u32(void **buffer, int *buffer_space)
92 if (*buffer_space < sizeof(value)) {
93 *buffer_space = -1; /* Indicate a failure. */
97 value = read_be32(*buffer);
98 *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
99 *buffer_space -= sizeof(value);
104 static void unmarshal_TPM2B_MAX_NV_BUFFER(void **buffer,
106 TPM2B_MAX_NV_BUFFER *nv_buffer)
108 nv_buffer->t.size = unmarshal_u16(buffer, size);
109 if (nv_buffer->t.size > *size) {
111 "size mismatch: expected %d, remaining %d\n",
112 __func__, __LINE__, nv_buffer->t.size, *size));
116 nv_buffer->t.buffer = *buffer;
118 *buffer = ((uint8_t *)(*buffer)) + nv_buffer->t.size;
119 *size -= nv_buffer->t.size;
122 static void unmarshal_authorization_section(void **buffer, int *size,
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.
130 VBDEBUG(("%s:%d - unexpected authorisation section size %d "
132 __func__, __LINE__, *size, cmd_name));
134 *buffer = ((uint8_t *)(*buffer)) + *size;
138 static void unmarshal_nv_read(void **buffer, int *size,
139 struct nv_read_response *nvr)
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);
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));
156 unmarshal_authorization_section(buffer, size, "NV_Read");
159 static void unmarshal_TPML_TAGGED_TPM_PROPERTY(void **buffer, int *size,
160 TPML_TAGGED_TPM_PROPERTY *prop)
162 prop->count = unmarshal_u32(buffer, size);
164 if (prop->count != 1) {
166 VBDEBUG(("%s:%d:Request to unmarshal unsupported "
167 "number of properties: %u\n",
168 __FILE__, __LINE__, prop->count));
172 prop->tpm_property[0].property = unmarshal_u32(buffer, size);
173 prop->tpm_property[0].value = unmarshal_u32(buffer, size);
176 static void unmarshal_TPMS_CAPABILITY_DATA(void **buffer, int *size,
177 TPMS_CAPABILITY_DATA *cap_data)
179 cap_data->capability = unmarshal_u32(buffer, size);
181 switch (cap_data->capability) {
183 case TPM_CAP_TPM_PROPERTIES:
184 unmarshal_TPML_TAGGED_TPM_PROPERTY(buffer, size,
191 VBDEBUG(("%s:%d:Request to unmarshal unsupported "
193 __FILE__, __LINE__, cap_data->capability));
197 static void unmarshal_get_capability(void **buffer, int *size,
198 struct get_capability_response *cap)
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);
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.
213 * Marshaling an arbitrary blob requires its size in addition to common
216 static void marshal_blob(void **buffer, void *blob,
217 size_t blob_size, int *buffer_space)
219 if (*buffer_space < blob_size) {
224 Memcpy(*buffer, blob, blob_size);
225 buffer_space -= blob_size;
226 *buffer = (void *)((uintptr_t)(*buffer) + blob_size);
229 static void marshal_u8(void **buffer, uint8_t value, int *buffer_space)
231 uint8_t *bp = *buffer;
233 if (*buffer_space < sizeof(value)) {
240 *buffer_space -= sizeof(value);
243 static void marshal_u16(void **buffer, uint16_t value, int *buffer_space)
245 if (*buffer_space < sizeof(value)) {
249 write_be16(*buffer, value);
250 *buffer = (void *)((uintptr_t)(*buffer) + sizeof(value));
251 *buffer_space -= sizeof(value);
254 static void marshal_u32(void **buffer, uint32_t value, int *buffer_space)
256 if (*buffer_space < sizeof(value)) {
261 write_be32(*buffer, value);
262 *buffer = (void *)((uintptr_t)(*buffer) + sizeof(value));
263 *buffer_space -= sizeof(value);
266 #define unmarshal_TPM_CC(a, b) unmarshal_u32(a, b)
267 #define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
269 static void marshal_session_header(void **buffer,
270 struct tpm2_session_header *session_header,
274 void *size_location = *buffer;
276 /* Skip room for the session header size. */
277 *buffer_space -= sizeof(uint32_t);
278 *buffer = (void *)(((uintptr_t) *buffer) + sizeof(uint32_t));
280 base_size = *buffer_space;
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);
291 if (*buffer_space < 0)
292 return; /* The structure did not fit. */
294 /* Paste in the session size. */
295 marshal_u32(&size_location, base_size - *buffer_space, &base_size);
298 static void marshal_TPM2B(void **buffer,
302 size_t total_size = data->size + sizeof(data->size);
304 if (total_size > *buffer_space) {
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;
314 static void marshal_nv_write(void **buffer,
315 struct tpm2_nv_write_cmd *command_body,
318 struct tpm2_session_header session_header;
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;
327 marshal_TPM2B(buffer, &command_body->data.b, buffer_space);
328 marshal_u16(buffer, command_body->offset, buffer_space);
331 static void marshal_nv_read(void **buffer,
332 struct tpm2_nv_read_cmd *command_body,
335 struct tpm2_session_header session_header;
337 /* Use empty password auth if platform hierarchy is disabled */
339 marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
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);
351 static void marshal_nv_write_lock(void **buffer,
352 struct tpm2_nv_write_lock_cmd *command_body,
355 struct tpm2_session_header session_header;
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);
365 static void marshal_hierarchy_control(void **buffer,
366 struct tpm2_hierarchy_control_cmd
370 struct tpm2_session_header session_header;
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);
378 marshal_TPM_HANDLE(buffer, command_body->enable, buffer_space);
379 marshal_u8(buffer, command_body->state, buffer_space);
382 static void marshal_get_capability(void **buffer,
383 struct tpm2_get_capability_cmd
387 tpm_tag = TPM_ST_NO_SESSIONS;
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);
394 int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
395 void *buffer, int buffer_size)
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;
401 /* Will be modified when marshaling some commands. */
402 tpm_tag = TPM_ST_NO_SESSIONS;
407 marshal_nv_read(&cmd_body, tpm_command_body, &body_size);
411 marshal_nv_write(&cmd_body, tpm_command_body, &body_size);
414 case TPM2_NV_WriteLock:
415 marshal_nv_write_lock(&cmd_body, tpm_command_body, &body_size);
418 case TPM2_Hierarchy_Control:
419 marshal_hierarchy_control(&cmd_body,
420 tpm_command_body, &body_size);
423 case TPM2_GetCapability:
424 marshal_get_capability(&cmd_body, tpm_command_body, &body_size);
429 VBDEBUG(("%s:%d:Request to marshal unsupported command %#x\n",
430 __FILE__, __LINE__, command));
435 /* See how much room was taken by marshaling. */
436 body_size = max_body_size - body_size;
438 body_size += sizeof(struct tpm_header);
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);
448 struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
452 static struct tpm2_response tpm2_resp;
454 if (cr_size < sizeof(struct tpm_header))
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);
462 if (tpm2_resp.hdr.tpm_size != sizeof(tpm2_resp.hdr))
463 VBDEBUG(("%s: size mismatch in response to command %#x\n",
470 unmarshal_nv_read(&response_body, &cr_size,
474 case TPM2_GetCapability:
475 unmarshal_get_capability(&response_body, &cr_size,
479 case TPM2_Hierarchy_Control:
481 case TPM2_NV_WriteLock:
482 /* Session data included in response can be safely ignored. */
491 "Request to unmarshal unexpected command %#x,"
493 __func__, __LINE__, command,
494 tpm2_resp.hdr.tpm_code));
496 for (i = 0; i < cr_size; i++) {
500 ((uint8_t *)response_body)[i]));
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,
515 /* The entire message have been parsed. */
519 void tpm_set_ph_disabled(int flag)
524 int tpm_is_ph_disabled(void)