Skip to content

Commit 70e9305

Browse files
committed
[ot] hw/opentitan: ot_hmac: Implement key/digest size regs & checks
This commit implements initial register interface support for the key length and digest size fields in the config register of OpenTitan's HMAC. It checks that the values written are valid one-hot encodings, and maps them as is done in current hardware if not. This also implements some additional checks that the combination of (key length, digest size, HMAC enable) is valid when attempting to run the START/CONTINUE command, otherwise producing a (new type of) software error.
1 parent 4583274 commit 70e9305

File tree

1 file changed

+94
-2
lines changed

1 file changed

+94
-2
lines changed

hw/opentitan/ot_hmac.c

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ REG32(ERR_CODE, 0x1cu)
8585
#define R_ERR_CODE_UPDATE_SECRET_KEY_INPROCESS 0x00000003u
8686
#define R_ERR_CODE_HASH_START_WHEN_ACTIVE 0x00000004u
8787
#define R_ERR_CODE_PUSH_MSG_WHEN_DISALLOWED 0x00000005u
88+
#define R_ERR_CODE_INVALID_CONFIG 0x00000006u
8889
REG32(WIPE_SECRET, 0x20u)
8990
REG32(KEY_0, 0x24u)
9091
REG32(KEY_1, 0x28u)
@@ -259,6 +260,62 @@ struct OtHMACState {
259260
char *ot_id;
260261
};
261262

263+
enum OtHMACDigestSize {
264+
HMAC_SHA2_256,
265+
HMAC_SHA2_384,
266+
HMAC_SHA2_512,
267+
HMAC_SHA2_NONE,
268+
};
269+
270+
enum OtHMACKeyLength {
271+
HMAC_KEY_128,
272+
HMAC_KEY_256,
273+
HMAC_KEY_384,
274+
HMAC_KEY_512,
275+
HMAC_KEY_1024,
276+
HMAC_KEY_NONE,
277+
};
278+
279+
static inline enum OtHMACDigestSize ot_hmac_get_digest_size(uint32_t cfg_reg)
280+
{
281+
switch ((cfg_reg & R_CFG_DIGEST_SIZE_MASK) >> R_CFG_DIGEST_SIZE_SHIFT) {
282+
case 0x1u:
283+
return HMAC_SHA2_256;
284+
case 0x2u:
285+
return HMAC_SHA2_384;
286+
case 0x4u:
287+
return HMAC_SHA2_512;
288+
case 0x8u:
289+
default:
290+
return HMAC_SHA2_NONE;
291+
}
292+
}
293+
294+
static inline enum OtHMACKeyLength ot_hmac_get_key_length(uint32_t cfg_reg)
295+
{
296+
switch ((cfg_reg & R_CFG_KEY_LENGTH_MASK) >> R_CFG_KEY_LENGTH_SHIFT) {
297+
case 0x01u:
298+
return HMAC_KEY_128;
299+
case 0x02u:
300+
return HMAC_KEY_256;
301+
case 0x04u:
302+
return HMAC_KEY_384;
303+
case 0x08u:
304+
return HMAC_KEY_512;
305+
case 0x10u:
306+
return HMAC_KEY_1024;
307+
case 0x20u:
308+
default:
309+
return HMAC_KEY_NONE;
310+
}
311+
}
312+
313+
static inline bool ot_hmac_key_length_supported(
314+
enum OtHMACDigestSize digest_size, enum OtHMACKeyLength key_length)
315+
{
316+
return !(digest_size == HMAC_SHA2_256 && key_length == HMAC_KEY_1024);
317+
}
318+
262319
static void ot_hmac_update_irqs(OtHMACState *s)
263320
{
264321
uint32_t levels = s->regs->intr_state & s->regs->intr_enable;
@@ -589,6 +646,9 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
589646
uint32_t pc = ibex_get_current_pc();
590647
trace_ot_hmac_io_write(s->ot_id, (uint32_t)addr, REG_NAME(reg), val32, pc);
591648

649+
enum OtHMACDigestSize digest_size;
650+
enum OtHMACKeyLength key_length;
651+
592652
switch (reg) {
593653
case R_INTR_STATE:
594654
s->regs->intr_state &= ~(val32 & INTR_MASK);
@@ -612,19 +672,51 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
612672
break;
613673
}
614674

615-
s->regs->cfg =
616-
val32 &
675+
val32 &=
617676
(R_CFG_HMAC_EN_MASK | R_CFG_SHA_EN_MASK | R_CFG_ENDIAN_SWAP_MASK |
618677
R_CFG_DIGEST_SWAP_MASK | R_CFG_KEY_SWAP_MASK |
619678
R_CFG_DIGEST_SIZE_MASK | R_CFG_KEY_LENGTH_MASK);
620679

680+
/* If the digest size is invalid, it gets mapped to SHA2_NONE. */
681+
digest_size = ot_hmac_get_digest_size(val32);
682+
if (digest_size == HMAC_SHA2_NONE) {
683+
val32 &= ~R_CFG_DIGEST_SIZE_MASK;
684+
val32 |= 0x8u << R_CFG_DIGEST_SIZE_SHIFT;
685+
}
686+
687+
/* If the key length is invalid, it gets mapped to KEY_NONE. */
688+
key_length = ot_hmac_get_key_length(val32);
689+
if (key_length == HMAC_KEY_NONE) {
690+
val32 &= ~R_CFG_KEY_LENGTH_MASK;
691+
val32 |= 0x20u << R_CFG_KEY_LENGTH_SHIFT;
692+
}
693+
694+
s->regs->cfg = val32;
695+
621696
/* clear digest when SHA is disabled */
622697
if (!(s->regs->cfg & R_CFG_SHA_EN_MASK)) {
623698
ot_hmac_wipe_buffer(s, s->regs->digest,
624699
ARRAY_SIZE(s->regs->digest));
625700
}
626701
break;
627702
case R_CMD:
703+
if (val32 & (R_CMD_HASH_START_MASK | R_CMD_HASH_CONTINUE_MASK)) {
704+
digest_size = ot_hmac_get_digest_size(s->regs->cfg);
705+
if (digest_size == HMAC_SHA2_NONE) {
706+
ot_hmac_report_error(s, R_ERR_CODE_INVALID_CONFIG);
707+
break;
708+
}
709+
710+
if (s->regs->cfg & R_CFG_HMAC_EN_MASK) {
711+
key_length = ot_hmac_get_key_length(s->regs->cfg);
712+
if (key_length == HMAC_KEY_NONE ||
713+
!ot_hmac_key_length_supported(digest_size, key_length)) {
714+
ot_hmac_report_error(s, R_ERR_CODE_INVALID_CONFIG);
715+
break;
716+
}
717+
}
718+
}
719+
628720
if (val32 & R_CMD_HASH_START_MASK) {
629721
if (!(s->regs->cfg & R_CFG_SHA_EN_MASK)) {
630722
ot_hmac_report_error(s,

0 commit comments

Comments
 (0)