From f6038756db576e7758f5a3d94e984a673fca87d8 Mon Sep 17 00:00:00 2001 From: Alex Jones Date: Thu, 12 Dec 2024 14:56:42 +0000 Subject: [PATCH] [ot] hw/opentitan: ot_hmac: Digest size write should not affect current hash This commit updates the functionality for the HMAC's digest size configuration register field, updating it to match the current hardware behaviour. The hardware uses a `digest_size_started` field to allow the user to write a digest size at any time, while ensuring that if a hash is in progress it will carry on using the existing digest size. A similar field is introduced into the context/state struct to allow the QEMU HMAC model to keep track of the digest size when the last START/CONTINUE command was sent, and use that in place of checking the register value every time. --- hw/opentitan/ot_hmac.c | 65 ++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/hw/opentitan/ot_hmac.c b/hw/opentitan/ot_hmac.c index 7e2959bfc8f1..d61bc76c8b2a 100644 --- a/hw/opentitan/ot_hmac.c +++ b/hw/opentitan/ot_hmac.c @@ -229,6 +229,22 @@ static const char *REG_NAMES[REGS_COUNT] = { }; #undef REG_NAME_ENTRY +typedef enum OtHMACDigestSize { + HMAC_SHA2_NONE, + HMAC_SHA2_256, + HMAC_SHA2_384, + HMAC_SHA2_512, +} OtHMACDigestSize; + +typedef enum OtHMACKeyLength { + HMAC_KEY_NONE, + HMAC_KEY_128, + HMAC_KEY_256, + HMAC_KEY_384, + HMAC_KEY_512, + HMAC_KEY_1024, +} OtHMACKeyLength; + struct OtHMACRegisters { uint32_t intr_state; uint32_t intr_enable; @@ -245,6 +261,7 @@ typedef struct OtHMACRegisters OtHMACRegisters; struct OtHMACContext { hash_state state; + OtHMACDigestSize digest_size_started; }; typedef struct OtHMACContext OtHMACContext; @@ -266,22 +283,6 @@ struct OtHMACState { char *ot_id; }; -typedef enum OtHMACDigestSize { - HMAC_SHA2_NONE, - HMAC_SHA2_256, - HMAC_SHA2_384, - HMAC_SHA2_512, -} OtHMACDigestSize; - -typedef enum OtHMACKeyLength { - HMAC_KEY_NONE, - HMAC_KEY_128, - HMAC_KEY_256, - HMAC_KEY_384, - HMAC_KEY_512, - HMAC_KEY_1024, -} OtHMACKeyLength; - static inline OtHMACDigestSize ot_hmac_get_digest_size(uint32_t cfg_reg) { switch ((cfg_reg & R_CFG_DIGEST_SIZE_MASK) >> R_CFG_DIGEST_SIZE_SHIFT) { @@ -297,9 +298,9 @@ static inline OtHMACDigestSize ot_hmac_get_digest_size(uint32_t cfg_reg) } } -static size_t ot_hmac_get_digest_bytes(OtHMACState *s) +static size_t ot_hmac_get_digest_bytes(OtHMACDigestSize digest_size) { - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (digest_size) { case HMAC_SHA2_256: return 32u; case HMAC_SHA2_384: @@ -412,7 +413,7 @@ static void ot_hmac_report_error(OtHMACState *s, uint32_t error) static void ot_hmac_writeback_digest_state(OtHMACState *s) { /* copy intermediary digest to mock HMAC's stop/continue behaviour. */ - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (s->ctx->digest_size_started) { case HMAC_SHA2_256: for (unsigned idx = 0; idx < 8u; idx++) { STORE32H(s->ctx->state.sha256.state[idx], s->regs->digest + idx); @@ -441,7 +442,7 @@ static void ot_hmac_writeback_digest_state(OtHMACState *s) static void ot_hmac_restore_context(OtHMACState *s) { - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (s->ctx->digest_size_started) { case HMAC_SHA2_256: s->ctx->state.sha256.curlen = 0; s->ctx->state.sha256.length = s->regs->msg_length; @@ -473,7 +474,7 @@ static void ot_hmac_restore_context(OtHMACState *s) static size_t ot_hmac_get_curlen(OtHMACState *s) { - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (s->ctx->digest_size_started) { case HMAC_SHA2_256: return s->ctx->state.sha256.curlen; case HMAC_SHA2_384: @@ -492,7 +493,7 @@ static size_t ot_hmac_get_curlen(OtHMACState *s) static void ot_hmac_sha_init(OtHMACState *s, bool write_back) { - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (s->ctx->digest_size_started) { case HMAC_SHA2_256: sha256_init(&s->ctx->state); break; @@ -519,7 +520,7 @@ static void ot_hmac_sha_init(OtHMACState *s, bool write_back) static void ot_hmac_sha_process(OtHMACState *s, const uint8_t *in, size_t inlen, bool write_back) { - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (s->ctx->digest_size_started) { case HMAC_SHA2_256: sha256_process(&s->ctx->state, in, inlen); break; @@ -546,7 +547,7 @@ static void ot_hmac_sha_process(OtHMACState *s, const uint8_t *in, size_t inlen, static void ot_hmac_sha_done(OtHMACState *s) { - switch (ot_hmac_get_digest_size(s->regs->cfg)) { + switch (s->ctx->digest_size_started) { case HMAC_SHA2_256: sha256_done(&s->ctx->state, (uint8_t *)s->regs->digest); return; @@ -589,7 +590,9 @@ static void ot_hmac_compute_digest(OtHMACState *s) ot_hmac_sha_init(s, false); ot_hmac_sha_process(s, (const uint8_t *)opad, pad_length_b, false); ot_hmac_sha_process(s, (const uint8_t *)s->regs->digest, - ot_hmac_get_digest_bytes(s), true); + ot_hmac_get_digest_bytes( + s->ctx->digest_size_started), + true); } ot_hmac_sha_done(s); } @@ -931,6 +934,12 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value, ibex_irq_set(&s->clkmgr, true); + /* + * Hold the previous digest size until the HMAC is started with the + * new digest size configured + */ + s->ctx->digest_size_started = ot_hmac_get_digest_size(s->regs->cfg); + ot_hmac_sha_init(s, true); /* HMAC mode, process input padding */ @@ -998,6 +1007,12 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value, s->regs->cmd = R_CMD_HASH_CONTINUE_MASK; + /* + * Hold the previous digest size until the HMAC is started with the + * new digest size configured + */ + s->ctx->digest_size_started = ot_hmac_get_digest_size(s->regs->cfg); + ot_hmac_restore_context(s); /* trigger delayed processing of FIFO */