coreboot-libre-fam15h-rdimm/3rdparty/chromeec/board/cr50/tpm2/hash.c

374 lines
8.7 KiB
C
Raw Normal View History

2024-03-04 11:14:53 +01:00
/* Copyright 2015 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.
*/
#include "CryptoEngine.h"
#include "util.h"
#include "dcrypto.h"
static const HASH_INFO *lookup_hash_info(TPM_ALG_ID alg)
{
int i;
const int num_algs = ARRAY_SIZE(g_hashData);
for (i = 0; i < num_algs - 1; i++) {
if (g_hashData[i].alg == alg)
return &g_hashData[i];
}
return &g_hashData[num_algs - 1];
}
TPM_ALG_ID _cpri__GetContextAlg(CPRI_HASH_STATE *hash_state)
{
return hash_state->hashAlg;
}
TPM_ALG_ID _cpri__GetHashAlgByIndex(uint32_t index)
{
if (index >= HASH_COUNT)
return TPM_ALG_NULL;
return g_hashData[index].alg;
}
uint16_t _cpri__GetDigestSize(TPM_ALG_ID alg)
{
return lookup_hash_info(alg)->digestSize;
}
uint16_t _cpri__GetHashBlockSize(TPM_ALG_ID alg)
{
return lookup_hash_info(alg)->blockSize;
}
BUILD_ASSERT(sizeof(LITE_SHA256_CTX) == USER_MIN_HASH_STATE_SIZE);
BUILD_ASSERT(sizeof(CPRI_HASH_STATE) == sizeof(EXPORT_HASH_STATE));
void _cpri__ImportExportHashState(CPRI_HASH_STATE *osslFmt,
EXPORT_HASH_STATE *externalFmt,
IMPORT_EXPORT direction)
{
if (direction == IMPORT_STATE)
memcpy(osslFmt, externalFmt, sizeof(CPRI_HASH_STATE));
else
memcpy(externalFmt, osslFmt, sizeof(CPRI_HASH_STATE));
}
uint16_t _cpri__HashBlock(TPM_ALG_ID alg, uint32_t in_len, uint8_t *in,
uint32_t out_len, uint8_t *out)
{
uint8_t digest[SHA_DIGEST_MAX_BYTES];
const uint16_t digest_len = _cpri__GetDigestSize(alg);
if (digest_len == 0)
return 0;
switch (alg) {
case TPM_ALG_SHA1:
DCRYPTO_SHA1_hash(in, in_len, digest);
break;
case TPM_ALG_SHA256:
DCRYPTO_SHA256_hash(in, in_len, digest);
break;
case TPM_ALG_SHA384:
DCRYPTO_SHA384_hash(in, in_len, digest);
break;
case TPM_ALG_SHA512:
DCRYPTO_SHA512_hash(in, in_len, digest);
break;
default:
FAIL(FATAL_ERROR_INTERNAL);
break;
}
out_len = MIN(out_len, digest_len);
memcpy(out, digest, out_len);
return out_len;
}
BUILD_ASSERT(sizeof(struct HASH_CTX) <=
sizeof(((CPRI_HASH_STATE *)0)->state));
uint16_t _cpri__StartHash(TPM_ALG_ID alg, BOOL sequence,
CPRI_HASH_STATE *state)
{
struct HASH_CTX *ctx = (struct HASH_CTX *) state->state;
uint16_t result;
/* NOTE: as per bug http://crosbug.com/p/55331#26 (NVMEM
* encryption), always use the software hash implementation
* for TPM related calculations, since we have no guarantee
* that the key-ladder will not be used between SHA_init() and
* final().
*/
switch (alg) {
case TPM_ALG_SHA1:
DCRYPTO_SHA1_init(ctx, 1);
result = HASH_size(ctx);
break;
case TPM_ALG_SHA256:
DCRYPTO_SHA256_init(ctx, 1);
result = HASH_size(ctx);
break;
case TPM_ALG_SHA384:
DCRYPTO_SHA384_init(ctx);
result = HASH_size(ctx);
break;
case TPM_ALG_SHA512:
DCRYPTO_SHA512_init(ctx);
result = HASH_size(ctx);
break;
default:
result = 0;
break;
}
if (result > 0)
state->hashAlg = alg;
return result;
}
void _cpri__UpdateHash(CPRI_HASH_STATE *state, uint32_t in_len,
BYTE *in)
{
struct HASH_CTX *ctx = (struct HASH_CTX *) state->state;
HASH_update(ctx, in, in_len);
}
uint16_t _cpri__CompleteHash(CPRI_HASH_STATE *state,
uint32_t out_len, uint8_t *out)
{
struct HASH_CTX *ctx = (struct HASH_CTX *) state->state;
out_len = MIN(HASH_size(ctx), out_len);
memcpy(out, HASH_final(ctx), out_len);
return out_len;
}
#ifdef CRYPTO_TEST_SETUP
#include "console.h"
#include "extension.h"
#include "shared_mem.h"
#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args)
struct test_context {
int context_handle;
CPRI_HASH_STATE hstate;
};
static struct {
int current_context_count;
int max_contexts;
struct test_context *contexts;
} hash_test_db;
struct test_context *find_context(int handle)
{
int i;
for (i = 0; i < hash_test_db.current_context_count; i++)
if (hash_test_db.contexts[i].context_handle == handle)
return hash_test_db.contexts + i;
return NULL;
}
static void process_start(TPM_ALG_ID alg, int handle, void *response_body,
size_t *response_size)
{
uint8_t *response = response_body;
struct test_context *new_context;
if (find_context(handle)) {
*response = EXC_HASH_DUPLICATED_HANDLE;
*response_size = 1;
return;
}
if (!hash_test_db.max_contexts) {
size_t buffer_size;
/* Check how many contexts could possible fit. */
hash_test_db.max_contexts = shared_mem_size() /
sizeof(struct test_context);
buffer_size = sizeof(struct test_context) *
hash_test_db.max_contexts;
if (shared_mem_acquire(buffer_size,
(char **)&hash_test_db.contexts) !=
EC_SUCCESS) {
/* Must be out of memory. */
hash_test_db.max_contexts = 0;
*response = EXC_HASH_TOO_MANY_HANDLES;
*response_size = 1;
return;
}
memset(hash_test_db.contexts, 0, buffer_size);
}
if (hash_test_db.current_context_count == hash_test_db.max_contexts) {
*response = EXC_HASH_TOO_MANY_HANDLES;
*response_size = 1;
return;
}
new_context = hash_test_db.contexts +
hash_test_db.current_context_count++;
new_context->context_handle = handle;
_cpri__StartHash(alg, 0, &new_context->hstate);
}
static void process_continue(int handle, void *cmd_body, uint16_t text_len,
void *response_body, size_t *response_size)
{
struct test_context *context = find_context(handle);
if (!context) {
*((uint8_t *)response_body) = EXC_HASH_UNKNOWN_CONTEXT;
*response_size = 1;
return;
}
_cpri__UpdateHash(&context->hstate, text_len, cmd_body);
}
static void process_finish(int handle, void *response_body,
size_t *response_size)
{
struct test_context *context = find_context(handle);
if (!context) {
*((uint8_t *)response_body) = EXC_HASH_UNKNOWN_CONTEXT;
*response_size = 1;
return;
}
/* There for sure is enough room in the TPM buffer. */
*response_size = _cpri__CompleteHash(&context->hstate,
SHA_DIGEST_MAX_BYTES,
response_body);
/* drop this context from the database. */
hash_test_db.current_context_count--;
if (!hash_test_db.current_context_count) {
shared_mem_release(hash_test_db.contexts);
hash_test_db.max_contexts = 0;
return;
}
/* Nothing to do, if the deleted context is the last one in memory. */
if (context == (hash_test_db.contexts +
hash_test_db.current_context_count))
return;
memcpy(context,
hash_test_db.contexts + hash_test_db.current_context_count,
sizeof(*context));
}
static void hash_command_handler(void *cmd_body,
size_t cmd_size,
size_t *response_size)
{
int mode;
int hash_mode;
int handle;
uint16_t text_len;
uint8_t *cmd;
size_t response_room = *response_size;
TPM_ALG_ID alg;
cmd = cmd_body;
/*
* Empty response is sent as a success indication when the digest is
* not yet expected (i.e. in response to 'start' and 'cont' commands,
* as defined below).
*
* Single byte responses indicate errors, test successes are
* communicated as responses of the size of the appropriate digests.
*/
*response_size = 0;
/*
* Command structure, shared out of band with the test driver running
* on the host:
*
* field | size | note
* ===================================================================
* mode | 1 | 0 - start, 1 - cont., 2 - finish, 3 - single
* hash_mode | 1 | 0 - sha1, 1 - sha256
* handle | 1 | seassion handle, ignored in 'single' mode
* text_len | 2 | size of the text to process, big endian
* text | text_len | text to hash
*/
mode = *cmd++;
hash_mode = *cmd++;
handle = *cmd++;
text_len = *cmd++;
text_len = text_len * 256 + *cmd++;
switch (hash_mode) {
case 0:
alg = TPM_ALG_SHA1;
break;
case 1:
alg = TPM_ALG_SHA256;
break;
default:
return;
}
switch (mode) {
case 0: /* Start a new hash context. */
process_start(alg, handle, cmd_body, response_size);
if (*response_size)
break; /* Something went wrong. */
process_continue(handle, cmd, text_len,
cmd_body, response_size);
break;
case 1:
process_continue(handle, cmd, text_len,
cmd_body, response_size);
break;
case 2:
process_continue(handle, cmd, text_len,
cmd_body, response_size);
if (*response_size)
break; /* Something went wrong. */
process_finish(handle, cmd_body, response_size);
CPRINTF("%s:%d response size %d\n", __func__, __LINE__,
*response_size);
break;
case 3: /* Process a buffer in a single shot. */
if (!text_len)
break;
/*
* Error responses are just 1 byte in size, valid responses
* are of various hash sizes.
*/
*response_size = _cpri__HashBlock(alg, text_len,
cmd, response_room, cmd_body);
CPRINTF("%s:%d response size %d\n", __func__,
__LINE__, *response_size);
break;
default:
break;
}
}
DECLARE_EXTENSION_COMMAND(EXTENSION_HASH, hash_command_handler);
#endif /* CRYPTO_TEST_SETUP */