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. */
12 static void write_be16(void *dest, uint16_t val)
14 uint8_t *byte_dest = dest;
16 byte_dest[0] = val >> 8;
20 static void write_be32(void *dest, uint32_t val)
22 uint8_t *byte_dest = dest;
24 byte_dest[0] = val >> 24;
25 byte_dest[1] = val >> 16;
26 byte_dest[2] = val >> 8;
30 static uint16_t read_be16(const void *src)
32 const uint8_t *s = src;
33 return (((uint16_t)s[0]) << 8) | (((uint16_t)s[1]) << 0);
36 static inline uint32_t read_be32(const void *src)
38 const uint8_t *s = src;
40 return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) |
41 (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0);
45 * Each unmarshaling function receives a pointer to the buffer pointer and a
46 * pointer to the size of data still in the buffer. The function extracts data
47 * from the buffer and adjusts both buffer pointer and remaining data size.
49 * Should there be not enough data in the buffer to unmarshal the required
50 * object, the remaining data size is set to -1 to indicate the error. The
51 * remaining data size is expected to be set to zero once the last data item
52 * has been extracted from the buffer.
55 static uint16_t unmarshal_u16(void **buffer, int *buffer_space)
59 if (*buffer_space < sizeof(value)) {
60 *buffer_space = -1; /* Indicate a failure. */
64 value = read_be16(*buffer);
65 *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
66 *buffer_space -= sizeof(value);
71 static uint16_t unmarshal_u32(void **buffer, int *buffer_space)
75 if (*buffer_space < sizeof(value)) {
76 *buffer_space = -1; /* Indicate a failure. */
80 value = read_be32(*buffer);
81 *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
82 *buffer_space -= sizeof(value);
87 static void unmarshal_TPM2B_MAX_NV_BUFFER(void **buffer,
89 TPM2B_MAX_NV_BUFFER *nv_buffer)
91 nv_buffer->t.size = unmarshal_u16(buffer, size);
92 if (nv_buffer->t.size > *size) {
94 "size mismatch: expected %d, remaining %d\n",
95 __func__, __LINE__, nv_buffer->t.size, *size));
99 nv_buffer->t.buffer = *buffer;
101 *buffer = ((uint8_t *)(*buffer)) + nv_buffer->t.size;
102 *size -= nv_buffer->t.size;
105 static void unmarshal_nv_read(void **buffer, int *size,
106 struct nv_read_response *nvr)
108 /* Total size of the parameter field. */
109 nvr->params_size = unmarshal_u32(buffer, size);
110 unmarshal_TPM2B_MAX_NV_BUFFER(buffer, size, &nvr->buffer);
112 if (nvr->params_size !=
113 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
114 VBDEBUG(("%s:%d - parameter/buffer %d/%d size mismatch",
115 __func__, __LINE__, nvr->params_size,
116 nvr->buffer.t.size));
123 * Let's ignore the authorisation section. It should be 5 bytes total,
124 * just confirm that this is the case and report any discrepancy.
127 VBDEBUG(("%s:%d - unexpected authorisation seciton size %d\n",
128 __func__, __LINE__, *size));
130 *buffer = ((uint8_t *)(*buffer)) + *size;
136 * Each marshaling function receives a pointer to the buffer to marshal into,
137 * a pointer to the data item to be marshaled, and a pointer to the remaining
138 * room in the buffer.
142 * Marshaling an arbitrary blob requires its size in addition to common
145 static void marshal_blob(void **buffer, void *blob,
146 size_t blob_size, int *buffer_space)
148 if (*buffer_space < blob_size) {
153 Memcpy(*buffer, blob, blob_size);
154 buffer_space -= blob_size;
155 *buffer = (void *)((uintptr_t)(*buffer) + blob_size);
158 static void marshal_u8(void **buffer, uint8_t value, int *buffer_space)
160 uint8_t *bp = *buffer;
162 if (*buffer_space < sizeof(value)) {
169 *buffer_space -= sizeof(value);
172 static void marshal_u16(void **buffer, uint16_t value, int *buffer_space)
174 if (*buffer_space < sizeof(value)) {
178 write_be16(*buffer, value);
179 *buffer = (void *)((uintptr_t)(*buffer) + sizeof(value));
180 *buffer_space -= sizeof(value);
183 static void marshal_u32(void **buffer, uint32_t value, int *buffer_space)
185 if (*buffer_space < sizeof(value)) {
190 write_be32(*buffer, value);
191 *buffer = (void *)((uintptr_t)(*buffer) + sizeof(value));
192 *buffer_space -= sizeof(value);
195 #define unmarshal_TPM_CC(a, b) unmarshal_u32(a, b)
196 #define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
198 static void marshal_session_header(void **buffer,
199 struct tpm2_session_header *session_header,
203 void *size_location = *buffer;
205 /* Skip room for the session header size. */
206 *buffer_space -= sizeof(uint32_t);
207 *buffer = (void *)(((uintptr_t) *buffer) + sizeof(uint32_t));
209 base_size = *buffer_space;
211 marshal_u32(buffer, session_header->session_handle, buffer_space);
212 marshal_u16(buffer, session_header->nonce_size, buffer_space);
213 marshal_blob(buffer, session_header->nonce,
214 session_header->nonce_size, buffer_space);
215 marshal_u8(buffer, session_header->session_attrs, buffer_space);
216 marshal_u16(buffer, session_header->auth_size, buffer_space);
217 marshal_blob(buffer, session_header->auth,
218 session_header->auth_size, buffer_space);
220 if (*buffer_space < 0)
221 return; /* The structure did not fit. */
223 /* Paste in the session size. */
224 marshal_u32(&size_location, base_size - *buffer_space, &base_size);
227 static void marshal_TPM2B(void **buffer,
231 size_t total_size = data->size + sizeof(data->size);
233 if (total_size > *buffer_space) {
237 marshal_u16(buffer, data->size, buffer_space);
238 Memcpy(*buffer, data->buffer, data->size);
239 *buffer = ((uint8_t *)(*buffer)) + data->size;
240 *buffer_space -= data->size;
243 static void marshal_nv_write(void **buffer,
244 struct tpm2_nv_write_cmd *command_body,
247 struct tpm2_session_header session_header;
249 marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
250 marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
251 Memset(&session_header, 0, sizeof(session_header));
252 session_header.session_handle = TPM_RS_PW;
253 marshal_session_header(buffer, &session_header, buffer_space);
254 tpm_tag = TPM_ST_SESSIONS;
256 marshal_TPM2B(buffer, &command_body->data.b, buffer_space);
257 marshal_u16(buffer, command_body->offset, buffer_space);
260 static void marshal_nv_read(void **buffer,
261 struct tpm2_nv_read_cmd *command_body,
264 struct tpm2_session_header session_header;
266 marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space);
267 marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space);
268 Memset(&session_header, 0, sizeof(session_header));
269 session_header.session_handle = TPM_RS_PW;
270 marshal_session_header(buffer, &session_header, buffer_space);
271 tpm_tag = TPM_ST_SESSIONS;
272 marshal_u16(buffer, command_body->size, buffer_space);
273 marshal_u16(buffer, command_body->offset, buffer_space);
277 int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
278 void *buffer, int buffer_size)
280 void *cmd_body = (uint8_t *)buffer + sizeof(struct tpm_header);
281 int max_body_size = buffer_size - sizeof(struct tpm_header);
282 int body_size = max_body_size;
284 /* Will be modified when marshaling some commands. */
285 tpm_tag = TPM_ST_NO_SESSIONS;
290 marshal_nv_read(&cmd_body, tpm_command_body, &body_size);
294 marshal_nv_write(&cmd_body, tpm_command_body, &body_size);
299 VBDEBUG(("%s:%d:Request to marshal unsupported command %#x\n",
300 __FILE__, __LINE__, command));
305 /* See how much room was taken by marshaling. */
306 body_size = max_body_size - body_size;
308 body_size += sizeof(struct tpm_header);
310 marshal_u16(&buffer, tpm_tag, &max_body_size);
311 marshal_u32(&buffer, body_size, &max_body_size);
312 marshal_u32(&buffer, command, &max_body_size);
318 struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
322 static struct tpm2_response tpm2_resp;
324 if (cr_size < sizeof(struct tpm_header))
327 tpm2_resp.hdr.tpm_tag = unmarshal_u16(&response_body, &cr_size);
328 tpm2_resp.hdr.tpm_size = unmarshal_u32(&response_body, &cr_size);
329 tpm2_resp.hdr.tpm_code = unmarshal_TPM_CC(&response_body, &cr_size);
332 if (tpm2_resp.hdr.tpm_size != sizeof(tpm2_resp.hdr))
333 VBDEBUG(("%s: size mismatch in response to command %#x\n",
340 unmarshal_nv_read(&response_body, &cr_size,
345 /* Session data included in response can be safely ignored. */
354 "Request to unmarshal unexpected command %#x,"
356 __func__, __LINE__, command,
357 tpm2_resp.hdr.tpm_code));
359 for (i = 0; i < cr_size; i++) {
363 ((uint8_t *)response_body)[i]));
371 VBDEBUG(("%s:%d got %d bytes back in response to %#x,"
372 " failed to parse (%d)\n",
373 __func__, __LINE__, tpm2_resp.hdr.tpm_size,
378 /* The entire message have been parsed. */