mirror of https://github.com/wolfSSL/wolfBoot.git
PolarFire SoC: drive the Athena F5200 through the wolfCrypt port
parent
ffb65a9a29
commit
4cedb7126a
586
hal/mpfs250.c
586
hal/mpfs250.c
|
|
@ -49,22 +49,11 @@
|
|||
#endif
|
||||
|
||||
#ifdef MPFS_ATHENA
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
/* Microchip's CAL headers for the Athena F5200, referenced not vendored (they
|
||||
* carry a Mercury Systems notice); MPFS_ATHENA_CAL_DIR puts them on the path. */
|
||||
#ifndef CALCONFIGH /* the HSS calpolicy.h defines both */
|
||||
#define CALCONFIGH "config_user.h"
|
||||
#endif
|
||||
#ifndef INC_STDINT_H
|
||||
#define INC_STDINT_H /* make caltypes.h use <stdint.h> */
|
||||
#endif
|
||||
/* caltypes.h and wolfSSL's types.h both define a uint128_t, a union of words
|
||||
* there and __uint128_t here; nothing below needs CAL's. */
|
||||
#define uint128_t cal_uint128_t
|
||||
#include "calini.h"
|
||||
#include "hash.h"
|
||||
#include "sym.h"
|
||||
#undef uint128_t
|
||||
/* CAL is reached only through the wolfCrypt port, so none of Microchip's
|
||||
* headers are included here and the uint128_t clash between caltypes.h and
|
||||
* wolfSSL's types.h stays inside that one translation unit. */
|
||||
#include <wolfssl/wolfcrypt/wc_port.h>
|
||||
#include <wolfssl/wolfcrypt/port/microchip/mpfs_athena.h>
|
||||
#endif
|
||||
|
||||
#if defined(DISK_SDCARD) || defined(DISK_EMMC)
|
||||
|
|
@ -330,547 +319,52 @@ static void qspi_uart_program(void);
|
|||
#endif
|
||||
|
||||
#ifdef MPFS_ATHENA
|
||||
/* Ungate and release the Athena F5200 (per HSS opensbi_crypto_ecall.c).
|
||||
* Idempotent: ATHENA_CR_RESET after CALIni() kills AES, not hashing. */
|
||||
static void mpfs_athena_enable(void)
|
||||
{
|
||||
static int athena_enabled;
|
||||
uint64_t cyc;
|
||||
|
||||
if (athena_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
SYSREG_SUBBLK_CLOCK_CR |= MSS_PERIPH_ATHENA;
|
||||
SYSREG_SOFT_RESET_CR &= ~MSS_PERIPH_ATHENA;
|
||||
__asm__ volatile("rdcycle %0" : "=r"(cyc));
|
||||
ATHENA_STALL_CR = (uint32_t)(cyc ^ (cyc >> 32));
|
||||
ATHENA_CR = ATHENA_CR_RESET | ATHENA_CR_RINGOSCON;
|
||||
ATHENA_CR = ATHENA_CR_RINGOSCON | ATHENA_CR_STALL_EN;
|
||||
athena_enabled = 1;
|
||||
}
|
||||
|
||||
/* CAL finds the engine through this global: the User Crypto base in the Libero
|
||||
* design. The HSS build has it compiled in and ignores this symbol. */
|
||||
uint32_t g_user_crypto_base_addr = 0x22000000UL;
|
||||
|
||||
/* Hash context handed to CAL; sized for SATRESCONTEXT and checked below so a
|
||||
* CAL update cannot silently overflow it. */
|
||||
#define MPFS_ATHENA_CTX_SIZE 256
|
||||
typedef char athena_ctx_size_check[
|
||||
(MPFS_ATHENA_CTX_SIZE >= (int)sizeof(SATRESCONTEXT)) ? 1 : -1];
|
||||
|
||||
static int mpfs_athena_engine_init(void)
|
||||
{
|
||||
/* CALIni() must follow the un-reset, and the core must not be reset after
|
||||
* it: that silently kills AES (writes nothing, returns success). */
|
||||
mpfs_athena_enable();
|
||||
if (CALIni() != SATR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CAL status of the last call that failed, reported by the self-check. */
|
||||
static int athena_last_cal_rc;
|
||||
|
||||
static int mpfs_athena_sha384_init(void *ctx)
|
||||
{
|
||||
SATR rc = CALHashCtxIni((SATRESCONTEXTPTR)ctx, SATHASHTYPE_SHA384);
|
||||
|
||||
if (rc != SATR_SUCCESS) {
|
||||
athena_last_cal_rc = (int)rc;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* len must be a whole number of blocks; a partial non-final chunk is rejected
|
||||
* by the engine with SATR_BADHASHLEN. */
|
||||
static int mpfs_athena_sha384_update(void *ctx, const void *in, uint32_t len)
|
||||
{
|
||||
SATR rc = CALHashCtx((SATRESHANDLE)0, (SATRESCONTEXTPTR)ctx, in,
|
||||
(SATUINT32_t)len, NULL, SAT_FALSE);
|
||||
|
||||
if (rc != SATR_SUCCESS) {
|
||||
athena_last_cal_rc = (int)rc;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The final call may carry any remaining length, including zero. */
|
||||
static int mpfs_athena_sha384_final(void *ctx, const void *in, uint32_t len,
|
||||
void *digest)
|
||||
{
|
||||
SATR rc = CALHashCtx((SATRESHANDLE)0, (SATRESCONTEXTPTR)ctx, in,
|
||||
(SATUINT32_t)len, digest, SAT_TRUE);
|
||||
|
||||
if (rc != SATR_SUCCESS) {
|
||||
athena_last_cal_rc = (int)rc;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MPFS_ATHENA_AES
|
||||
/* AES-256-CTR. CTR is symmetric, so this serves encrypt and decrypt alike.
|
||||
* iv is advanced in place by the engine, so a caller may chain calls. */
|
||||
static int mpfs_athena_aes256_ctr(const void *key, void *iv, const void *in,
|
||||
void *out, uint32_t len)
|
||||
{
|
||||
if (CALSymEncrypt(SATSYMTYPE_AES256, (const SATUINT32_t *)key,
|
||||
SATSYMMODE_CTR, iv, SAT_TRUE, in, out, (SATUINT32_t)len)
|
||||
!= SATR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
/* CALSymEncrypt only starts the transfer. Without this wait the output
|
||||
* buffer is never written while both calls still report SATR_SUCCESS. */
|
||||
if (CALSymTrfRes(SAT_TRUE) != SATR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* MPFS_ATHENA_AES */
|
||||
#endif /* MPFS_ATHENA */
|
||||
|
||||
#ifdef MPFS_ATHENA
|
||||
/* SHA-384 + AES-256-CTR via the plain-C mpfs_athena_* API. CAL contract: a
|
||||
* non-final update must be whole 128-byte blocks, so tails are buffered. */
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
#define ATHENA_SHA384_BLOCK 128
|
||||
#define ATHENA_HASH_SLOTS 2
|
||||
|
||||
struct athena_hash_slot {
|
||||
void *owner; /* wc_Sha384* that owns this slot */
|
||||
uint8_t ctx[MPFS_ATHENA_CTX_SIZE]; /* opaque CAL hash context */
|
||||
uint8_t part[ATHENA_SHA384_BLOCK]; /* partial block awaiting more data */
|
||||
uint32_t part_len;
|
||||
uint8_t failed; /* an update faulted: no digest from
|
||||
* this context can be trusted */
|
||||
};
|
||||
|
||||
static struct athena_hash_slot athena_hash_slots[ATHENA_HASH_SLOTS];
|
||||
#endif /* MPFS_ATHENA_SHA */
|
||||
|
||||
/* Set once the self-check has passed: from then on a SHA-384 request the
|
||||
* engine cannot take is a hardware error, never a silent software fallback. */
|
||||
static int athena_ready;
|
||||
|
||||
/* Counts callback entries actually serviced by the engine, so a correct
|
||||
* digest cannot be mistaken for hardware use when the callback never ran. */
|
||||
static uint32_t athena_cb_calls;
|
||||
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
/* Keyed by wc_Sha384 address. The cryptocb has no free event, so a context
|
||||
* freed without Final strands its slot and a later one there resumes it. */
|
||||
static struct athena_hash_slot *athena_slot_find(void *owner)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATHENA_HASH_SLOTS; i++) {
|
||||
if (athena_hash_slots[i].owner == owner) {
|
||||
return &athena_hash_slots[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Feed whole blocks from the slot buffer plus the caller's data. Anything
|
||||
* short of a block is retained for the next call or the final. */
|
||||
static int athena_hash_feed(struct athena_hash_slot *slot, const uint8_t *in,
|
||||
uint32_t len)
|
||||
{
|
||||
uint32_t take;
|
||||
|
||||
if (slot->part_len > 0) {
|
||||
take = ATHENA_SHA384_BLOCK - slot->part_len;
|
||||
if (take > len) {
|
||||
take = len;
|
||||
}
|
||||
memcpy(&slot->part[slot->part_len], in, take);
|
||||
slot->part_len += take;
|
||||
in += take;
|
||||
len -= take;
|
||||
if (slot->part_len < ATHENA_SHA384_BLOCK) {
|
||||
return 0; /* still short of a block */
|
||||
}
|
||||
if (mpfs_athena_sha384_update(slot->ctx, slot->part,
|
||||
ATHENA_SHA384_BLOCK) != 0) {
|
||||
return -1;
|
||||
}
|
||||
slot->part_len = 0;
|
||||
}
|
||||
|
||||
take = len - (len % ATHENA_SHA384_BLOCK);
|
||||
if (take > 0) {
|
||||
if (mpfs_athena_sha384_update(slot->ctx, in, take) != 0) {
|
||||
return -1;
|
||||
}
|
||||
in += take;
|
||||
len -= take;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(slot->part, in, len);
|
||||
slot->part_len = len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* MPFS_ATHENA_SHA */
|
||||
|
||||
#if defined(MPFS_ATHENA_AES) && defined(WOLFSSL_AES_COUNTER) && !defined(NO_AES)
|
||||
/* AES-256-CTR, one path for both directions. Key from aes->devKey, not the
|
||||
* SETKEY hook: succeeding there strands the software fallback. */
|
||||
static int athena_aesctr(wc_CryptoInfo *info)
|
||||
{
|
||||
Aes *aes;
|
||||
word32 sz;
|
||||
word32 whole;
|
||||
|
||||
if (info->cipher.type != WC_CIPHER_AES_CTR) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
aes = info->cipher.aesctr.aes;
|
||||
if (aes == NULL) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
/* AES-256 only; the engine supports 128/192 but wolfBoot's encrypted
|
||||
* images are AES-256 and an untested path is worse than none. */
|
||||
if (aes->keylen != 32) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
/* aes->left != 0 means wolfCrypt holds keystream from a previous partial
|
||||
* block; picking up mid-keystream would desync the counter. */
|
||||
if (aes->left != 0) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
sz = info->cipher.aesctr.sz;
|
||||
if (sz == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The engine advances the counter in place, so aes->reg stays correct for
|
||||
* any subsequent call on the same context. */
|
||||
whole = sz - (sz % WC_AES_BLOCK_SIZE);
|
||||
if (whole > 0) {
|
||||
if (mpfs_athena_aes256_ctr(aes->devKey, aes->reg,
|
||||
info->cipher.aesctr.in, info->cipher.aesctr.out,
|
||||
whole) != 0) {
|
||||
return WC_HW_E;
|
||||
}
|
||||
}
|
||||
if (whole < sz) {
|
||||
/* Trailing partial block: leave the unused keystream where wolfCrypt
|
||||
* keeps its own (aes->tmp, aes->left) so either path can continue. */
|
||||
uint8_t ks[WC_AES_BLOCK_SIZE];
|
||||
word32 i;
|
||||
|
||||
memset(ks, 0, sizeof(ks));
|
||||
if (mpfs_athena_aes256_ctr(aes->devKey, aes->reg, ks, ks,
|
||||
WC_AES_BLOCK_SIZE) != 0) {
|
||||
return WC_HW_E;
|
||||
}
|
||||
for (i = whole; i < sz; i++) {
|
||||
info->cipher.aesctr.out[i] = info->cipher.aesctr.in[i] ^
|
||||
ks[i - whole];
|
||||
}
|
||||
memcpy(aes->tmp, ks, WC_AES_BLOCK_SIZE);
|
||||
aes->left = WC_AES_BLOCK_SIZE - (sz - whole);
|
||||
memset(ks, 0, sizeof(ks));
|
||||
}
|
||||
athena_cb_calls++;
|
||||
return 0;
|
||||
}
|
||||
#endif /* MPFS_ATHENA_AES && WOLFSSL_AES_COUNTER && !NO_AES */
|
||||
|
||||
static int mpfs_athena_cryptocb(int devIdArg, wc_CryptoInfo *info, void *ctx)
|
||||
{
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
struct athena_hash_slot *slot;
|
||||
#endif
|
||||
|
||||
(void)devIdArg;
|
||||
(void)ctx;
|
||||
|
||||
if (info == NULL) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
#if defined(MPFS_ATHENA_AES) && defined(WOLFSSL_AES_COUNTER) && !defined(NO_AES)
|
||||
if (info->algo_type == WC_ALGO_TYPE_CIPHER) {
|
||||
return athena_aesctr(info);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MPFS_ATHENA_SHA
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
#else
|
||||
if (info->algo_type != WC_ALGO_TYPE_HASH ||
|
||||
info->hash.type != WC_HASH_TYPE_SHA384) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
slot = athena_slot_find(info->hash.sha384);
|
||||
if ((slot != NULL) && (info->hash.sha384->devCtx != slot)) {
|
||||
/* Same address, but a context initialized after the one that held
|
||||
* the slot was abandoned without a final: start over. */
|
||||
slot->owner = NULL;
|
||||
slot->failed = 0;
|
||||
slot = NULL;
|
||||
}
|
||||
if ((slot != NULL) && (slot->failed != 0)) {
|
||||
/* An earlier update faulted, so the engine holds a partial digest.
|
||||
* Starting fresh here would digest only the data after the fault. */
|
||||
return WC_HW_E;
|
||||
}
|
||||
if (slot == NULL) {
|
||||
/* First call: the only safe point to decline, since afterwards
|
||||
* wolfCrypt's own state is incomplete and the digest would be wrong. */
|
||||
slot = athena_slot_find(NULL);
|
||||
if (slot == NULL) {
|
||||
return athena_ready ? WC_HW_E : CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
if (mpfs_athena_sha384_init(slot->ctx) != 0) {
|
||||
return athena_ready ? WC_HW_E : CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
slot->owner = info->hash.sha384;
|
||||
info->hash.sha384->devCtx = slot;
|
||||
slot->part_len = 0;
|
||||
slot->failed = 0;
|
||||
}
|
||||
|
||||
if (info->hash.in != NULL && info->hash.inSz > 0) {
|
||||
if (athena_hash_feed(slot, info->hash.in, info->hash.inSz) != 0) {
|
||||
slot->failed = 1;
|
||||
return WC_HW_E;
|
||||
}
|
||||
}
|
||||
|
||||
athena_cb_calls++;
|
||||
|
||||
if (info->hash.digest != NULL) {
|
||||
int ret = mpfs_athena_sha384_final(slot->ctx, slot->part,
|
||||
slot->part_len, info->hash.digest);
|
||||
slot->owner = NULL; /* release for reuse */
|
||||
slot->part_len = 0;
|
||||
slot->failed = 0;
|
||||
if (ret != 0) {
|
||||
return WC_HW_E;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif /* MPFS_ATHENA_SHA */
|
||||
}
|
||||
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
/* Known answers for the self-check: SHA-384 of 0x00..0xFF, hashed in chunks
|
||||
* that straddle the 128-byte block so intermediate state must carry. */
|
||||
static const uint8_t athena_kat_sha384_256b[48] = {
|
||||
0xff, 0xda, 0xeb, 0xff, 0x65, 0xed, 0x05, 0xcf,
|
||||
0x40, 0x0f, 0x02, 0x21, 0xc4, 0xcc, 0xfb, 0x4b,
|
||||
0x21, 0x04, 0xfb, 0x6a, 0x51, 0xf8, 0x7e, 0x40,
|
||||
0xbe, 0x6c, 0x43, 0x09, 0x38, 0x6b, 0xfd, 0xec,
|
||||
0x28, 0x92, 0xe9, 0x17, 0x9b, 0x34, 0x63, 0x23,
|
||||
0x31, 0xa5, 0x95, 0x92, 0x73, 0x7d, 0xb5, 0xc5
|
||||
};
|
||||
#endif /* MPFS_ATHENA_SHA */
|
||||
#ifdef MPFS_ATHENA_AES
|
||||
/* AES-256-CTR of the bytes 0x00..0x1F under key 0x00..0x1F, counter 0x00..0x0F. */
|
||||
static const uint8_t athena_kat_aesctr[32] = {
|
||||
0x5a, 0x6f, 0x06, 0x54, 0x0c, 0xfe, 0x77, 0x91,
|
||||
0xf8, 0x27, 0x5f, 0x36, 0x0e, 0xce, 0xa8, 0x9d,
|
||||
0x70, 0xe2, 0x02, 0xc6, 0xd7, 0x90, 0x4e, 0x4a,
|
||||
0x4d, 0x0f, 0xe1, 0x4a, 0x6e, 0xf8, 0x3e, 0xd0
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Run the offload through the callback path once and compare. The callback
|
||||
* count is part of it: wolfCrypt falls back to software silently. */
|
||||
/* What the self-check tripped on, for the panic message. */
|
||||
static const char *athena_fail_what;
|
||||
static int athena_fail_rc;
|
||||
|
||||
#ifdef MPFS_ATHENA_AES
|
||||
/* One CTR run from a fresh key schedule, split into one or two calls so the
|
||||
* self-check can prove the counter carries across them. */
|
||||
static int athena_ctr_run(const uint8_t *key, const uint8_t *ctr,
|
||||
const uint8_t *in, uint8_t *out, uint32_t first, uint32_t second)
|
||||
{
|
||||
Aes aes;
|
||||
int ret;
|
||||
|
||||
ret = wc_AesInit(&aes, NULL, WOLFBOOT_DEVID_CRYPT);
|
||||
if (ret == 0) {
|
||||
ret = wc_AesSetKeyDirect(&aes, key, 32, ctr, AES_ENCRYPTION);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_AesCtrEncrypt(&aes, out, in, first);
|
||||
}
|
||||
if ((ret == 0) && (second > 0u)) {
|
||||
ret = wc_AesCtrEncrypt(&aes, out + first, in + first, second);
|
||||
}
|
||||
wc_AesFree(&aes);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mpfs_athena_selfcheck(void)
|
||||
{
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
wc_Sha384 sha;
|
||||
uint8_t digest[48];
|
||||
#endif
|
||||
uint8_t buf[256];
|
||||
#ifdef MPFS_ATHENA_AES
|
||||
uint8_t key[32], ctr[16], out[32], out2[32];
|
||||
#endif
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
athena_fail_what = NULL;
|
||||
athena_fail_rc = 0;
|
||||
athena_last_cal_rc = 0;
|
||||
|
||||
for (i = 0; i < (int)sizeof(buf); i++) {
|
||||
buf[i] = (uint8_t)i;
|
||||
}
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
athena_cb_calls = 0;
|
||||
ret = wc_InitSha384_ex(&sha, NULL, WOLFBOOT_DEVID_HASH);
|
||||
if (ret != 0) {
|
||||
athena_fail_what = "SHA-384 init";
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Update(&sha, buf, 100);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Update(&sha, &buf[100], 100);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Update(&sha, &buf[200], 56);
|
||||
}
|
||||
if ((ret != 0) && (athena_fail_what == NULL)) {
|
||||
athena_fail_what = "SHA-384 update";
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Final(&sha, digest);
|
||||
if (ret != 0) {
|
||||
athena_fail_what = "SHA-384 final";
|
||||
}
|
||||
}
|
||||
wc_Sha384Free(&sha);
|
||||
if (ret != 0) {
|
||||
athena_fail_rc = ret;
|
||||
return -1;
|
||||
}
|
||||
if (athena_cb_calls == 0) {
|
||||
athena_fail_what = "SHA-384 callback never serviced (software fallback)";
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(digest, athena_kat_sha384_256b, sizeof(digest)) != 0) {
|
||||
athena_fail_what = "SHA-384 digest mismatch";
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
ret = 0;
|
||||
#endif /* MPFS_ATHENA_SHA */
|
||||
|
||||
#ifdef MPFS_ATHENA_AES
|
||||
for (i = 0; i < 32; i++) {
|
||||
key[i] = (uint8_t)i;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
ctr[i] = (uint8_t)i;
|
||||
}
|
||||
athena_cb_calls = 0;
|
||||
ret = athena_ctr_run(key, ctr, buf, out, 32, 0);
|
||||
if (ret != 0) {
|
||||
athena_fail_what = "AES-256-CTR";
|
||||
athena_fail_rc = ret;
|
||||
return -1;
|
||||
}
|
||||
if (athena_cb_calls == 0) {
|
||||
athena_fail_what = "AES-256-CTR callback never serviced (software "
|
||||
"fallback)";
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(out, athena_kat_aesctr, sizeof(out)) != 0) {
|
||||
athena_fail_what = "AES-256-CTR known-answer mismatch";
|
||||
return -1;
|
||||
}
|
||||
/* The disk decrypt path calls CTR per chunk, so the counter must carry:
|
||||
* two 16-byte calls must equal one 32-byte call, ragged splits too. */
|
||||
ret = athena_ctr_run(key, ctr, buf, out2, 16, 16);
|
||||
if (ret == 0) {
|
||||
if (memcmp(out, out2, sizeof(out)) != 0) {
|
||||
athena_fail_what = "AES-256-CTR counter does not carry across "
|
||||
"calls";
|
||||
return -1;
|
||||
}
|
||||
ret = athena_ctr_run(key, ctr, buf, out2, 20, 12);
|
||||
}
|
||||
if (ret != 0) {
|
||||
athena_fail_what = "AES-256-CTR split run";
|
||||
athena_fail_rc = ret;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(out2, athena_kat_aesctr, sizeof(out2)) != 0) {
|
||||
athena_fail_what = "AES-256-CTR partial block mismatch";
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A build that asks for the hardware must not fall through to software
|
||||
* crypto unnoticed: every failure here halts. */
|
||||
/* The Athena F5200 is driven by the wolfCrypt port in
|
||||
* wolfcrypt/src/port/microchip/mpfs_athena.c, which owns the CAL calls, the
|
||||
* crypto callback and the known-answer tests. A build that asks for the
|
||||
* hardware must not fall through to software unnoticed: every failure halts. */
|
||||
static void mpfs_athena_init(void)
|
||||
{
|
||||
#ifdef MPFS_ATHENA_SHA
|
||||
int i;
|
||||
word32 calls;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ATHENA_HASH_SLOTS; i++) {
|
||||
athena_hash_slots[i].owner = NULL;
|
||||
athena_hash_slots[i].part_len = 0;
|
||||
/* The port deliberately does not call wc_CryptoCb_Init(), which would
|
||||
* clear the whole device table. wolfCrypt_Init() does it, and is
|
||||
* reference counted, so a later caller is harmless. */
|
||||
ret = wolfCrypt_Init();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Athena: wolfCrypt_Init failed (%d)\n", ret);
|
||||
wolfBoot_panic();
|
||||
}
|
||||
/* One registration serves both: the callback dispatches on algo_type and
|
||||
* options.mk gives the hash and the cipher the same devId. MPFS_ATHENA_SHA=0
|
||||
* leaves the hash devId invalid, so image hashing stays in software. */
|
||||
#if defined(MPFS_ATHENA_SHA) && (WOLFBOOT_DEVID_HASH != WOLFBOOT_DEVID_CRYPT)
|
||||
#error "the Athena port registers one devId: keep DEVID_HASH and DEVID_CRYPT equal"
|
||||
#endif
|
||||
|
||||
/* Free slots hold INVALID_DEVID (-2), not 0, so registration returns
|
||||
* BUFFER_E until the zero-initialised device table is initialised. */
|
||||
wc_CryptoCb_Init();
|
||||
|
||||
if (mpfs_athena_engine_init() != 0) {
|
||||
wolfBoot_printf("Athena: engine init failed\n");
|
||||
ret = wc_MpfsAthena_RegisterDevice(WOLFBOOT_DEVID_CRYPT);
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Athena: RegisterDevice failed (%d)\n", ret);
|
||||
wolfBoot_panic();
|
||||
}
|
||||
if (wc_CryptoCb_RegisterDevice(WOLFBOOT_DEVID_HASH, mpfs_athena_cryptocb,
|
||||
NULL) != 0) {
|
||||
wolfBoot_printf("Athena: RegisterDevice failed\n");
|
||||
ret = wc_MpfsAthena_SelfTest();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Athena: self-test failed: %s (rc %d)\n",
|
||||
wc_MpfsAthena_SelfTestDesc(), ret);
|
||||
wolfBoot_panic();
|
||||
}
|
||||
#if defined(WOLFBOOT_DEVID_CRYPT) && (WOLFBOOT_DEVID_CRYPT != WOLFBOOT_DEVID_HASH)
|
||||
if (wc_CryptoCb_RegisterDevice(WOLFBOOT_DEVID_CRYPT, mpfs_athena_cryptocb,
|
||||
NULL) != 0) {
|
||||
wolfBoot_printf("Athena: cipher RegisterDevice failed\n");
|
||||
/* A correct digest proves nothing on its own: with registration failed
|
||||
* wolfCrypt computes the right answer in software. The port counts the
|
||||
* calls the engine actually served, and asserts its own count inside each
|
||||
* known-answer test it compiles, so zero here means no offload path was
|
||||
* built and the engine would sit idle behind a reassuring banner. */
|
||||
calls = wc_MpfsAthena_GetCbCount();
|
||||
if (calls == 0) {
|
||||
wolfBoot_printf("Athena: self-test served no engine call\n");
|
||||
wolfBoot_panic();
|
||||
}
|
||||
#endif
|
||||
if (mpfs_athena_selfcheck() != 0) {
|
||||
wolfBoot_printf("Athena: self-check failed: %s (rc %d, CAL rc %d, "
|
||||
"callbacks %u)\n", athena_fail_what, athena_fail_rc,
|
||||
athena_last_cal_rc, (unsigned)athena_cb_calls);
|
||||
wolfBoot_panic();
|
||||
}
|
||||
athena_ready = 1;
|
||||
#if defined(MPFS_ATHENA_SHA) && defined(MPFS_ATHENA_AES)
|
||||
wolfBoot_printf("Athena: SHA-384 + AES-256-CTR offload active\n");
|
||||
#elif defined(MPFS_ATHENA_SHA)
|
||||
wolfBoot_printf("Athena: SHA-384 offload active\n");
|
||||
#else
|
||||
wolfBoot_printf("Athena: AES-256-CTR offload active\n");
|
||||
#endif
|
||||
wolfBoot_printf("Athena: offload active, engine served %u call(s)\n",
|
||||
(unsigned)calls);
|
||||
}
|
||||
#endif /* MPFS_ATHENA */
|
||||
|
||||
|
|
|
|||
50
options.mk
50
options.mk
|
|
@ -1983,19 +1983,44 @@ ifeq ($(MPFS_ATHENA),1)
|
|||
$(error MPFS_ATHENA=1 requires MPFS_ATHENA_CAL_DIR to point at the \
|
||||
Microchip user-crypto (CAL) directory)
|
||||
endif
|
||||
# The engine is driven by the wolfCrypt port, so the wolfSSL in use has to
|
||||
# carry it. Checked here because an older tree -- a stale submodule, or a
|
||||
# WOLFBOOT_LIB_WOLFSSL override -- otherwise fails as a missing header and a
|
||||
# pile of undefined wc_MpfsAthena_* symbols.
|
||||
MPFS_ATHENA_PORT_SRC = \
|
||||
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/microchip/mpfs_athena.c
|
||||
ifeq ($(wildcard $(MPFS_ATHENA_PORT_SRC)),)
|
||||
$(error MPFS_ATHENA=1 needs a wolfSSL containing the Athena port at \
|
||||
wolfcrypt/src/port/microchip/mpfs_athena.c; update the lib/wolfssl \
|
||||
submodule or point WOLFBOOT_LIB_WOLFSSL at a tree that has it)
|
||||
endif
|
||||
# Both CAL archives are soft-float lp64, so callers must be too (see arch.mk).
|
||||
# M-mode: hart-software-services/services/crypto. S-mode: the rv64imafd
|
||||
# build from polarfire-soc-bare-metal-examples .../middleware/cal.
|
||||
# The include path is for the wolfCrypt port, which owns the CAL calls, not
|
||||
# for this HAL. WOLFSSL_MICROCHIP_MPFS selects the SoC family and
|
||||
# WOLFSSL_MPFS_ATHENA says the part carries the engine; wolfSSL's settings.h
|
||||
# turns on WOLF_CRYPTO_CB and the COPY/FREE events from the latter, so they
|
||||
# are not repeated here. Which engines are offloaded follows the ordinary
|
||||
# WOLFSSL_SHA384 and WOLFSSL_AES_COUNTER gates, so AES-256-CTR comes with an
|
||||
# AES-256 ENCRYPT build.
|
||||
CFLAGS += -DMPFS_ATHENA -I$(MPFS_ATHENA_CAL_DIR)
|
||||
CFLAGS += -DWOLF_CRYPTO_CB
|
||||
CFLAGS += -DWOLFBOOT_DEVID_HASH=0xA7
|
||||
CFLAGS += -DWOLFSSL_MICROCHIP_MPFS -DWOLFSSL_MPFS_ATHENA
|
||||
# Matches the port's own WC_MPFS_ATHENA_DEVID default; wolfBoot tags its
|
||||
# cipher contexts with this one.
|
||||
CFLAGS += -DWOLFBOOT_DEVID_CRYPT=0xA7
|
||||
WOLFCRYPT_OBJS += $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/cryptocb.o
|
||||
WOLFCRYPT_OBJS += \
|
||||
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/microchip/mpfs_athena.o
|
||||
# SHA-384 offload. Over a whole image in DDR it is slower than the software
|
||||
# hash, so an encrypted build wanting only the AES win sets MPFS_ATHENA_SHA=0.
|
||||
# hash, so an encrypted build wanting only the AES win sets MPFS_ATHENA_SHA=0,
|
||||
# which leaves WOLFBOOT_DEVID_HASH at INVALID_DEVID and image hashing in
|
||||
# software. The port's self-test still runs its SHA-384 known-answer test
|
||||
# whenever WOLFSSL_SHA384 is compiled, so the engine's hash path is still
|
||||
# brought up and checked; the knob moves the image hash, not the self-test.
|
||||
MPFS_ATHENA_SHA ?= 1
|
||||
ifeq ($(MPFS_ATHENA_SHA),1)
|
||||
CFLAGS += -DMPFS_ATHENA_SHA
|
||||
CFLAGS += -DMPFS_ATHENA_SHA -DWOLFBOOT_DEVID_HASH=0xA7
|
||||
endif
|
||||
# The hash offload and its self-check are SHA-384; an image hashed with
|
||||
# something else keeps that in software and still gets the AES offload.
|
||||
|
|
@ -2007,20 +2032,17 @@ ifeq ($(MPFS_ATHENA),1)
|
|||
# Archive name differs between Microchip's two published builds.
|
||||
MPFS_ATHENA_CAL_LIB ?= mpfs-rv64imac-user-crypto-lib.a
|
||||
LIBS += $(MPFS_ATHENA_CAL_DIR)/$(MPFS_ATHENA_CAL_LIB)
|
||||
# AES-256-CTR offload rides on the AES-CTR path an AES-256 ENCRYPT build
|
||||
# compiles; other builds offload the hash only. MPFS_ATHENA_AES=0 opts out.
|
||||
ifeq ($(ENCRYPT_WITH_AES256),1)
|
||||
MPFS_ATHENA_AES ?= 1
|
||||
ifeq ($(MPFS_ATHENA_AES),1)
|
||||
CFLAGS += -DMPFS_ATHENA_AES
|
||||
endif
|
||||
endif
|
||||
# AES-256-CTR offload now follows the port's own WOLFSSL_AES_COUNTER gate, so
|
||||
# it is present exactly when an AES-256 ENCRYPT build compiles that path.
|
||||
# With neither offload selected the engine is brought up and self-checked for
|
||||
# nothing, so say so rather than linking CAL into a build that cannot use it.
|
||||
# ENCRYPT_WITH_AES256=1 on its own is not enough: WOLFSSL_AES_COUNTER, which
|
||||
# the port's cipher path is gated on, is only defined under ENCRYPT=1.
|
||||
ifneq ($(MPFS_ATHENA_SHA),1)
|
||||
ifneq ($(MPFS_ATHENA_AES),1)
|
||||
ifneq ($(ENCRYPT)$(ENCRYPT_WITH_AES256),11)
|
||||
$(error MPFS_ATHENA=1 with MPFS_ATHENA_SHA=0 and no AES offload leaves \
|
||||
nothing offloaded: drop MPFS_ATHENA, or set ENCRYPT_WITH_AES256=1)
|
||||
nothing offloaded: drop MPFS_ATHENA, or set ENCRYPT=1 \
|
||||
ENCRYPT_WITH_AES256=1)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue