Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hmac tests #25825

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hw/top_earlgrey/data/ip/chip_hmac_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@
si_stage: SV3
lc_states: ["PROD"]
tests: []
bazel: []
bazel: ["//sw/device/tests:hmac_error_conditions_test"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding tests that are not mentioned in the testplan (e.g., run_test_invalidconfig_keylength). Could you please update the testplan to document the additional tests?

}
]
}
25 changes: 25 additions & 0 deletions sw/device/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7280,3 +7280,28 @@ opentitan_test(
"//sw/device/lib/testing/test_framework:ottf_utils",
],
)

opentitan_test(
name = "hmac_error_conditions_test",
srcs = ["hmac_error_conditions_test.c"],
exec_env = dicts.add(
EARLGREY_SILICON_OWNER_ROM_EXT_ENVS,
{
"//hw/top_earlgrey:sim_verilator": None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest moving these changes into the same commit as the first commit in this PR?

"//hw/top_earlgrey:fpga_cw340_sival": None,
"//hw/top_earlgrey:silicon_creator": None,
},
),
verilator = verilator_params(
timeout = "long",
),
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/arch:device",
"//sw/device/lib/base:mmio",
"//sw/device/lib/dif:hmac",
"//sw/device/lib/runtime:log",
"//sw/device/lib/testing:hmac_testutils",
"//sw/device/lib/testing/test_framework:ottf_main",
],
)
360 changes: 360 additions & 0 deletions sw/device/tests/hmac_error_conditions_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,360 @@
// Copyright lowRISC contributors (OpenTitan project).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a subject tag to the commit message header?

// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/base/abs_mmio.h"
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_hmac.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/hmac_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"

OTTF_DEFINE_TEST_CONFIG();

#define TOP_EARLGREY_HMAC_BASE_ADDR 0x41110000u
#define HMAC_CFG_REG_OFFSET 0x10
#define HMAC_CFG_SHA_EN_BIT_FIELD 0x01
#define HMAC_CFG_HMAC_EN_BIT_FIELD 0x00
#define HMAC_INTR_STATE_ERR_BIT_FIELD 0x02
#define HMAC_CMD_HASHSTARTBIT_FIELD 0x00
#define HMAC_CMD_HASHCONTINUEBIT_FIELD 0x03
#define HMAC_CMD_HASHSTOPBIT_FIELD 0x02
#define HMAC_CFG_SHADIGEST_FIELD 0x08

#define HMAC_INTR_TEST_ERR_BIT 0x01
#define HMAC_CMD_REG_OFFSET 0x14
#define HMAC_ERROR_REG_OFFSET 0x1c
#define HMAC_STATUS_REG_OFFSET 0x18
#define HMAC_INTR_TEST_REG_OFFSET 0x8
#define HMAC_INTR_STATE_REG_OFFSET 0x0
#define HMAC_INTR_ENABLE_REG_OFFSET 0x4
#define HMAC_WIPE_SECRET_REG_OFFSET 0x20
#define HMAC_CFG_SHADIGEST_VAL 0x3

#define HMAC_CFG_SHADIGEST_NONE 0x8
#define HMAC_CFG_KEYLEN_VAL 0x20
Comment on lines +18 to +39
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace this by including #include "hmac_regs.h". By including this, your code will also in the future as the registers can change.


// keylen_field32.mask = 0b11;
// keylenfield.index = 12;
// uint32_t HMAC_CFG_KEYLEN_VAL_VAR = 0b;
Comment on lines +41 to +43
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this.


enum {
/* The beginning of the address space of HMAC. */
kHmacBaseAddr = TOP_EARLGREY_HMAC_BASE_ADDR,
};
Comment on lines +45 to +48
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, you can replace this by just accessing the base address via the HMAC object, e.g., hmac.base_addr


static const dif_hmac_transaction_t kHmacTransactionConfig = {
.digest_endianness = kDifHmacEndiannessLittle,
.message_endianness = kDifHmacEndiannessLittle,
};

static const char kData[142] =
"Every one suspects himself of at least one of "
"the cardinal virtues, and this is mine: I am "
"one of the few honest people that I have ever "
"known";

