Skip to content

Commit

Permalink
[ot] hw/opentitan: ot_hmac: Add STOP/CONTINUE commands to HMAC
Browse files Browse the repository at this point in the history
Adds the STOP/CONTINUE commands to the OpenTitan HMAC model. These
commands allow you to stop a SHA/HMAC hash after the next full round of
hashing/compression, and retrieve the partial digest so that this
context can be restored later and computation can continue. This lets
users stop/start the HMAC as needed, and better cache hash computations.

To correctly implement these commands, in addition to writing back the
partial intermediary digests of the `sha_process` operations, additional
conditional logic is introduced on stop commands for only processing the
FIFO until the next hash block boundary, and an additional check is
added to the `process` call for the hash being completed.

Note that this commit still hard-codes for SHA256, and does not update
the corresponding DIGEST / MESSAGE LENGTH registers to be writable.

Signed-off-by: Alex Jones <[email protected]>
  • Loading branch information
AlexJones0 committed Dec 11, 2024
1 parent 2c5f13d commit 0fb5872
Showing 1 changed file with 56 additions and 4 deletions.
60 changes: 56 additions & 4 deletions hw/opentitan/ot_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,14 +344,30 @@ static void ot_hmac_process_fifo(OtHMACState *s)
{
trace_ot_hmac_debug(s->ot_id, __func__);

if (!fifo8_is_empty(&s->input_fifo)) {
while (!fifo8_is_empty(&s->input_fifo)) {
bool stop = s->regs->cmd & R_CMD_HASH_STOP_MASK;

if (!fifo8_is_empty(&s->input_fifo) &&
(!stop || s->ctx->state.sha256.curlen != 0)) {
while (!fifo8_is_empty(&s->input_fifo) &&
(!stop || s->ctx->state.sha256.curlen != 0)) {
uint8_t value = fifo8_pop(&s->input_fifo);
ot_hmac_sha_process(s, &value, 1u, false);
}

/* write back updated digest state */
if (fifo8_is_empty(&s->input_fifo) || stop) {
ot_hmac_writeback_digest_state(s);
}

/* assert FIFO Empty IRQ */
s->regs->intr_state |= INTR_FIFO_EMPTY_MASK;
if (fifo8_is_empty(&s->input_fifo)) {
s->regs->intr_state |= INTR_FIFO_EMPTY_MASK;
}
}

if (stop && s->ctx->state.sha256.curlen == 0) {
s->regs->intr_state |= INTR_HMAC_DONE_MASK;
s->regs->cmd = 0;
}

if (s->regs->cmd & R_CMD_HASH_PROCESS_MASK) {
Expand Down Expand Up @@ -633,7 +649,8 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
}

if (val32 & R_CMD_HASH_PROCESS_MASK) {
if (!(s->regs->cmd & R_CMD_HASH_START_MASK)) {
if (!(s->regs->cmd &
(R_CMD_HASH_START_MASK | R_CMD_HASH_CONTINUE_MASK))) {
qemu_log_mask(
LOG_GUEST_ERROR,
"%s: CMD.PROCESS requested but hash not started yet\n",
Expand All @@ -653,6 +670,41 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
ibex_irq_set(&s->clkmgr, true);
ot_hmac_process_fifo(s);
}

if (val32 & R_CMD_HASH_STOP_MASK) {
s->regs->cmd = R_CMD_HASH_STOP_MASK;

/* trigger delayed processing of FIFO until the next block is processed. */
ibex_irq_set(&s->clkmgr, true);
ot_hmac_process_fifo(s);
}

if (val32 & R_CMD_HASH_CONTINUE_MASK) {
if (!(s->regs->cfg & R_CFG_SHA_EN_MASK)) {
ot_hmac_report_error(s,
R_ERR_CODE_HASH_START_WHEN_SHA_DISABLED);
break;
}
if (s->regs->cmd) {
ot_hmac_report_error(s, R_ERR_CODE_HASH_START_WHEN_ACTIVE);
break;
}

s->regs->cmd = R_CMD_HASH_CONTINUE_MASK;

/* Restore SHA256 context */
s->ctx->state.sha256.curlen = 0;
s->ctx->state.sha256.length = s->regs->msg_length;
unsigned digest_length = OT_HMAC_DIGEST_LENGTH / sizeof(uint32_t);
for (unsigned i = 0; i < digest_length; i++) {
s->ctx->state.sha256.state[i] = s->regs->digest[i];
}

/* trigger delayed processing of FIFO */
ibex_irq_set(&s->clkmgr, true);
ot_hmac_process_fifo(s);
}

break;
case R_WIPE_SECRET:
/* TODO ignore write if engine is not idle? */
Expand Down

0 comments on commit 0fb5872

Please sign in to comment.