2016-06-19 21:13:18 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2016-08-19 19:45:04 +02:00
|
|
|
#include <arch/early_variables.h>
|
2017-03-25 06:38:45 +01:00
|
|
|
#include <commonlib/iobuf.h>
|
2016-06-19 21:13:18 +02:00
|
|
|
#include <console/console.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "tpm2_marshaling.h"
|
|
|
|
|
2016-08-19 19:45:04 +02:00
|
|
|
static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
|
|
|
|
#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
|
|
|
|
#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
|
|
|
|
#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
|
|
|
|
#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
return obuf_write_be16(ob, cmd_body->startup_type);
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_get_capability(struct obuf *ob,
|
|
|
|
struct tpm2_get_capability *cmd_body)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= obuf_write_be32(ob, cmd_body->capability);
|
|
|
|
rc |= obuf_write_be32(ob, cmd_body->property);
|
|
|
|
rc |= obuf_write_be32(ob, cmd_body->propertyCount);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= obuf_write_be16(ob, data->size);
|
|
|
|
rc |= obuf_write(ob, data->buffer, data->size);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
uint32_t v;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
memcpy(&v, nv, sizeof(v));
|
|
|
|
return obuf_write_be32(ob, v);
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
|
|
|
|
rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
|
|
|
|
rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
|
|
|
|
rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
|
|
|
|
rc |= obuf_write_be16(ob, nvpub->dataSize);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
|
|
|
|
rc |= obuf_write(ob, tpmtha->digest.sha256,
|
|
|
|
sizeof(tpmtha->digest.sha256));
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-07-04 07:20:17 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
|
|
|
|
TPML_DIGEST_VALUES *dvalues)
|
2016-07-04 07:20:17 +02:00
|
|
|
{
|
|
|
|
int i;
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-07-04 07:20:17 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= obuf_write_be32(ob, dvalues->count);
|
2016-07-04 07:20:17 +02:00
|
|
|
for (i = 0; i < dvalues->count; i++)
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
|
|
|
|
|
|
|
|
return rc;
|
2016-07-04 07:20:17 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_session_header(struct obuf *ob,
|
|
|
|
struct tpm2_session_header *session_header)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
|
|
|
struct obuf ob_sz;
|
|
|
|
size_t prev_written;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Snapshot current location to place size of header. */
|
|
|
|
if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
|
|
|
|
return -1;
|
tpm2: avoid comparison between signed and unsigned ints
The marshaling/unmarshaling code is using integer values to represent
room left in the buffer, to be able to communicate three conditions:
positive number means there is room left in the buffer, zero means
that the exact amount of data in the buffer was unmarshaled and
negative value means that the result of the operation did not fit into
the buffer.
The implementation is wrong though, as it compares directly signed and
unsigned values, which is illegal, as signed values get promoted to
unsigned by the compiler.
This patch changes the marshaling code to use size_t for the size, and
use zero as marshaling failure indication - after all the buffer where
the data is marshaled to should definitely be large enough, and it is
reasonable to expect at least some room left in it after marshaling.
The unmarshaling situation is different: we sure want to communicate
errors to the caller, but do not want to propagate error return values
through multiple layers. This patch keeps the size value in int, but
checks if it is negative separately, before comparing with positive
values.
BRANCH=none
BUG=chrome-os-partner:50645
TEST=with the rest of the patches applied kevin successfully boots up.
Change-Id: Ibfbd1b351e35e37c8925a78d095e4e8492805bad
Signed-off-by: Martin Roth <martinroth@chromium.org>
Original-Commit-Id: b1e862c2a650fa5f6cb25a01fe61e848a696cf17
Original-Change-Id: Ie7552b333afaff9a1234c948caf9d9a64447b2e1
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/358772
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/15610
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2016-07-07 19:52:46 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Write a size placeholder. */
|
|
|
|
rc |= obuf_write_be32(ob, 0);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Keep track of session header data size by tracking num written. */
|
|
|
|
prev_written = obuf_nr_written(ob);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= obuf_write_be32(ob, session_header->session_handle);
|
|
|
|
rc |= obuf_write_be16(ob, session_header->nonce_size);
|
|
|
|
rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
|
|
|
|
rc |= obuf_write_be8(ob, session_header->session_attrs);
|
|
|
|
rc |= obuf_write_be16(ob, session_header->auth_size);
|
|
|
|
rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Fill back in proper size of session header. */
|
|
|
|
rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2016-07-07 20:04:06 +02:00
|
|
|
/*
|
|
|
|
* Common session header can include one or two handles and an empty
|
|
|
|
* session_header structure.
|
|
|
|
*/
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_common_session_header(struct obuf *ob,
|
2016-07-07 20:04:06 +02:00
|
|
|
const uint32_t *handles,
|
2017-03-25 06:38:45 +01:00
|
|
|
size_t handle_count)
|
2016-07-07 20:04:06 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
size_t i;
|
2016-07-07 20:04:06 +02:00
|
|
|
struct tpm2_session_header session_header;
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-07-07 20:04:06 +02:00
|
|
|
|
2016-08-19 19:45:04 +02:00
|
|
|
car_set_var(tpm_tag, TPM_ST_SESSIONS);
|
2016-07-07 20:04:06 +02:00
|
|
|
|
|
|
|
for (i = 0; i < handle_count; i++)
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_TPM_HANDLE(ob, handles[i]);
|
2016-07-07 20:04:06 +02:00
|
|
|
|
|
|
|
memset(&session_header, 0, sizeof(session_header));
|
|
|
|
session_header.session_handle = TPM_RS_PW;
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_session_header(ob, &session_header);
|
|
|
|
|
|
|
|
return rc;
|
2016-07-07 20:04:06 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_nv_define_space(struct obuf *ob,
|
|
|
|
struct tpm2_nv_define_space_cmd *nvd_in)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2016-07-07 20:04:06 +02:00
|
|
|
const uint32_t handle[] = { TPM_RH_PLATFORM };
|
2017-03-25 06:38:45 +01:00
|
|
|
struct obuf ob_sz;
|
|
|
|
size_t prev_written;
|
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
|
|
|
|
rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Snapshot current location to place size field. */
|
|
|
|
if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
|
|
|
|
return -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Put placeholder for size */
|
|
|
|
rc |= obuf_write_be16(ob, 0);
|
tpm2: avoid comparison between signed and unsigned ints
The marshaling/unmarshaling code is using integer values to represent
room left in the buffer, to be able to communicate three conditions:
positive number means there is room left in the buffer, zero means
that the exact amount of data in the buffer was unmarshaled and
negative value means that the result of the operation did not fit into
the buffer.
The implementation is wrong though, as it compares directly signed and
unsigned values, which is illegal, as signed values get promoted to
unsigned by the compiler.
This patch changes the marshaling code to use size_t for the size, and
use zero as marshaling failure indication - after all the buffer where
the data is marshaled to should definitely be large enough, and it is
reasonable to expect at least some room left in it after marshaling.
The unmarshaling situation is different: we sure want to communicate
errors to the caller, but do not want to propagate error return values
through multiple layers. This patch keeps the size value in int, but
checks if it is negative separately, before comparing with positive
values.
BRANCH=none
BUG=chrome-os-partner:50645
TEST=with the rest of the patches applied kevin successfully boots up.
Change-Id: Ibfbd1b351e35e37c8925a78d095e4e8492805bad
Signed-off-by: Martin Roth <martinroth@chromium.org>
Original-Commit-Id: b1e862c2a650fa5f6cb25a01fe61e848a696cf17
Original-Change-Id: Ie7552b333afaff9a1234c948caf9d9a64447b2e1
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/358772
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/15610
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2016-07-07 19:52:46 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Keep track of nv define space data size by tracking num written. */
|
|
|
|
prev_written = obuf_nr_written(ob);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
|
|
|
|
rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
|
tpm2: avoid comparison between signed and unsigned ints
The marshaling/unmarshaling code is using integer values to represent
room left in the buffer, to be able to communicate three conditions:
positive number means there is room left in the buffer, zero means
that the exact amount of data in the buffer was unmarshaled and
negative value means that the result of the operation did not fit into
the buffer.
The implementation is wrong though, as it compares directly signed and
unsigned values, which is illegal, as signed values get promoted to
unsigned by the compiler.
This patch changes the marshaling code to use size_t for the size, and
use zero as marshaling failure indication - after all the buffer where
the data is marshaled to should definitely be large enough, and it is
reasonable to expect at least some room left in it after marshaling.
The unmarshaling situation is different: we sure want to communicate
errors to the caller, but do not want to propagate error return values
through multiple layers. This patch keeps the size value in int, but
checks if it is negative separately, before comparing with positive
values.
BRANCH=none
BUG=chrome-os-partner:50645
TEST=with the rest of the patches applied kevin successfully boots up.
Change-Id: Ibfbd1b351e35e37c8925a78d095e4e8492805bad
Signed-off-by: Martin Roth <martinroth@chromium.org>
Original-Commit-Id: b1e862c2a650fa5f6cb25a01fe61e848a696cf17
Original-Change-Id: Ie7552b333afaff9a1234c948caf9d9a64447b2e1
Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/358772
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/15610
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2016-07-07 19:52:46 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_nv_write(struct obuf *ob,
|
|
|
|
struct tpm2_nv_write_cmd *command_body)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-07-07 20:04:06 +02:00
|
|
|
uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
|
|
|
rc |= marshal_TPM2B(ob, &command_body->data.b);
|
|
|
|
rc |= obuf_write_be16(ob, command_body->offset);
|
|
|
|
|
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_nv_write_lock(struct obuf *ob,
|
|
|
|
struct tpm2_nv_write_lock_cmd *command_body)
|
2016-07-04 02:08:10 +02:00
|
|
|
{
|
|
|
|
uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
|
2017-03-25 06:38:45 +01:00
|
|
|
|
|
|
|
return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
2016-07-04 02:08:10 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_pcr_extend(struct obuf *ob,
|
|
|
|
struct tpm2_pcr_extend_cmd *command_body)
|
2016-07-04 07:20:17 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
|
|
|
uint32_t handles[] = { command_body->pcrHandle };
|
|
|
|
|
|
|
|
rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
|
|
|
rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
|
2016-07-04 07:20:17 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-07-04 07:20:17 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_nv_read(struct obuf *ob,
|
|
|
|
struct tpm2_nv_read_cmd *command_body)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-07-07 20:04:06 +02:00
|
|
|
uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
|
|
|
|
rc |= obuf_write_be16(ob, command_body->size);
|
|
|
|
rc |= obuf_write_be16(ob, command_body->offset);
|
|
|
|
|
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2016-07-01 05:50:49 +02:00
|
|
|
/* TPM2_Clear command does not require paramaters. */
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_clear(struct obuf *ob)
|
2016-07-01 05:50:49 +02:00
|
|
|
{
|
|
|
|
const uint32_t handle[] = { TPM_RH_PLATFORM };
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
|
2016-07-01 05:50:49 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_selftest(struct obuf *ob,
|
|
|
|
struct tpm2_self_test *command_body)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
return obuf_write_be8(ob, command_body->yes_no);
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_hierarchy_control(struct obuf *ob,
|
|
|
|
struct tpm2_hierarchy_control_cmd *command_body)
|
2017-01-11 00:44:42 +01:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2017-01-11 00:44:42 +01:00
|
|
|
struct tpm2_session_header session_header;
|
|
|
|
|
|
|
|
car_set_var(tpm_tag, TPM_ST_SESSIONS);
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
|
2017-01-11 00:44:42 +01:00
|
|
|
memset(&session_header, 0, sizeof(session_header));
|
|
|
|
session_header.session_handle = TPM_RS_PW;
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_session_header(ob, &session_header);
|
|
|
|
|
|
|
|
rc |= marshal_TPM_HANDLE(ob, command_body->enable);
|
|
|
|
rc |= obuf_write_be8(ob, command_body->state);
|
2017-01-11 00:44:42 +01:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2017-01-11 00:44:42 +01:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
|
2017-03-08 18:23:11 +01:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
|
|
|
uint16_t *sub_command = command_body;
|
2017-03-08 18:23:11 +01:00
|
|
|
|
|
|
|
switch (*sub_command) {
|
|
|
|
case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= obuf_write_be16(ob, *sub_command);
|
2017-03-08 18:23:11 +01:00
|
|
|
break;
|
2017-03-23 00:01:53 +01:00
|
|
|
case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= obuf_write_be16(ob, sub_command[0]);
|
|
|
|
rc |= obuf_write_be16(ob, sub_command[1]);
|
2017-03-23 00:01:53 +01:00
|
|
|
break;
|
2017-03-08 18:23:11 +01:00
|
|
|
default:
|
|
|
|
/* Unsupported subcommand. */
|
|
|
|
printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
|
|
|
|
*sub_command);
|
2017-03-25 06:38:45 +01:00
|
|
|
rc = -1;
|
2017-03-08 18:23:11 +01:00
|
|
|
break;
|
|
|
|
}
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2017-03-08 18:23:11 +01:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
struct obuf ob_hdr;
|
|
|
|
const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
|
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2016-08-19 19:45:04 +02:00
|
|
|
car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Write TPM command header with placeholder field values. */
|
|
|
|
rc |= obuf_write_be16(ob, 0);
|
|
|
|
rc |= obuf_write_be32(ob, 0);
|
|
|
|
rc |= obuf_write_be32(ob, command);
|
|
|
|
|
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
|
|
|
|
2016-06-19 21:13:18 +02:00
|
|
|
switch (command) {
|
|
|
|
case TPM2_Startup:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_startup(ob, tpm_command_body);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TPM2_GetCapability:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_get_capability(ob, tpm_command_body);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TPM2_NV_Read:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_nv_read(ob, tpm_command_body);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TPM2_NV_DefineSpace:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_nv_define_space(ob, tpm_command_body);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TPM2_NV_Write:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_nv_write(ob, tpm_command_body);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
2016-07-04 02:08:10 +02:00
|
|
|
case TPM2_NV_WriteLock:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_nv_write_lock(ob, tpm_command_body);
|
2016-07-04 02:08:10 +02:00
|
|
|
break;
|
|
|
|
|
2016-06-19 21:13:18 +02:00
|
|
|
case TPM2_SelfTest:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_selftest(ob, tpm_command_body);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
2017-01-11 00:44:42 +01:00
|
|
|
case TPM2_Hierarchy_Control:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_hierarchy_control(ob, tpm_command_body);
|
2017-01-11 00:44:42 +01:00
|
|
|
break;
|
|
|
|
|
2016-07-01 05:50:49 +02:00
|
|
|
case TPM2_Clear:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_clear(ob);
|
2016-07-01 05:50:49 +02:00
|
|
|
break;
|
|
|
|
|
2016-07-04 07:20:17 +02:00
|
|
|
case TPM2_PCR_Extend:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_pcr_extend(ob, tpm_command_body);
|
2016-07-04 07:20:17 +02:00
|
|
|
break;
|
|
|
|
|
2017-03-08 18:23:11 +01:00
|
|
|
case TPM2_CR50_VENDOR_COMMAND:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
|
2017-03-08 18:23:11 +01:00
|
|
|
break;
|
|
|
|
|
2016-06-19 21:13:18 +02:00
|
|
|
default:
|
|
|
|
printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
|
|
|
|
__FILE__, __LINE__, command);
|
2017-03-25 06:38:45 +01:00
|
|
|
rc = -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
/* Fix up the command header with known values. */
|
|
|
|
rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
|
|
|
|
rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int unmarshal_get_capability(struct ibuf *ib,
|
2016-06-19 21:13:18 +02:00
|
|
|
struct get_cap_response *gcr)
|
|
|
|
{
|
|
|
|
int i;
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= ibuf_read_be8(ib, &gcr->more_data);
|
|
|
|
rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
|
|
|
switch (gcr->cd.capability) {
|
|
|
|
case TPM_CAP_TPM_PROPERTIES:
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
|
|
|
|
return -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
|
|
|
|
(gcr->cd.data.tpmProperties.tpmProperty)) {
|
|
|
|
printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
|
|
|
|
__FILE__, __func__, __LINE__,
|
|
|
|
gcr->cd.data.tpmProperties.count);
|
2017-03-25 06:38:45 +01:00
|
|
|
return -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
|
|
|
|
TPMS_TAGGED_PROPERTY *pp;
|
|
|
|
|
|
|
|
pp = gcr->cd.data.tpmProperties.tpmProperty + i;
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= unmarshal_TPM_PT(ib, &pp->property);
|
|
|
|
rc |= ibuf_read_be32(ib, &pp->value);
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk(BIOS_ERR,
|
|
|
|
"%s:%d - unable to unmarshal capability response",
|
|
|
|
__func__, __LINE__);
|
|
|
|
printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
|
2017-03-25 06:38:45 +01:00
|
|
|
rc = -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
}
|
2017-03-25 06:38:45 +01:00
|
|
|
|
|
|
|
return rc;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
|
2016-06-19 21:13:18 +02:00
|
|
|
TPM2B_MAX_NV_BUFFER *nv_buffer)
|
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_read_be16(ib, &nv_buffer->t.size))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
|
|
|
|
|
|
|
|
if (nv_buffer->t.buffer == NULL) {
|
2016-06-19 21:13:18 +02:00
|
|
|
printk(BIOS_ERR, "%s:%d - "
|
2017-03-25 06:38:45 +01:00
|
|
|
"size mismatch: expected %d, remaining %zd\n",
|
|
|
|
__func__, __LINE__, nv_buffer->t.size,
|
|
|
|
ibuf_remaining(ib));
|
|
|
|
return -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
|
|
|
/* Total size of the parameter field. */
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_read_be32(ib, &nvr->params_size))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
|
|
|
|
return -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
|
|
|
if (nvr->params_size !=
|
|
|
|
(nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
|
|
|
|
printk(BIOS_ERR,
|
|
|
|
"%s:%d - parameter/buffer %d/%d size mismatch",
|
|
|
|
__func__, __LINE__, nvr->params_size,
|
|
|
|
nvr->buffer.t.size);
|
2017-03-25 06:38:45 +01:00
|
|
|
return -1;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let's ignore the authorisation section. It should be 5 bytes total,
|
|
|
|
* just confirm that this is the case and report any discrepancy.
|
|
|
|
*/
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_remaining(ib) != 5)
|
2016-06-19 21:13:18 +02:00
|
|
|
printk(BIOS_ERR,
|
2017-03-25 06:38:45 +01:00
|
|
|
"%s:%d - unexpected authorisation seciton size %zd\n",
|
|
|
|
__func__, __LINE__, ibuf_remaining(ib));
|
|
|
|
|
|
|
|
ibuf_oob_drain(ib, ibuf_remaining(ib));
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
return 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
static int unmarshal_vendor_command(struct ibuf *ib,
|
2017-03-23 00:01:53 +01:00
|
|
|
struct vendor_command_response *vcr)
|
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_read_be16(ib, &vcr->vc_subcommand))
|
|
|
|
return -1;
|
2017-03-23 00:01:53 +01:00
|
|
|
|
|
|
|
switch (vcr->vc_subcommand) {
|
|
|
|
case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
|
|
|
|
break;
|
|
|
|
case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
|
2017-03-25 06:38:45 +01:00
|
|
|
return ibuf_read_be8(ib, &vcr->num_restored_headers);
|
2017-03-23 00:01:53 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk(BIOS_ERR,
|
|
|
|
"%s:%d - unsupported vendor command %#04x!\n",
|
|
|
|
__func__, __LINE__, vcr->vc_subcommand);
|
2017-03-25 06:38:45 +01:00
|
|
|
return -1;
|
2017-03-23 00:01:53 +01:00
|
|
|
}
|
2017-03-25 06:38:45 +01:00
|
|
|
|
|
|
|
return 0;
|
2017-03-23 00:01:53 +01:00
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
|
2016-06-19 21:13:18 +02:00
|
|
|
{
|
2016-09-02 01:09:43 +02:00
|
|
|
static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
|
|
|
|
struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
|
2017-03-25 06:38:45 +01:00
|
|
|
int rc = 0;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
|
|
|
|
rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
|
|
|
|
rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
if (rc != 0)
|
|
|
|
return NULL;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_remaining(ib) == 0) {
|
|
|
|
if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
|
2016-06-19 21:13:18 +02:00
|
|
|
printk(BIOS_ERR,
|
|
|
|
"%s: size mismatch in response to command %#x\n",
|
|
|
|
__func__, command);
|
2016-09-02 01:09:43 +02:00
|
|
|
return tpm2_resp;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (command) {
|
|
|
|
case TPM2_Startup:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TPM2_GetCapability:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TPM2_NV_Read:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
2017-01-11 00:44:42 +01:00
|
|
|
case TPM2_Hierarchy_Control:
|
2016-07-01 05:50:49 +02:00
|
|
|
case TPM2_Clear:
|
2016-06-19 21:13:18 +02:00
|
|
|
case TPM2_NV_DefineSpace:
|
|
|
|
case TPM2_NV_Write:
|
2016-07-04 02:08:10 +02:00
|
|
|
case TPM2_NV_WriteLock:
|
2016-07-04 07:20:17 +02:00
|
|
|
case TPM2_PCR_Extend:
|
2016-06-19 21:13:18 +02:00
|
|
|
/* Session data included in response can be safely ignored. */
|
2017-03-25 06:38:45 +01:00
|
|
|
ibuf_oob_drain(ib, ibuf_remaining(ib));
|
2016-06-19 21:13:18 +02:00
|
|
|
break;
|
|
|
|
|
2017-03-08 18:23:11 +01:00
|
|
|
case TPM2_CR50_VENDOR_COMMAND:
|
2017-03-25 06:38:45 +01:00
|
|
|
rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
|
2017-03-08 18:23:11 +01:00
|
|
|
break;
|
|
|
|
|
2016-06-19 21:13:18 +02:00
|
|
|
default:
|
|
|
|
{
|
2017-03-25 06:38:45 +01:00
|
|
|
size_t i;
|
|
|
|
size_t sz_left;
|
|
|
|
const uint8_t *data;
|
2016-06-19 21:13:18 +02:00
|
|
|
|
|
|
|
printk(BIOS_INFO, "%s:%d:"
|
|
|
|
"Request to unmarshal unexpected command %#x,"
|
|
|
|
" code %#x",
|
|
|
|
__func__, __LINE__, command,
|
2016-09-02 01:09:43 +02:00
|
|
|
tpm2_resp->hdr.tpm_code);
|
2016-06-19 21:13:18 +02:00
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
sz_left = ibuf_remaining(ib);
|
|
|
|
data = ibuf_oob_drain(ib, sz_left);
|
|
|
|
|
|
|
|
for (i = 0; i < sz_left; i++) {
|
2016-06-19 21:13:18 +02:00
|
|
|
if (!(i % 16))
|
|
|
|
printk(BIOS_INFO, "\n");
|
2017-03-25 06:38:45 +01:00
|
|
|
printk(BIOS_INFO, "%2.2x ", data[i]);
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
printk(BIOS_INFO, "\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-25 06:38:45 +01:00
|
|
|
if (ibuf_remaining(ib)) {
|
2016-06-19 21:13:18 +02:00
|
|
|
printk(BIOS_INFO,
|
|
|
|
"%s:%d got %d bytes back in response to %#x,"
|
2017-03-25 06:38:45 +01:00
|
|
|
" failed to parse (%zd)\n",
|
2016-09-02 01:09:43 +02:00
|
|
|
__func__, __LINE__, tpm2_resp->hdr.tpm_size,
|
2017-03-25 06:38:45 +01:00
|
|
|
command, ibuf_remaining(ib));
|
2016-06-19 21:13:18 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The entire message have been parsed. */
|
2016-09-02 01:09:43 +02:00
|
|
|
return tpm2_resp;
|
2016-06-19 21:13:18 +02:00
|
|
|
}
|