static uint32_t kHmacKey[8] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also applies to this change.

0xec4e6c89, 0x082efa98, 0x299f31d0, 0xa4093822,
0x03707344, 0x13198a2e, 0x85a308d3, 0x243f6a88,
};

static const dif_hmac_digest_t kExpectedShaDigest = {
.digest =
{
0xd6c6c94e,
0xf7cff519,
0x45c76d42,
0x9d37a8b8,
0xe2762fe9,
0x71ff68cb,
0x68e236af,
0x3dc296dc,
},
};

static const dif_hmac_digest_t kExpectedHmacDigest = {
.digest =
{
0xebce4019,
0x284d39f1,
0x5eae12b0,
0x0c48fb23,
0xfadb9531,
0xafbbf3c2,
0x90d3833f,
0x397b98e4,
},
};

/**
* Initialize the HMAC engine. Return `true` if the configuration is valid.
*/
static void test_setup(mmio_region_t base_addr, dif_hmac_t *hmac) {
CHECK_DIF_OK(dif_hmac_init(base_addr, hmac));
}

/**
* Start HMAC in the correct mode. If `key` == NULL use SHA256 mode, otherwise
* use the provided key in HMAC mode.
*/

static void test_start(const dif_hmac_t *hmac, const uint8_t *key) {
// Let a null key indicate we are operating in SHA256-only mode.
if (key == NULL) {
CHECK_DIF_OK(dif_hmac_mode_sha256_start(hmac, kHmacTransactionConfig));
} else {
CHECK_DIF_OK(dif_hmac_mode_hmac_start(hmac, key, kHmacTransactionConfig));
}
}

/**
* Kick off the HMAC (or SHA256) run.
*/
static void run_hmac(const dif_hmac_t *hmac) {
CHECK_DIF_OK(dif_hmac_process(hmac));
}

static void run_hmac_enable_interrupt(void) {
// Enable Interrupt enable register
uint32_t intr_enable_reg_val_set = 0x0007;
abs_mmio_write32(kHmacBaseAddr + HMAC_INTR_ENABLE_REG_OFFSET,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace all kHmacBaseAddr with hmac.base_addr.

intr_enable_reg_val_set);
}
static void run_hmac_clear_interrupt(void) {
uint32_t intr_state_reg_val_reset = 0x0007;
abs_mmio_write32(kHmacBaseAddr + HMAC_INTR_STATE_REG_OFFSET,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@engdoreis is there a suggestion when to use abs_mmio_write32() vs mmio_region_write32()?

intr_state_reg_val_reset);
}

// The following function reports error when attempts to write data into the
// message FIFO (MSG_FIFO) while the SHA engine is disabled.
static void run_test_pushmsg_when_shadisabled(
const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x05;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit suprised that the HMAC DIF driver does not provide error codes. For example, KMAC provides this structure in the DIF:

typedef enum dif_kmac_error {
/**
* No error has occured.
*/
kDifErrorNone = 0,
/**
* The Key Manager has raised an error because the secret key is not valid.
*/
kDifErrorKeyNotValid = 1,
/**
* An attempt was made to write data into the message FIFO but the KMAC unit
* was not in the correct state to receive the data.
*/
kDifErrorSoftwarePushedMessageFifo = 2,
/**
* SW issued a command while a HW application interface was using KMAC.
*/
kDifErrorSoftwareIssuedCommandWhileAppInterfaceActive = 3,
/**
* The entropy wait timer has expired.
*/
kDifErrorEntropyWaitTimerExpired = 4,
/**
* Incorrect entropy mode when entropy is ready.
*/
kDifErrorEntropyModeIncorrect = 5,
kDifErrorUnexpectedModeStrength = 6,
kDifErrorIncorrectFunctionName = 7,
kDifErrorSoftwareCommandSequence = 8,
kDifErrorSoftwareHashingWithoutEntropyReady = 9,
kDifErrorFatalError = 0xC1,
kDifErrorPackerIntegrity = 0xC2,
kDifErrorMsgFifoIntegrity = 0xC3,
} dif_kmac_error_t;

As I think adding this to the DIF is out of scope for this PR, maybe you can add a typedef for the different error codes you are expecting at the beginning of this test? Then it would be clearer what exactly error code 5 means.

run_hmac_enable_interrupt();
// Read current config register
uint32_t cfg_reg_3 = abs_mmio_read32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET);
// Disable SHA_EN
cfg_reg_3 = bitfield_bit32_write(cfg_reg_3, HMAC_CFG_SHA_EN_BIT_FIELD, false);
abs_mmio_write32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET, cfg_reg_3);
CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
uint32_t hmacerr_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmacerr_reg,
error_code_expected);
Comment on lines +147 to +150
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A print (LOG_INFO()) is not sufficient to check whether the test passed or failed. Please add something like:

