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 <arch/early_variables.h>
8 #include <commonlib/endian.h>
9 #include <console/console.h>
13 #include "tpm2_marshaling.h"
15 static uint16_t tpm_tag CAR_GLOBAL
; /* Depends on the command type. */
18 * Each unmarshaling function receives a pointer to the buffer pointer and a
19 * pointer to the size of data still in the buffer. The function extracts data
20 * from the buffer and adjusts both buffer pointer and remaining data size.
22 * Should there be not enough data in the buffer to unmarshal the required
23 * object, the remaining data size is set to -1 to indicate the error. The
24 * remaining data size is expected to be set to zero once the last data item
25 * has been extracted from the receive buffer.
27 static uint16_t unmarshal_u16(void **buffer
, int *buffer_space
)
31 if (*buffer_space
< 0)
34 if (*buffer_space
< sizeof(value
)) {
35 *buffer_space
= -1; /* Indicate a failure. */
39 value
= read_be16(*buffer
);
40 *buffer
= (void *) ((uintptr_t) (*buffer
) + sizeof(value
));
41 *buffer_space
-= sizeof(value
);
46 static uint16_t unmarshal_u32(void **buffer
, int *buffer_space
)
50 if (*buffer_space
< 0)
53 if (*buffer_space
< sizeof(value
)) {
54 *buffer_space
= -1; /* Indicate a failure. */
58 value
= read_be32(*buffer
);
59 *buffer
= (void *) ((uintptr_t) (*buffer
) + sizeof(value
));
60 *buffer_space
-= sizeof(value
);
65 static uint8_t unmarshal_u8(void **buffer
, int *buffer_space
)
69 if (*buffer_space
< 0)
72 if (*buffer_space
< sizeof(value
)) {
73 *buffer_space
= -1; /* Indicate a failure. */
77 value
= ((uint8_t *)(*buffer
))[0];
78 *buffer
= (void *) ((uintptr_t) (*buffer
) + sizeof(value
));
79 *buffer_space
-= sizeof(value
);
84 #define unmarshal_TPM_CAP(a, b) unmarshal_u32(a, b)
85 #define unmarshal_TPM_CC(a, b) unmarshal_u32(a, b)
86 #define unmarshal_TPM_PT(a, b) unmarshal_u32(a, b)
87 #define unmarshal_TPM_HANDLE(a, b) unmarshal_u32(a, b)
90 * Each marshaling function receives a pointer to the buffer to marshal into,
91 * a pointer to the data item to be marshaled, and a pointer to the remaining
96 * Marshaling an arbitrary blob requires its size in addition to common
99 static void marshal_blob(void **buffer
, void *blob
,
100 size_t blob_size
, size_t *buffer_space
)
102 if (*buffer_space
< blob_size
) {
107 memcpy(*buffer
, blob
, blob_size
);
108 *buffer_space
-= blob_size
;
109 *buffer
= (void *)((uintptr_t)(*buffer
) + blob_size
);
112 static void marshal_u8(void **buffer
, uint8_t value
, size_t *buffer_space
)
114 uint8_t *bp
= *buffer
;
116 if (*buffer_space
< sizeof(value
)) {
123 *buffer_space
-= sizeof(value
);
126 static void marshal_u16(void **buffer
, uint16_t value
, size_t *buffer_space
)
128 if (*buffer_space
< sizeof(value
)) {
132 write_be16(*buffer
, value
);
133 *buffer
= (void *)((uintptr_t)(*buffer
) + sizeof(value
));
134 *buffer_space
-= sizeof(value
);
137 static void marshal_u32(void **buffer
, uint32_t value
, size_t *buffer_space
)
139 if (*buffer_space
< sizeof(value
)) {
144 write_be32(*buffer
, value
);
145 *buffer
= (void *)((uintptr_t)(*buffer
) + sizeof(value
));
146 *buffer_space
-= sizeof(value
);
149 #define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
150 #define marshal_TPMI_RH_NV_AUTH(a, b, c) marshal_TPM_HANDLE(a, b, c)
151 #define marshal_TPMI_RH_NV_INDEX(a, b, c) marshal_TPM_HANDLE(a, b, c)
152 #define marshal_TPMI_SH_AUTH_SESSION(a, b, c) marshal_TPM_HANDLE(a, b, c)
153 #define marshal_TPMI_ALG_HASH(a, b, c) marshal_u16(a, b, c)
155 static void marshal_startup(void **buffer
,
156 struct tpm2_startup
*cmd_body
,
157 size_t *buffer_space
)
159 marshal_u16(buffer
, cmd_body
->startup_type
, buffer_space
);
162 static void marshal_get_capability(void **buffer
,
163 struct tpm2_get_capability
*cmd_body
,
164 size_t *buffer_space
)
166 marshal_u32(buffer
, cmd_body
->capability
, buffer_space
);
167 marshal_u32(buffer
, cmd_body
->property
, buffer_space
);
168 marshal_u32(buffer
, cmd_body
->propertyCount
, buffer_space
);
171 static void marshal_TPM2B(void **buffer
,
173 size_t *buffer_space
)
175 size_t total_size
= data
->size
+ sizeof(data
->size
);
177 if (total_size
> *buffer_space
) {
181 marshal_u16(buffer
, data
->size
, buffer_space
);
182 memcpy(*buffer
, data
->buffer
, data
->size
);
183 *buffer
= ((uint8_t *)(*buffer
)) + data
->size
;
184 *buffer_space
-= data
->size
;
187 static void marshal_TPMA_NV(void **buffer
,
189 size_t *buffer_space
)
191 marshal_u32(buffer
, *((uint32_t *)nv
), buffer_space
);
194 static void marshal_TPMS_NV_PUBLIC(void **buffer
,
195 TPMS_NV_PUBLIC
*nvpub
,
196 size_t *buffer_space
)
198 marshal_TPM_HANDLE(buffer
, nvpub
->nvIndex
, buffer_space
);
199 marshal_TPMI_ALG_HASH(buffer
, nvpub
->nameAlg
, buffer_space
);
200 marshal_TPMA_NV(buffer
, &nvpub
->attributes
, buffer_space
);
201 marshal_TPM2B(buffer
, &nvpub
->authPolicy
.b
, buffer_space
);
202 marshal_u16(buffer
, nvpub
->dataSize
, buffer_space
);
205 static void marshal_TPMT_HA(void **buffer
,
207 size_t *buffer_space
)
209 marshal_TPMI_ALG_HASH(buffer
, tpmtha
->hashAlg
, buffer_space
);
210 marshal_blob(buffer
, tpmtha
->digest
.sha256
,
211 sizeof(tpmtha
->digest
.sha256
),
215 static void marshal_TPML_DIGEST_VALUES(void **buffer
,
216 TPML_DIGEST_VALUES
*dvalues
,
217 size_t *buffer_space
)
221 marshal_u32(buffer
, dvalues
->count
, buffer_space
);
222 for (i
= 0; i
< dvalues
->count
; i
++)
223 marshal_TPMT_HA(buffer
, &dvalues
->digests
[i
], buffer_space
);
226 static void marshal_session_header(void **buffer
,
227 struct tpm2_session_header
*session_header
,
228 size_t *buffer_space
)
231 void *size_location
= *buffer
;
233 /* Skip room for the session header size. */
234 if (*buffer_space
< sizeof(uint32_t)) {
239 *buffer_space
-= sizeof(uint32_t);
240 *buffer
= (void *)(((uintptr_t) *buffer
) + sizeof(uint32_t));
242 base_size
= *buffer_space
;
244 marshal_u32(buffer
, session_header
->session_handle
, buffer_space
);
245 marshal_u16(buffer
, session_header
->nonce_size
, buffer_space
);
246 marshal_blob(buffer
, session_header
->nonce
,
247 session_header
->nonce_size
, buffer_space
);
248 marshal_u8(buffer
, session_header
->session_attrs
, buffer_space
);
249 marshal_u16(buffer
, session_header
->auth_size
, buffer_space
);
250 marshal_blob(buffer
, session_header
->auth
,
251 session_header
->auth_size
, buffer_space
);
254 return; /* The structure did not fit. */
256 /* Paste in the session size. */
257 marshal_u32(&size_location
, base_size
- *buffer_space
, &base_size
);
261 * Common session header can include one or two handles and an empty
262 * session_header structure.
264 static void marshal_common_session_header(void **buffer
,
265 const uint32_t *handles
,
267 size_t *buffer_space
)
270 struct tpm2_session_header session_header
;
272 car_set_var(tpm_tag
, TPM_ST_SESSIONS
);
274 for (i
= 0; i
< handle_count
; i
++)
275 marshal_TPM_HANDLE(buffer
, handles
[i
], buffer_space
);
277 memset(&session_header
, 0, sizeof(session_header
));
278 session_header
.session_handle
= TPM_RS_PW
;
279 marshal_session_header(buffer
, &session_header
, buffer_space
);
282 static void marshal_nv_define_space(void **buffer
,
283 struct tpm2_nv_define_space_cmd
*nvd_in
,
284 size_t *buffer_space
)
288 size_t sizeof_nv_public_size
= sizeof(uint16_t);
289 const uint32_t handle
[] = { TPM_RH_PLATFORM
};
291 marshal_common_session_header(buffer
, handle
,
292 ARRAY_SIZE(handle
), buffer_space
);
293 marshal_TPM2B(buffer
, &nvd_in
->auth
.b
, buffer_space
);
295 /* This is where the TPMS_NV_PUBLIC size will be stored. */
296 size_location
= *buffer
;
298 /* Allocate room for the size. */
299 *buffer
= ((uint8_t *)(*buffer
)) + sizeof(uint16_t);
301 if (*buffer_space
< sizeof_nv_public_size
) {
305 *buffer_space
-= sizeof_nv_public_size
;
306 base_size
= *buffer_space
;
308 marshal_TPMS_NV_PUBLIC(buffer
, &nvd_in
->publicInfo
, buffer_space
);
312 base_size
= base_size
- *buffer_space
;
313 marshal_u16(&size_location
, base_size
, &sizeof_nv_public_size
);
316 static void marshal_nv_write(void **buffer
,
317 struct tpm2_nv_write_cmd
*command_body
,
318 size_t *buffer_space
)
320 uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
322 marshal_common_session_header(buffer
, handles
,
323 ARRAY_SIZE(handles
), buffer_space
);
324 marshal_TPM2B(buffer
, &command_body
->data
.b
, buffer_space
);
325 marshal_u16(buffer
, command_body
->offset
, buffer_space
);
328 static void marshal_nv_write_lock(void **buffer
,
329 struct tpm2_nv_write_lock_cmd
*command_body
,
330 size_t *buffer_space
)
332 uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
333 marshal_common_session_header(buffer
, handles
,
334 ARRAY_SIZE(handles
), buffer_space
);
337 static void marshal_pcr_extend(void **buffer
,
338 struct tpm2_pcr_extend_cmd
*command_body
,
339 size_t *buffer_space
)
341 uint32_t handle
= command_body
->pcrHandle
;
343 marshal_common_session_header(buffer
, &handle
, 1, buffer_space
);
344 marshal_TPML_DIGEST_VALUES(buffer
,
345 &command_body
->digests
, buffer_space
);
348 static void marshal_nv_read(void **buffer
,
349 struct tpm2_nv_read_cmd
*command_body
,
350 size_t *buffer_space
)
352 uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
354 marshal_common_session_header(buffer
, handles
,
355 ARRAY_SIZE(handles
), buffer_space
);
356 marshal_u16(buffer
, command_body
->size
, buffer_space
);
357 marshal_u16(buffer
, command_body
->offset
, buffer_space
);
360 /* TPM2_Clear command does not require paramaters. */
361 static void marshal_clear(void **buffer
, size_t *buffer_space
)
363 const uint32_t handle
[] = { TPM_RH_PLATFORM
};
365 marshal_common_session_header(buffer
, handle
,
366 ARRAY_SIZE(handle
), buffer_space
);
369 static void marshal_selftest(void **buffer
,
370 struct tpm2_self_test
*command_body
,
371 size_t *buffer_space
)
373 marshal_u8(buffer
, command_body
->yes_no
, buffer_space
);
376 int tpm_marshal_command(TPM_CC command
, void *tpm_command_body
,
377 void *buffer
, size_t buffer_size
)
379 void *cmd_body
= (uint8_t *)buffer
+ sizeof(struct tpm_header
);
380 size_t max_body_size
= buffer_size
- sizeof(struct tpm_header
);
381 size_t body_size
= max_body_size
;
383 /* Will be modified when marshaling some commands. */
384 car_set_var(tpm_tag
, TPM_ST_NO_SESSIONS
);
388 marshal_startup(&cmd_body
, tpm_command_body
, &body_size
);
391 case TPM2_GetCapability
:
392 marshal_get_capability(&cmd_body
, tpm_command_body
,
397 marshal_nv_read(&cmd_body
, tpm_command_body
, &body_size
);
400 case TPM2_NV_DefineSpace
:
401 marshal_nv_define_space(&cmd_body
,
402 tpm_command_body
, &body_size
);
406 marshal_nv_write(&cmd_body
, tpm_command_body
, &body_size
);
409 case TPM2_NV_WriteLock
:
410 marshal_nv_write_lock(&cmd_body
, tpm_command_body
, &body_size
);
414 marshal_selftest(&cmd_body
, tpm_command_body
, &body_size
);
418 marshal_clear(&cmd_body
, &body_size
);
421 case TPM2_PCR_Extend
:
422 marshal_pcr_extend(&cmd_body
, tpm_command_body
, &body_size
);
427 printk(BIOS_INFO
, "%s:%d:Request to marshal unsupported command %#x\n",
428 __FILE__
, __LINE__
, command
);
432 size_t marshaled_size
;
433 size_t header_room
= sizeof(struct tpm_header
);
435 /* See how much room was taken by marshaling. */
436 marshaled_size
= max_body_size
- body_size
;
438 /* Total size includes the header size. */
439 marshaled_size
+= sizeof(struct tpm_header
);
441 uint16_t tpm_tag_value
= car_get_var(tpm_tag
);
443 marshal_u16(&buffer
, tpm_tag_value
, &header_room
);
444 marshal_u32(&buffer
, marshaled_size
, &header_room
);
445 marshal_u32(&buffer
, command
, &header_room
);
446 return marshaled_size
;
452 static void unmarshal_get_capability(void **buffer
, int *size
,
453 struct get_cap_response
*gcr
)
457 gcr
->more_data
= unmarshal_u8(buffer
, size
);
459 gcr
->cd
.capability
= unmarshal_TPM_CAP(buffer
, size
);
463 switch (gcr
->cd
.capability
) {
464 case TPM_CAP_TPM_PROPERTIES
:
465 gcr
->cd
.data
.tpmProperties
.count
=
466 unmarshal_u32(buffer
, size
);
469 if (gcr
->cd
.data
.tpmProperties
.count
> ARRAY_SIZE
470 (gcr
->cd
.data
.tpmProperties
.tpmProperty
)) {
471 printk(BIOS_INFO
, "%s:%s:%d - %d - too many properties\n",
472 __FILE__
, __func__
, __LINE__
,
473 gcr
->cd
.data
.tpmProperties
.count
);
477 for (i
= 0; i
< gcr
->cd
.data
.tpmProperties
.count
; i
++) {
478 TPMS_TAGGED_PROPERTY
*pp
;
480 pp
= gcr
->cd
.data
.tpmProperties
.tpmProperty
+ i
;
481 pp
->property
= unmarshal_TPM_PT(buffer
, size
);
482 pp
->value
= unmarshal_u32(buffer
, size
);
487 "%s:%d - unable to unmarshal capability response",
489 printk(BIOS_ERR
, " for %d\n", gcr
->cd
.capability
);
495 static void unmarshal_TPM2B_MAX_NV_BUFFER(void **buffer
,
497 TPM2B_MAX_NV_BUFFER
*nv_buffer
)
499 nv_buffer
->t
.size
= unmarshal_u16(buffer
, size
);
500 if ((*size
< 0) || (nv_buffer
->t
.size
> *size
)) {
501 printk(BIOS_ERR
, "%s:%d - "
502 "size mismatch: expected %d, remaining %d\n",
503 __func__
, __LINE__
, nv_buffer
->t
.size
, *size
);
508 nv_buffer
->t
.buffer
= *buffer
;
510 *buffer
= ((uint8_t *)(*buffer
)) + nv_buffer
->t
.size
;
511 *size
-= nv_buffer
->t
.size
;
514 static void unmarshal_nv_read(void **buffer
, int *size
,
515 struct nv_read_response
*nvr
)
517 /* Total size of the parameter field. */
518 nvr
->params_size
= unmarshal_u32(buffer
, size
);
519 unmarshal_TPM2B_MAX_NV_BUFFER(buffer
, size
, &nvr
->buffer
);
521 if (nvr
->params_size
!=
522 (nvr
->buffer
.t
.size
+ sizeof(nvr
->buffer
.t
.size
))) {
524 "%s:%d - parameter/buffer %d/%d size mismatch",
525 __func__
, __LINE__
, nvr
->params_size
,
533 * Let's ignore the authorisation section. It should be 5 bytes total,
534 * just confirm that this is the case and report any discrepancy.
538 "%s:%d - unexpected authorisation seciton size %d\n",
539 __func__
, __LINE__
, *size
);
541 *buffer
= ((uint8_t *)(*buffer
)) + *size
;
545 struct tpm2_response
*tpm_unmarshal_response(TPM_CC command
,
549 static struct tpm2_response tpm2_static_resp CAR_GLOBAL
;
550 struct tpm2_response
*tpm2_resp
= car_get_var_ptr(&tpm2_static_resp
);
552 * Should be 0 when done, positive and negaitive values indicate
553 * unmarshaling errors.
555 int cr_size
= in_size
;
557 if ((cr_size
< 0) || (in_size
< sizeof(struct tpm_header
)))
560 tpm2_resp
->hdr
.tpm_tag
= unmarshal_u16(&response_body
, &cr_size
);
561 tpm2_resp
->hdr
.tpm_size
= unmarshal_u32(&response_body
, &cr_size
);
562 tpm2_resp
->hdr
.tpm_code
= unmarshal_TPM_CC(&response_body
, &cr_size
);
565 if (tpm2_resp
->hdr
.tpm_size
!= sizeof(tpm2_resp
->hdr
))
567 "%s: size mismatch in response to command %#x\n",
576 case TPM2_GetCapability
:
577 unmarshal_get_capability(&response_body
, &cr_size
,
582 unmarshal_nv_read(&response_body
, &cr_size
,
587 case TPM2_NV_DefineSpace
:
589 case TPM2_NV_WriteLock
:
590 case TPM2_PCR_Extend
:
591 /* Session data included in response can be safely ignored. */
599 printk(BIOS_INFO
, "%s:%d:"
600 "Request to unmarshal unexpected command %#x,"
602 __func__
, __LINE__
, command
,
603 tpm2_resp
->hdr
.tpm_code
);
605 for (i
= 0; i
< cr_size
; i
++) {
607 printk(BIOS_INFO
, "\n");
608 printk(BIOS_INFO
, "%2.2x ",
609 ((uint8_t *)response_body
)[i
]);
612 printk(BIOS_INFO
, "\n");
618 "%s:%d got %d bytes back in response to %#x,"
619 " failed to parse (%d)\n",
620 __func__
, __LINE__
, tpm2_resp
->hdr
.tpm_size
,
625 /* The entire message have been parsed. */