diff --git a/board/cr50/board.h b/board/cr50/board.h index 320b6fe133..c6462b56ec 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -49,6 +49,11 @@ #define CONFIG_SPS_TEST +/* Include crypto stuff, both software and hardware. */ +#define CONFIG_DCRYPTO +#define CONFIG_SHA1 +#define CONFIG_SHA256 + #ifndef __ASSEMBLER__ #include "gpio_signal.h" diff --git a/board/cr50/build.mk b/board/cr50/build.mk index fce011d0ec..aa84171346 100644 --- a/board/cr50/build.mk +++ b/board/cr50/build.mk @@ -31,6 +31,8 @@ dirs-y += $(BDIR)/tpm2 board-y = board.o board-y += tpm2/NVMem.o board-y += tpm2/aes.o +board-y += tpm2/hash.o +board-y += tpm2/hash_data.o board-y += tpm2/platform.o board-y += tpm2/stubs.o diff --git a/board/cr50/tpm2/aes.c b/board/cr50/tpm2/aes.c index 29348ad2ab..a751e9134e 100644 --- a/board/cr50/tpm2/aes.c +++ b/board/cr50/tpm2/aes.c @@ -7,7 +7,6 @@ #include "dcrypto.h" #include -#include static CRYPT_RESULT _cpri__AESBlock( uint8_t *out, uint32_t len, uint8_t *in); diff --git a/board/cr50/tpm2/hash.c b/board/cr50/tpm2/hash.c new file mode 100644 index 0000000000..8d3dc9a05d --- /dev/null +++ b/board/cr50/tpm2/hash.c @@ -0,0 +1,138 @@ +/* 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; +} + +void _cpri__ImportExportHashState(CPRI_HASH_STATE *osslFmt, + EXPORT_HASH_STATE *externalFmt, + IMPORT_EXPORT direction) +{ + pAssert(sizeof(CPRI_HASH_STATE) == sizeof(EXPORT_HASH_STATE)); + 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; +/* TODO: add support for SHA384 and SHA512 + * + * case TPM_ALG_SHA384: + * DCRYPTO_SHA384_hash(in, in_len, p); + * break; + * case TPM_ALG_SHA512: + * DCRYPTO_SHA512_hash(in, in_len, p); + * break; */ + default: + FAIL(FATAL_ERROR_INTERNAL); + break; + } + + out_len = MIN(out_len, digest_len); + memcpy(out, digest, out_len); + return out_len; +} + +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; + + pAssert(sizeof(struct HASH_CTX) < sizeof(state->state)); + switch (alg) { + case TPM_ALG_SHA1: + DCRYPTO_SHA1_init(ctx, sequence); + result = DCRYPTO_HASH_size(ctx); + break; + case TPM_ALG_SHA256: + DCRYPTO_SHA256_init(ctx, sequence); + result = DCRYPTO_HASH_size(ctx); + break; +/* TODO: add support for SHA384 and SHA512 + * case TPM_ALG_SHA384: + * DCRYPTO_SHA384_init(in, in_len, p); + * break; + * case TPM_ALG_SHA512: + * DCRYPTO_SHA512_init(in, in_len, p); + * break; */ + default: + result = 0; + break; + } + + return result; +} + +void _cpri__UpdateHash(CPRI_HASH_STATE *state, uint32_t in_len, + BYTE *in) +{ + struct HASH_CTX *ctx = (struct HASH_CTX *) state->state; + + DCRYPTO_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(DCRYPTO_HASH_size(ctx), out_len); + memcpy(out, DCRYPTO_HASH_final(ctx), out_len); + return out_len; +} diff --git a/board/cr50/tpm2/hash_data.c b/board/cr50/tpm2/hash_data.c new file mode 100644 index 0000000000..6e6ad8aa4d --- /dev/null +++ b/board/cr50/tpm2/hash_data.c @@ -0,0 +1,11 @@ +/* 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" + +/* + * This is unfortunate, but this is the only way to bring in necessary data + * from the TPM2 library, as this file is not compiled in embedded mode. + */ +#include "CpriHashData.c" diff --git a/board/cr50/tpm2/stubs.c b/board/cr50/tpm2/stubs.c index abfe07185c..a75ece04be 100644 --- a/board/cr50/tpm2/stubs.c +++ b/board/cr50/tpm2/stubs.c @@ -33,16 +33,6 @@ UINT16 _cpri__CompleteHMAC( return -1; } -UINT16 _cpri__CompleteHash( - CPRI_HASH_STATE * hashState, // IN: the state of hash stack - UINT32 dOutSize, // IN: size of digest buffer - BYTE * dOut // OUT: hash digest - ) -{ - ecprintf("%s called\n", __func__); - return -1; -} - CRYPT_RESULT _cpri__DecryptRSA( UINT32 * dOutSize, // OUT: the size of the decrypted data BYTE * dOut, // OUT: the decrypted data @@ -182,13 +172,6 @@ UINT16 _cpri__GenerateSeededRandom( return -1; } -TPM_ALG_ID _cpri__GetContextAlg( - CPRI_HASH_STATE * hashState) -{ - ecprintf("%s called\n", __func__); - return TPM_ALG_ERROR; -} - TPM_ECC_CURVE _cpri__GetCurveIdByIndex( UINT16 i) { @@ -196,14 +179,6 @@ TPM_ECC_CURVE _cpri__GetCurveIdByIndex( return TPM_ECC_NONE; } -UINT16 _cpri__GetDigestSize( - TPM_ALG_ID hashAlg // IN: hash algorithm to look up - ) -{ - ecprintf("%s called\n", __func__); - return -1; -} - CRYPT_RESULT _cpri__GetEphemeralEcc( TPMS_ECC_POINT * Qout, // OUT: the public point TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar @@ -214,21 +189,6 @@ CRYPT_RESULT _cpri__GetEphemeralEcc( return CRYPT_FAIL; } -LIB_EXPORT TPM_ALG_ID _cpri__GetHashAlgByIndex( - UINT32 index) // IN: the index -{ - ecprintf("%s called\n", __func__); - return TPM_ALG_ERROR; -} - -UINT16 _cpri__GetHashBlockSize( - TPM_ALG_ID hashAlg // IN: hash algorithm to look up - ) -{ - ecprintf("%s called\n", __func__); - return -1; -} - INT16 _cpri__GetSymmetricBlockSize( TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm UINT16 keySizeInBits // IN: the key size @@ -238,28 +198,6 @@ INT16 _cpri__GetSymmetricBlockSize( return -1; } -UINT16 _cpri__HashBlock( - TPM_ALG_ID hashAlg, // IN: The hash algorithm - UINT32 dataSize, // IN: size of buffer to hash - BYTE * data, // IN: the buffer to hash - UINT32 digestSize, // IN: size of the digest buffer - BYTE * digest // OUT: hash digest - ) -{ - ecprintf("%s called\n", __func__); - return -1; -} - -void _cpri__ImportExportHashState( - CPRI_HASH_STATE * osslFmt, // IN/OUT: the hash state formated for use - // by openSSL - EXPORT_HASH_STATE * externalFmt, // IN/OUT: the exported hash state - IMPORT_EXPORT direction // - ) -{ - ecprintf("%s called\n", __func__); -} - UINT16 _cpri__KDFa( TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC TPM2B * key, // IN: HMAC key @@ -335,16 +273,6 @@ UINT16 _cpri__StartHMAC( return -1; } -UINT16 _cpri__StartHash( - TPM_ALG_ID hashAlg, // IN: hash algorithm - BOOL sequence, // IN: TRUE if the state should be saved - CPRI_HASH_STATE * hashState // OUT: the state of hash stack. - ) -{ - ecprintf("%s called\n", __func__); - return -1; -} - BOOL _cpri__Startup( void) { @@ -374,16 +302,6 @@ CRYPT_RESULT _cpri__TestKeyRSA( return CRYPT_FAIL; } -void _cpri__UpdateHash( - CPRI_HASH_STATE * hashState, // IN: the hash context information - UINT32 dataSize, // IN: the size of data to be added - // to the digest - BYTE * data // IN: data to be hashed - ) -{ - ecprintf("%s called\n", __func__); -} - CRYPT_RESULT _cpri__ValidateSignatureEcc( TPM2B_ECC_PARAMETER * rIn, // IN: r component of the signature TPM2B_ECC_PARAMETER * sIn, // IN: s component of the signature diff --git a/chip/g/build.mk b/chip/g/build.mk index 45b4867fbd..4dc40cd556 100644 --- a/chip/g/build.mk +++ b/chip/g/build.mk @@ -24,7 +24,11 @@ chip-y += polling_uart.o else chip-y += uart.o endif -chip-y += dcrypto/aes.o + +chip-$(CONFIG_DCRYPTO)+= dcrypto/aes.o +chip-$(CONFIG_DCRYPTO)+= dcrypto/sha1.o +chip-$(CONFIG_DCRYPTO)+= dcrypto/sha256.o + chip-y+= pmu.o chip-y+= trng.o chip-$(CONFIG_SPS)+= sps.o @@ -38,10 +42,11 @@ chip-$(CONFIG_USB_HID)+=usb_hid.o chip-$(CONFIG_USB_BLOB)+=usb_blob.o chip-$(CONFIG_FLASH)+=flash.o +dirs-y += chip/g/dcrypto ifneq ($(CONFIG_CUSTOMIZED_RO),) custom-ro_objs-y = chip/g/clock.o -custom-ro_objs-y += chip/g/loader/hw_sha256.o +custom-ro_objs-y += chip/g/dcrypto/sha256.o custom-ro_objs-y += chip/g/loader/key_ladder.o custom-ro_objs-y += chip/g/loader/launch.o custom-ro_objs-y += chip/g/loader/main.o @@ -56,6 +61,7 @@ custom-ro_objs-y += common/printf.o custom-ro_objs-y += common/util.o custom-ro_objs-y += core/cortex-m/init.o custom-ro_objs-y += core/cortex-m/panic.o +dirs-y += chip/g/dcrypto dirs-y += chip/g/loader endif diff --git a/chip/g/dcrypto/dcrypto.h b/chip/g/dcrypto/dcrypto.h index 1dab319392..7cafb224da 100644 --- a/chip/g/dcrypto/dcrypto.h +++ b/chip/g/dcrypto/dcrypto.h @@ -4,15 +4,15 @@ */ /* - * Crypto wrapper library for CR50. + * Crypto wrapper library for the g chip. */ -#ifndef EC_BOARD_CR50_DCRYPTO_DCRYPTO_H_ -#define EC_BOARD_CR50_DCRYPTO_DCRYPTO_H_ +#ifndef __EC_CHIP_G_DCRYPTO_DCRYPTO_H +#define __EC_CHIP_G_DCRYPTO_DCRYPTO_H /* TODO(vbendeb) don't forget to disable this for prod builds. */ #define CRYPTO_TEST_SETUP -#include +#include "internal.h" enum cipher_mode { CIPHER_MODE_ECB = 0, @@ -26,6 +26,36 @@ enum encrypt_mode { ENCRYPT_MODE = 1 }; +#define SHA1_DIGEST_BYTES 20 +#define SHA256_DIGEST_BYTES 32 +#define SHA384_DIGEST_BYTES 48 +#define SHA512_DIGEST_BYTES 64 +#define SHA_DIGEST_MAX_BYTES SHA512_DIGEST_BYTES + +#define SHA1_DIGEST_WORDS (SHA1_DIGEST_BYTES / sizeof(uint32_t)) +#define SHA256_DIGEST_WORDS (SHA256_DIGEST_BYTES / sizeof(uint32_t)) +#define SHA384_DIGEST_WORDS (SHA384_DIGEST_BYTES / sizeof(uint32_t)) +#define SHA512_DIGEST_WORDS (SHA512_DIGEST_BYTES / sizeof(uint32_t)) + +struct HASH_CTX; /* Forward declaration. */ + +typedef struct HASH_CTX SHA1_CTX; +typedef struct HASH_CTX SHA256_CTX; + +#define DCRYPTO_HASH_update(ctx, data, len) \ + ((ctx)->vtab->update((ctx), (data), (len))) +#define DCRYPTO_HASH_final(ctx) \ + ((ctx)->vtab->final((ctx))) +#define DCRYPTO_HASH_size(ctx) \ + ((ctx)->vtab->size) + +#define DCRYPTO_SHA1_update(ctx, data, n) \ + DCRYPTO_HASH_update((ctx), (data), (n)) +#define DCRYPTO_SHA1_final(ctx) DCRYPTO_HASH_final((ctx)) + +/* + * AES implementation, based on a hardware AES block. + */ int DCRYPTO_aes_init(const uint8_t *key, uint32_t key_len, const uint8_t *iv, enum cipher_mode c_mode, enum encrypt_mode e_mode); int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out); @@ -33,4 +63,24 @@ int DCRYPTO_aes_block(const uint8_t *in, uint8_t *out); void DCRYPTO_aes_write_iv(const uint8_t *iv); void DCRYPTO_aes_read_iv(uint8_t *iv); -#endif /* ! EC_BOARD_CR50_DCRYPTO_DCRYPTO_H_ */ +/* + * SHA implementation. This abstraction is backed by either a + * software or hardware implementation. + * + * There could be only a single hardware SHA context in progress. The init + * functions will try using the HW context, if available, unless 'sw_required' + * is TRUE, in which case there will be no attempt to use the hardware for + * this particular hashing session. + */ +void DCRYPTO_SHA1_init(SHA1_CTX *ctx, uint32_t sw_required); +void DCRYPTO_SHA256_init(SHA256_CTX *ctx, uint32_t sw_required); +const uint8_t *DCRYPTO_SHA1_hash(const uint8_t *data, uint32_t n, + uint8_t *digest); + +#define DCRYPTO_SHA256_update(ctx, data, n) \ + DCRYPTO_HASH_update((ctx), (data), (n)) +#define DCRYPTO_SHA256_final(ctx) DCRYPTO_HASH_final((ctx)) +const uint8_t *DCRYPTO_SHA256_hash(const uint8_t *data, uint32_t n, + uint8_t *digest); + +#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */ diff --git a/chip/g/dcrypto/internal.h b/chip/g/dcrypto/internal.h index 5eb76ecc8a..279b2798e7 100644 --- a/chip/g/dcrypto/internal.h +++ b/chip/g/dcrypto/internal.h @@ -3,19 +3,43 @@ * found in the LICENSE file. */ -/* - * Crypto wrapper library for CR50. - */ -#ifndef EC_BOARD_CR50_DCRYPTO_INTERNAL_H_ -#define EC_BOARD_CR50_DCRYPTO_INTERNAL_H_ +#ifndef __EC_CHIP_G_DCRYPTO_INTERNAL_H +#define __EC_CHIP_G_DCRYPTO_INTERNAL_H + +#include #include "common.h" +#include "sha1.h" +#include "sha256.h" #define CTRL_CTR_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #define CTRL_ENABLE 1 #define CTRL_ENCRYPT 1 #define CTRL_NO_SOFT_RESET 0 +struct HASH_CTX; /* Forward declaration. */ + +struct HASH_VTAB { + void (* const update)(struct HASH_CTX *, const uint8_t *, uint32_t); + const uint8_t *(* const final)(struct HASH_CTX *); + const uint8_t *(* const hash)(const uint8_t *, uint32_t, uint8_t *); + uint32_t size; +}; + +struct HASH_CTX { + const struct HASH_VTAB *vtab; + union { + uint8_t buf[64]; + struct sha1_ctx sw_sha1; + struct sha256_ctx sw_sha256; + } u; +}; + +enum sha_mode { + SHA1_MODE = 0, + SHA256_MODE = 1 +}; + /* * Use this structure to avoid alignment problems with input and output * pointers. @@ -24,4 +48,15 @@ struct access_helper { uint32_t udata; } __packed; -#endif /* ! EC_BOARD_CR50_DCRYPTO_INTERNAL_H_ */ +#ifndef SECTION_IS_RO +int dcrypto_grab_sha_hw(void); +void dcrypto_release_sha_hw(void); +#endif +void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data, + uint32_t n, uint8_t *digest); +void dcrypto_sha_init(enum sha_mode mode); +void dcrypto_sha_update(struct HASH_CTX *unused, + const uint8_t *data, uint32_t n); +void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest); + +#endif /* ! __EC_CHIP_G_DCRYPTO_INTERNAL_H */ diff --git a/chip/g/dcrypto/sha1.c b/chip/g/dcrypto/sha1.c new file mode 100644 index 0000000000..9721a9c2d9 --- /dev/null +++ b/chip/g/dcrypto/sha1.c @@ -0,0 +1,98 @@ +/* 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 "dcrypto.h" +#include "internal.h" +#include "registers.h" + +static void sw_sha1_init(SHA1_CTX *ctx); +static void sw_sha1_update(SHA1_CTX *ctx, const uint8_t *data, uint32_t len); +static const uint8_t *sw_sha1_final(SHA1_CTX *ctx); +static const uint8_t *sha1_hash(const uint8_t *data, uint32_t len, + uint8_t *digest); +static const uint8_t *dcrypto_sha1_final(SHA1_CTX *unused); + +/* Software SHA1 implementation. */ +static const struct HASH_VTAB SW_SHA1_VTAB = { + sw_sha1_update, + sw_sha1_final, + sha1_hash, + SHA1_DIGEST_BYTES +}; + +static void sw_sha1_init(SHA1_CTX *ctx) +{ + ctx->vtab = &SW_SHA1_VTAB; + sha1_init(&ctx->u.sw_sha1); +} + +static void sw_sha1_update(SHA1_CTX *ctx, const uint8_t *data, uint32_t len) +{ + sha1_update(&ctx->u.sw_sha1, data, len); +} + +static const uint8_t *sw_sha1_final(SHA1_CTX *ctx) +{ + return sha1_final(&ctx->u.sw_sha1); +} + +static const uint8_t *sha1_hash(const uint8_t *data, uint32_t len, + uint8_t *digest) +{ + SHA1_CTX ctx; + + sw_sha1_init(&ctx); + sw_sha1_update(&ctx, data, len); + memcpy(digest, sw_sha1_final(&ctx), SHA1_DIGEST_BYTES); + return digest; +} + + +/* + * Hardware SHA implementation. + */ +static const struct HASH_VTAB HW_SHA1_VTAB = { + dcrypto_sha_update, + dcrypto_sha1_final, + DCRYPTO_SHA1_hash, + SHA1_DIGEST_BYTES +}; + +/* Select and initialize either the software or hardware + * implementation. If "multi-threaded" behaviour is required, then + * callers must set sw_required to 1. This is because SHA1 state + * internal to the hardware cannot be extracted, so it is not possible + * to suspend and resume a hardware based SHA operation. + * + * If the caller has no preference as to implementation, then hardware + * is preferred based on availability. Hardware is considered to be + * in use between init() and finished() calls. */ +void DCRYPTO_SHA1_init(SHA1_CTX *ctx, uint32_t sw_required) +{ + if (!sw_required && dcrypto_grab_sha_hw()) { + ctx->vtab = &HW_SHA1_VTAB; + dcrypto_sha_init(SHA1_MODE); + } else { + sw_sha1_init(ctx); + } +} + +static const uint8_t *dcrypto_sha1_final(SHA1_CTX *ctx) +{ + dcrypto_sha_wait(SHA1_MODE, (uint32_t *) ctx->u.buf); + return ctx->u.buf; +} + +const uint8_t *DCRYPTO_SHA1_hash(const uint8_t *data, uint32_t n, + uint8_t *digest) +{ + if (dcrypto_grab_sha_hw()) + /* dcrypto_sha_wait() will release the hw. */ + dcrypto_sha_hash(SHA1_MODE, data, n, digest); + else + sha1_hash(data, n, digest); + return digest; +} + diff --git a/chip/g/dcrypto/sha256.c b/chip/g/dcrypto/sha256.c new file mode 100644 index 0000000000..19025f3503 --- /dev/null +++ b/chip/g/dcrypto/sha256.c @@ -0,0 +1,216 @@ +/* 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 "dcrypto.h" +#include "internal.h" +#include "registers.h" +#include "util.h" + +static const uint8_t *dcrypto_sha256_final(SHA256_CTX *ctx); + +#ifdef SECTION_IS_RO +/* RO is single threaded. */ +#define mutex_lock(x) +#define mutex_unlock(x) +static inline int dcrypto_grab_sha_hw(void) +{ + return 1; +} +static inline void dcrypto_release_sha_hw(void) +{ +} +#else +#include "task.h" +static struct mutex hw_busy_mutex; + +static void sha256_init(SHA256_CTX *ctx); +static void sha256_update(SHA256_CTX *ctx, const uint8_t *data, uint32_t len); +static const uint8_t *sha256_final(SHA256_CTX *ctx); +static const uint8_t *sha256_hash(const uint8_t *data, uint32_t len, + uint8_t *digest); + +static const struct HASH_VTAB SW_SHA256_VTAB = { + sha256_update, + sha256_final, + sha256_hash, + SHA256_DIGEST_BYTES +}; + +static void sha256_init(SHA256_CTX *ctx) +{ + ctx->vtab = &SW_SHA256_VTAB; + SHA256_init(&ctx->u.sw_sha256); +} + +static void sha256_update(SHA256_CTX *ctx, const uint8_t *data, uint32_t len) +{ + SHA256_update(&ctx->u.sw_sha256, data, len); +} + +static const uint8_t *sha256_final(SHA256_CTX *ctx) +{ + return SHA256_final(&ctx->u.sw_sha256); +} + +static const uint8_t *sha256_hash(const uint8_t *data, uint32_t len, + uint8_t *digest) +{ + SHA256_CTX ctx; + + sha256_init(&ctx); + sha256_update(&ctx, data, len); + sha256_final(&ctx); + + memcpy(digest, ctx.u.sw_sha256.buf, SHA256_DIGEST_WORDS); + + return digest; +} + +static int hw_busy; + +int dcrypto_grab_sha_hw(void) +{ + int rv = 0; + + mutex_lock(&hw_busy_mutex); + if (!hw_busy) { + rv = 1; + hw_busy = 1; + } + mutex_unlock(&hw_busy_mutex); + + return rv; +} + +void dcrypto_release_sha_hw(void) +{ + mutex_lock(&hw_busy_mutex); + hw_busy = 0; + mutex_unlock(&hw_busy_mutex); +} + +#endif /* ! SECTION_IS_RO */ + +void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest) +{ + int i; + const int digest_len = (mode == SHA1_MODE) ? + SHA1_DIGEST_BYTES : + SHA256_DIGEST_BYTES; + + /* Stop LIVESTREAM mode. */ + GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_STOP, 1); + /* Wait for SHA DONE interrupt. */ + while (!GREG32(KEYMGR, SHA_ITOP)) + ; + + /* Read out final digest. */ + for (i = 0; i < digest_len / 4; ++i) + *digest++ = GR_KEYMGR_SHA_HASH(i); + dcrypto_release_sha_hw(); +} + +/* Hardware SHA implementation. */ +static const struct HASH_VTAB HW_SHA256_VTAB = { + dcrypto_sha_update, + dcrypto_sha256_final, + DCRYPTO_SHA256_hash, + SHA256_DIGEST_BYTES +}; + +void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data, uint32_t n, + uint8_t *digest) +{ + dcrypto_sha_init(mode); + dcrypto_sha_update(NULL, data, n); + dcrypto_sha_wait(mode, (uint32_t *) digest); +} + +void dcrypto_sha_update(struct HASH_CTX *unused, + const uint8_t *data, uint32_t n) +{ + const uint8_t *bp = (const uint8_t *) data; + const uint32_t *wp; + + /* Feed unaligned start bytes. */ + while (n != 0 && ((uint32_t)bp & 3)) { + GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++; + n -= 1; + } + + /* Feed groups of aligned words. */ + wp = (uint32_t *)bp; + while (n >= 8*4) { + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + n -= 8*4; + } + /* Feed individual aligned words. */ + while (n >= 4) { + GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; + n -= 4; + } + + /* Feed remaing bytes. */ + bp = (uint8_t *) wp; + while (n != 0) { + GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++; + n -= 1; + } +} + +void dcrypto_sha_init(enum sha_mode mode) +{ + /* Stop LIVESTREAM mode, in case final() was not called. */ + GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_STOP, 1); + /* Clear interrupt status. */ + GREG32(KEYMGR, SHA_ITOP) = 0; + /* SHA1 or SHA256 mode */ + GWRITE_FIELD(KEYMGR, SHA_CFG_EN, SHA1, mode == SHA1_MODE ? 1 : 0); + /* Enable streaming mode. */ + GWRITE_FIELD(KEYMGR, SHA_CFG_EN, LIVESTREAM, 1); + /* Enable the SHA DONE interrupt. */ + GWRITE_FIELD(KEYMGR, SHA_CFG_EN, INT_EN_DONE, 1); + /* Start SHA engine. */ + GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_GO, 1); +} + +void DCRYPTO_SHA256_init(SHA256_CTX *ctx, uint32_t sw_required) +{ + if (!sw_required && dcrypto_grab_sha_hw()) { + ctx->vtab = &HW_SHA256_VTAB; + dcrypto_sha_init(SHA1_MODE); + } +#ifndef SECTION_IS_RO + else + sha256_init(ctx); +#endif +} + +static const uint8_t *dcrypto_sha256_final(SHA256_CTX *ctx) +{ + dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->u.buf); + dcrypto_release_sha_hw(); + return ctx->u.buf; +} + +const uint8_t *DCRYPTO_SHA256_hash(const uint8_t *data, uint32_t n, + uint8_t *digest) +{ + if (dcrypto_grab_sha_hw()) + /* dcrypto_sha_wait() will release the hw. */ + dcrypto_sha_hash(SHA256_MODE, data, n, digest); +#ifndef SECTION_IS_RO + else + sha256_hash(data, n, digest); +#endif + return digest; +} diff --git a/chip/g/loader/hw_sha256.c b/chip/g/loader/hw_sha256.c deleted file mode 100644 index fb930f7d17..0000000000 --- a/chip/g/loader/hw_sha256.c +++ /dev/null @@ -1,75 +0,0 @@ -/* 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 "debug_printf.h" -#include "registers.h" -#include "setup.h" - -static void _sha_write(const void *data, size_t n) -{ - const uint8_t *bp = (const uint8_t *)data; - const uint32_t *wp; - - while (n && ((uint32_t)bp & 3)) { /* Feed unaligned start bytes. */ - *((uint8_t *)GREG32_ADDR(KEYMGR, SHA_INPUT_FIFO)) = *bp++; - n -= 1; - } - - wp = (uint32_t *)bp; - while (n >= 32) { /* Feed groups of aligned words. */ - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - n -= 32; - } - - while (n >= 4) { /* Feed individual aligned words. */ - GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++; - n -= 4; - } - - bp = (uint8_t *)wp; - while (n) { /* Feed remaing bytes. */ - *((uint8_t *)GREG32_ADDR(KEYMGR, SHA_INPUT_FIFO)) = *bp++; - n -= 1; - } -} - -static void _sha_wait(uint32_t *digest) -{ - int i; - - /* - * Wait for result. TODO: what harm does glitching do? Read out - * non-digest? Old digest? - */ - while (!GREG32(KEYMGR, SHA_ITOP)) - ; - - /* Read out final digest. */ - for (i = 0; i < 8; ++i) - *digest++ = GREG32_ADDR(KEYMGR, SHA_STS_H0)[i]; - - GREG32(KEYMGR, SHA_ITOP) = 0; /* Clear status. */ -} - -void hwSHA256(const void *data, size_t n, uint32_t *digest) -{ - GREG32(KEYMGR, SHA_ITOP) = 0; /* Clear status. */ - - GREG32(KEYMGR, SHA_CFG_MSGLEN_LO) = n; - GREG32(KEYMGR, SHA_CFG_MSGLEN_HI) = 0; - - GWRITE_FIELD(KEYMGR, SHA_CFG_EN, INT_EN_DONE, 1); - GWRITE_FIELD(KEYMGR, SHA_TRIG, TRIG_GO, 1); - - _sha_write(data, n); - _sha_wait(digest); -} diff --git a/chip/g/loader/hw_sha256.h b/chip/g/loader/hw_sha256.h deleted file mode 100644 index b52af6f857..0000000000 --- a/chip/g/loader/hw_sha256.h +++ /dev/null @@ -1,25 +0,0 @@ -/* 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. - */ - -#ifndef __EC_CHIP_G_LOADER_HW_SHA256_H -#define __EC_CHIP_G_LOADER_HW_SHA256_H - -#include -#include - -#define SHA256_DIGEST_BYTES 32 -#define SHA256_DIGEST_WORDS (SHA256_DIGEST_BYTES / sizeof(uint32_t)) - -typedef struct { - uint32_t digest[SHA256_DIGEST_WORDS]; -} hwSHA256_CTX; - -void hwSHA256_init(hwSHA256_CTX *ctx); -void hwSHA256_update(hwSHA256_CTX *ctx, const void *data, size_t len); -const uint8_t *hwSHA256_final(hwSHA256_CTX *ctx); - -void hwSHA256(const void *data, size_t len, uint32_t *digest); - -#endif /* __EC_CHIP_G_LOADER_HW_SHA256_H */ diff --git a/chip/g/loader/launch.c b/chip/g/loader/launch.c index 5ef3ba8c62..3e41756ae9 100644 --- a/chip/g/loader/launch.c +++ b/chip/g/loader/launch.c @@ -3,8 +3,8 @@ * found in the LICENSE file. */ +#include "dcrypto.h" #include "debug_printf.h" -#include "hw_sha256.h" #include "key_ladder.h" #include "registers.h" #include "rom_flash.h" @@ -76,9 +76,9 @@ void tryLaunch(uint32_t adr, size_t max_size) hdr->rx_max - hdr->rx_base - 1; GWRITE_FIELD(GLOBALSEC, CPU0_I_STAGING_REGION1_CTRL, EN, 1); GWRITE_FIELD(GLOBALSEC, CPU0_I_STAGING_REGION1_CTRL, RD_EN, 1); - hwSHA256(&hdr->tag, - hdr->image_size - offsetof(SignedHeader, tag), - hashes.img_hash); + DCRYPTO_SHA256_hash((uint8_t *) &hdr->tag, + hdr->image_size - offsetof(SignedHeader, tag), + (uint8_t *) hashes.img_hash); VERBOSE("img_hash : %.32h\n", hashes.img_hash); @@ -102,7 +102,8 @@ void tryLaunch(uint32_t adr, size_t max_size) } } - hwSHA256(fuses, sizeof(fuses), hashes.fuses_hash); + DCRYPTO_SHA256_hash((uint8_t *) fuses, sizeof(fuses), + (uint8_t *) hashes.fuses_hash); VERBOSE("fuses_hash: %.32h\n", hashes.fuses_hash); @@ -120,11 +121,13 @@ void tryLaunch(uint32_t adr, size_t max_size) } } - hwSHA256(info, sizeof(info), hashes.info_hash); + DCRYPTO_SHA256_hash((uint8_t *) info, sizeof(info), + (uint8_t *) hashes.info_hash); VERBOSE("info_hash : %.32h\n", hashes.info_hash); /* Hash our set of hashes to get final hash. */ - hwSHA256(&hashes, sizeof(hashes), hash); + DCRYPTO_SHA256_hash((uint8_t *) &hashes, sizeof(hashes), + (uint8_t *) hash); /* * Write measured hash to unlock register to try and unlock execution. diff --git a/chip/g/loader/verify.c b/chip/g/loader/verify.c index d852f16c9a..6700ca8ca3 100644 --- a/chip/g/loader/verify.c +++ b/chip/g/loader/verify.c @@ -2,8 +2,9 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + +#include "dcrypto.h" #include "debug_printf.h" -#include "hw_sha256.h" #include "registers.h" #include "setup.h" #include "trng.h" @@ -181,7 +182,7 @@ void LOADERKEY_verify(uint32_t keyid, const uint32_t *signature, VERBOSE("\nsig^ %.384h\n\n", buf); /* Hash resulting buffer. */ - hwSHA256(buf, RSA_NUM_BYTES, hash); + DCRYPTO_SHA256_hash((uint8_t *) buf, RSA_NUM_BYTES, (uint8_t *) hash); VERBOSE("hash %.32h\n", hash); diff --git a/chip/g/registers.h b/chip/g/registers.h index ccadca163f..7d3464b1fd 100644 --- a/chip/g/registers.h +++ b/chip/g/registers.h @@ -25,6 +25,8 @@ #define GOFFSET(mname, rname) \ GC_ ## mname ## _ ## rname ## _OFFSET +#define GREG8(mname, rname) \ + REG8(GBASE(mname) + GOFFSET(mname, rname)) #define GREG32(mname, rname) \ REG32(GBASE(mname) + GOFFSET(mname, rname)) #define GREG32_ADDR(mname, rname) \ @@ -332,6 +334,8 @@ static inline int x_timehs_addr(unsigned int module, unsigned int timer, /* Key manager */ #define GR_KEYMGR_AES_KEY(n) REG32(GREG32_ADDR(KEYMGR, AES_KEY0) + (n)) #define GR_KEYMGR_AES_CTR(n) REG32(GREG32_ADDR(KEYMGR, AES_CTR0) + (n)) +#define GR_KEYMGR_SHA_HASH(n) REG32(GREG32_ADDR(KEYMGR, SHA_STS_H0) \ + + (n)) /* USB device controller */ #define GR_USB_REG(off) REG32(GC_USB0_BASE_ADDR + (off)) diff --git a/common/build.mk b/common/build.mk index b889b641f9..c7fd49a5f1 100644 --- a/common/build.mk +++ b/common/build.mk @@ -69,7 +69,7 @@ common-$(CONFIG_PWM_KBLIGHT)+=pwm_kblight.o common-$(CONFIG_RSA)+=rsa.o common-$(CONFIG_RWSIG)+=rwsig.o common-$(CONFIG_MATH_UTIL)+=math_util.o -common-$(CONFIG_SHA1)+=sha1.o +common-$(CONFIG_SHA1)+= sha1.o common-$(CONFIG_SHA256)+=sha256.o common-$(CONFIG_SMBUS)+= smbus.o common-$(CONFIG_SOFTWARE_CLZ)+=clz.o diff --git a/include/config.h b/include/config.h index 4c8c4a492c..6a63cd6adb 100644 --- a/include/config.h +++ b/include/config.h @@ -623,6 +623,11 @@ */ #undef CONFIG_CUSTOMIZED_RO +/* + * When enabled, build in support for hardware crypto; only supported on CR50. + */ +#undef CONFIG_DCRYPTO + /*****************************************************************************/ /* * Debugging config