TRY_CHECK(hmacerr_reg == error_code_expected, "Unexpected error was triggered.");

This applies throughout the entire code.

run_hmac_clear_interrupt();
}

// The following function reports error when attempts to write data into the
// message FIFO (MSG_FIFO) when hmac is already in process
static void run_test_pushmsg_when_disallowed(
const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x05;
run_hmac_enable_interrupt();
test_start(hmac, key);
CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
run_hmac(hmac);
uint32_t hmacerr_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmacerr_reg,
error_code_expected);
CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
run_hmac_clear_interrupt();
}
// The following function reports error when the HMAC has been incorrectly
// configured by software. This could include an invalid key length for HMAC
// mode
static void run_test_invalidconfig_keylength(
const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x06;
run_hmac_enable_interrupt();
// Set HMAC KeyLength to Key_none and SHA2/HMAC Digest size to SHA2_256
uint32_t cfg_reg = 0x4023;
abs_mmio_write32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET, cfg_reg);
uint32_t hmac_cmd_reg =
mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASHSTARTBIT_FIELD, true);
abs_mmio_write32(kHmacBaseAddr + HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
uint32_t hmacerr_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmacerr_reg,
error_code_expected);
CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
run_hmac(hmac);
hmac_cmd_reg = mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASHSTOPBIT_FIELD, true);
abs_mmio_write32(kHmacBaseAddr + HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
// Write default cfg reg values to clear the error
uint32_t cfg_reg_default = 0x4100;
abs_mmio_write32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET, cfg_reg_default);
run_hmac_clear_interrupt();
}

// The following function reports error is reported when the HMAC has been
// incorrectly configured by software. This could include an invalid digest size
// for SHA-2/HMAC modes or an invalid key length for HMAC mode
static void run_test_invalidconfig_digest(
const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x06;
run_hmac_enable_interrupt();
// Set HMAC KeyLength to 256 bit and SHA2/HMAC Digest size to SHA2_None
uint32_t cfg_reg = 0x0503;
abs_mmio_write32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET, cfg_reg);
uint32_t hmac_cmd_reg =
mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASHSTARTBIT_FIELD, true);
abs_mmio_write32(kHmacBaseAddr + HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
uint32_t hmacerr_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmacerr_reg,
error_code_expected);
CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
run_hmac(hmac);
hmac_cmd_reg = mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASHSTOPBIT_FIELD, true);
abs_mmio_write32(kHmacBaseAddr + HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
// Write default cfg reg values to clear the error
uint32_t cfg_reg_default = 0x4100;
abs_mmio_write32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET, cfg_reg_default);
run_hmac_clear_interrupt();
}

// The following function reports error is reported when the HMAC has been
// incorrectly configured by software. This could include an invalid digest size
// for SHA-2/HMAC modes or an invalid key length for HMAC mode
static void run_test_updatekey(const dif_hmac_t *hmac, const char *data,
size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x03;
run_hmac_enable_interrupt();
test_start(hmac, key);
CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
// Updating the config with swap key - while hmac engine is in process state
CHECK_DIF_OK(dif_hmac_mode_hmac_start(hmac, key, kHmacTransactionConfig));
uint32_t hmacerr_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmacerr_reg,
error_code_expected);
run_hmac(hmac);
run_hmac_clear_interrupt();
}

