From ed6068ff364652e76b4b5ff86371ff2446cb5a9b Mon Sep 17 00:00:00 2001 From: Alex Jones <alex.jones@lowrisc.org> Date: Wed, 19 Mar 2025 17:29:57 +0000 Subject: [PATCH] [ot] hw/opentitan: ot_hmac: Restore correct msg_length with HMAC_EN HMAC can operate either with HMAC_EN, using HMAC algorithms, or without, using standard SHA algorithms. The HMAC algorithms introduce additional logic surrounding a key, and inner and outer padding. Relevant to this commit is that when computing HMAC, we first process a block of inner padding XORed with the key. This means that the message length reported to software in the msg_length register diverges from the message length reported by the tomcrypt cryptographic library's state. Specifically, with HMAC_EN=1, it undercounts by a block. This caused an error where, when saving and restoring context with HMAC_EN=1, the hash length would be undercounted by a block and thus the incorrect digest would be computed. This meant that save/restore and streaming operations were not working properly with HMAC_EN. This commit introduces the additional logic to fix this edge case. Signed-off-by: Alex Jones <alex.jones@lowrisc.org> --- hw/opentitan/ot_hmac.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/opentitan/ot_hmac.c b/hw/opentitan/ot_hmac.c index 3bfdb578da31..ba5cd002dad8 100644 --- a/hw/opentitan/ot_hmac.c +++ b/hw/opentitan/ot_hmac.c @@ -2,7 +2,7 @@ * QEMU OpenTitan HMAC device * * Copyright (c) 2022-2024 Rivos, Inc. - * Copyright (c) 2024 lowRISC contributors. + * Copyright (c) 2024-2025 lowRISC contributors. * * Author(s): * Loïc Lefort <loic@rivosinc.com> @@ -443,10 +443,21 @@ static void ot_hmac_writeback_digest_state(OtHMACState *s) static void ot_hmac_restore_context(OtHMACState *s) { + /* + * When restoring context, if HMAC is enabled we must add the block size to + * the message length to keep our cryptographic library consistent with the + * SW interface. This is because the extra block containing the key XORed + * with the inner pad is not included in the SW-visible message length. + */ + unsigned msg_length = s->regs->msg_length; + if (s->regs->cfg & R_CFG_HMAC_EN_MASK) { + msg_length += ot_hmac_get_block_size_bytes(s) * 8u; + } + 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; + s->ctx->state.sha256.length = msg_length; for (unsigned idx = 0; idx < 8u; idx++) { LOAD32H(s->ctx->state.sha256.state[idx], s->regs->digest + idx); } @@ -458,7 +469,7 @@ static void ot_hmac_restore_context(OtHMACState *s) */ case HMAC_SHA2_512: s->ctx->state.sha512.curlen = 0; - s->ctx->state.sha512.length = s->regs->msg_length; + s->ctx->state.sha512.length = msg_length; for (unsigned idx = 0; idx < 8u; idx++) { LOAD64H(s->ctx->state.sha512.state[idx], s->regs->digest + 2 * idx); }