// Reported when CMD.start is received when SHA is disabled
static void run_test_hashstartwhendisabled(
const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x02;
run_hmac_enable_interrupt();
uint32_t cfg_reg = abs_mmio_read32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET);
// uint32_t hmac_cmd_reg1 = mmio_region_read32(hmac->base_addr,
// HMAC_CMD_REG_OFFSET);
// Disable SHA_EN
cfg_reg = bitfield_bit32_write(cfg_reg, HMAC_CFG_SHA_EN_BIT_FIELD, false);
abs_mmio_write32(kHmacBaseAddr + HMAC_CFG_REG_OFFSET, cfg_reg);
// Write HASH_START_BIT
uint32_t hmac_cmd_reg =
mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASHSTARTBIT_FIELD, true);
abs_mmio_write32(kHmacBaseAddr + HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
uint32_t hmacerr_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmacerr_reg,
error_code_expected);
run_hmac_clear_interrupt();
}

// Reported when CMD.start is received while the HMAC is running
static void run_test_hashstartwhenactive(
const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
const dif_hmac_digest_t *expected_digest) {
uint32_t error_code_expected = 0x04;
run_hmac_enable_interrupt();
test_start(hmac, key);
uint32_t hmac_cmd_reg =
mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
hmac_cmd_reg =
bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASHSTARTBIT_FIELD, true);
abs_mmio_write32(kHmacBaseAddr + HMAC_CMD_REG_OFFSET, hmac_cmd_reg);
uint32_t hmac_err_reg =
mmio_region_read32(hmac->base_addr, HMAC_ERROR_REG_OFFSET);
LOG_INFO("REGISTER HMAC_ERROR_CODE: 0x%x Expected:0x%x", hmac_err_reg,
error_code_expected);
run_hmac(hmac);
run_hmac_clear_interrupt();
}

bool test_main(void) {
LOG_INFO("Running HMAC Error Condition test...");

dif_hmac_t hmac;
test_setup(mmio_region_from_addr(TOP_EARLGREY_HMAC_BASE_ADDR), &hmac);
for (int error_condition = 1; error_condition < 9; error_condition++) {
switch (error_condition) {
Comment on lines +309 to +310
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A for + switch construct seems a bit unnecessary in my opinion.

case 1:
LOG_INFO("Running test push message when sha disabled...");
run_test_pushmsg_when_shadisabled(&hmac, kData, sizeof(kData), NULL,
&kExpectedHmacDigest);
break;
case 2:
LOG_INFO("Running Hash start test when sha is disabled...");
run_test_hashstartwhendisabled(&hmac, kData, sizeof(kData), NULL,
&kExpectedShaDigest);
break;
case 3:
LOG_INFO("Running test with key when disallowed..,");
run_test_updatekey(&hmac, kData, sizeof(kData),
(uint8_t *)(&kHmacKey[0]), &kExpectedHmacDigest);
break;
case 4:
LOG_INFO("Running test HMAC hash start when active...");
run_test_hashstartwhenactive(&hmac, kData, sizeof(kData),
(uint8_t *)(&kHmacKey[0]),
&kExpectedHmacDigest);
break;
case 5:
LOG_INFO("Running test push message when disallowed...");
run_test_pushmsg_when_disallowed(&hmac, kData, sizeof(kData),
(uint8_t *)(&kHmacKey[0]),
&kExpectedHmacDigest);
break;
case 6:
LOG_INFO("Running test HMAC invalid config keylength...");
run_test_invalidconfig_keylength(&hmac, kData, sizeof(kData),
(uint8_t *)(&kHmacKey[0]),
&kExpectedHmacDigest);
break;
case 7:
LOG_INFO("Running test HMAC hash start when active...");
run_test_hashstartwhenactive(&hmac, kData, sizeof(kData),
(uint8_t *)(&kHmacKey[0]),
&kExpectedHmacDigest);
break;
case 8:
LOG_INFO("Running test HMAC invalid config digest size...");
run_test_invalidconfig_digest(&hmac, kData, sizeof(kData),
(uint8_t *)(&kHmacKey[0]),
&kExpectedHmacDigest);
break;
}
}

return true;
}
Loading