Software APIs
hmac_error_conditions_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
12 #include "sw/device/lib/testing/hmac_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
17 
18 OTTF_DEFINE_TEST_CONFIG();
19 
20 #include "hmac_regs.h"
21 
22 typedef enum hmac_err {
23 
24  /**
25  * No error has occured.
26  */
27  kErrorNone = 0x0,
28 
29  /**
30  * This error is reported when HMAC detects the CMD.start command while SHA is
31  * disabled
32  */
33  kErrorSwHashStartWhenShaDisabled = 0x02,
34 
35  /**
36  *This error occurs when software attempts to modify the secret key CSRs
37  *during hashing
38  */
39  kErrorSwUpdateSecretKeyInProcess = 0x03,
40 
41  /**
42  *This error is reported when CMD.start is received while HMAC is running
43  */
44  kErrorSwHashStartWhenActive = 0x04,
45 
46  /**
47  *This error is reported when the MSG_FIFO is updated when disallowed
48  */
49  kErrorSwPushMsgWhenDisallowed = 0x05,
50 
51  /**
52  *This error is reported when HMAC has been configured incorrectly by software
53  */
54  kErrorSwInvalidConfig = 0x06,
55 
56 } hmac_error_t;
57 
58 static const dif_hmac_transaction_t kHmacTransactionConfig = {
60  .message_endianness = kDifHmacEndiannessLittle,
61 };
62 
63 static const char kData[142] =
64  "Every one suspects himself of at least one of "
65  "the cardinal virtues, and this is mine: I am "
66  "one of the few honest people that I have ever "
67  "known";
68 
69 static uint32_t kHmacKey[8] = {
70  0xec4e6c89, 0x082efa98, 0x299f31d0, 0xa4093822,
71  0x03707344, 0x13198a2e, 0x85a308d3, 0x243f6a88,
72 };
73 
74 static const dif_hmac_digest_t kExpectedShaDigest = {
75  .digest =
76  {
77  0xd6c6c94e,
78  0xf7cff519,
79  0x45c76d42,
80  0x9d37a8b8,
81  0xe2762fe9,
82  0x71ff68cb,
83  0x68e236af,
84  0x3dc296dc,
85  },
86 };
87 
88 static const dif_hmac_digest_t kExpectedHmacDigest = {
89  .digest =
90  {
91  0xebce4019,
92  0x284d39f1,
93  0x5eae12b0,
94  0x0c48fb23,
95  0xfadb9531,
96  0xafbbf3c2,
97  0x90d3833f,
98  0x397b98e4,
99  },
100 };
101 
102 /**
103  * Initialize the HMAC engine. Return `true` if the configuration is valid.
104  */
105 static void test_setup(mmio_region_t base_addr, dif_hmac_t *hmac) {
106  CHECK_DIF_OK(dif_hmac_init(base_addr, hmac));
107 }
108 
109 /**
110  * Start HMAC in the correct mode. If `key` == NULL use SHA256 mode, otherwise
111  * use the provided key in HMAC mode.
112  */
113 
114 static void test_start(const dif_hmac_t *hmac, const uint8_t *key) {
115  // Let a null key indicate we are operating in SHA256-only mode.
116  if (key == NULL) {
117  CHECK_DIF_OK(dif_hmac_mode_sha256_start(hmac, kHmacTransactionConfig));
118  } else {
119  CHECK_DIF_OK(dif_hmac_mode_hmac_start(hmac, key, kHmacTransactionConfig));
120  }
121 }
122 
123 /**
124  * Kick off the HMAC (or SHA256) run.
125  */
126 static void run_hmac(const dif_hmac_t *hmac) {
127  CHECK_DIF_OK(dif_hmac_process(hmac));
128 }
129 
130 static void run_hmac_enable_interrupt(void) {
131  // Enable Interrupt enable register
132  uint32_t reg = 0;
133  reg = bitfield_bit32_write(reg, HMAC_INTR_ENABLE_HMAC_DONE_BIT, true);
134  reg = bitfield_bit32_write(reg, HMAC_INTR_ENABLE_FIFO_EMPTY_BIT, true);
135  reg = bitfield_bit32_write(reg, HMAC_INTR_ENABLE_HMAC_ERR_BIT, true);
136  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_INTR_ENABLE_REG_OFFSET,
137  reg);
138 }
139 
140 static void run_hmac_clear_interrupt(void) {
141  uint32_t reg = 0;
142  reg = bitfield_bit32_write(reg, HMAC_INTR_STATE_HMAC_DONE_BIT, true);
143  reg = bitfield_bit32_write(reg, HMAC_INTR_STATE_FIFO_EMPTY_BIT, true);
144  reg = bitfield_bit32_write(reg, HMAC_INTR_STATE_HMAC_ERR_BIT, true);
145  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_INTR_STATE_REG_OFFSET,
146  reg);
147 }
148 
149 // The following function reports error when attempts to write data into the
150 // message FIFO (MSG_FIFO) while the SHA engine is disabled.
151 status_t run_test_pushmsg_when_shadisabled(
152  const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
153  const dif_hmac_digest_t *expected_digest) {
154  run_hmac_enable_interrupt();
155  // Read current config register
156  uint32_t cfg_reg_3 =
157  abs_mmio_read32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET);
158  // Disable SHA_EN
159  cfg_reg_3 = bitfield_bit32_write(cfg_reg_3, HMAC_CFG_SHA_EN_BIT, false);
160  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET,
161  cfg_reg_3);
162  CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
163  uint32_t hmac_err_reg =
164  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
165  TRY_CHECK(hmac_err_reg == kErrorSwPushMsgWhenDisallowed,
166  "Error code doesn't match expected code ");
167  run_hmac_clear_interrupt();
168  return OK_STATUS();
169 }
170 
171 // The following function reports error when attempts to write data into the
172 // message FIFO (MSG_FIFO) when hmac is already in process
173 status_t run_test_pushmsg_when_disallowed(
174  const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
175  const dif_hmac_digest_t *expected_digest) {
176  run_hmac_enable_interrupt();
177  test_start(hmac, key);
178  CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
179  CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
180  run_hmac(hmac);
181  CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
182  uint32_t hmac_err_reg =
183  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
184  TRY_CHECK(hmac_err_reg == kErrorSwPushMsgWhenDisallowed,
185  "Error code doesn't match expected code");
186  CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
187  run_hmac_clear_interrupt();
188  return OK_STATUS();
189 }
190 // The following function reports error when the HMAC has been incorrectly
191 // configured by software. This could include an invalid key length for HMAC
192 // mode
193 status_t run_test_invalidconfig_keylength(
194  const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
195  const dif_hmac_digest_t *expected_digest) {
196  run_hmac_enable_interrupt();
197  // Set HMAC KeyLength to Key_none and SHA2/HMAC Digest size to SHA2_256
198  uint32_t reg = 0;
199  reg = bitfield_field32_write(reg, HMAC_CFG_KEY_LENGTH_FIELD,
200  HMAC_CFG_KEY_LENGTH_VALUE_KEY_NONE);
201  reg = bitfield_field32_write(reg, HMAC_CFG_DIGEST_SIZE_FIELD,
202  HMAC_CFG_DIGEST_SIZE_VALUE_SHA2_256);
203  reg = bitfield_bit32_write(reg, HMAC_CFG_SHA_EN_BIT, true);
204  reg = bitfield_bit32_write(reg, HMAC_CFG_HMAC_EN_BIT, true);
205  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET, reg);
206  uint32_t hmac_cmd_reg =
207  mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
208  hmac_cmd_reg =
209  bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_START_BIT, true);
210  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET,
211  hmac_cmd_reg);
212  uint32_t hmacerr_reg =
213  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
214  TRY_CHECK(hmacerr_reg == kErrorSwInvalidConfig,
215  "Error code doesn't match expected code");
216  CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
217  CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
218  run_hmac(hmac);
219  hmac_cmd_reg = mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
220  hmac_cmd_reg =
221  bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_STOP_BIT, true);
222  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET,
223  hmac_cmd_reg);
224  // Write default cfg reg values to clear the error
225  uint32_t cfg_reg_default = HMAC_CFG_REG_RESVAL;
226  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET,
227  cfg_reg_default);
228  run_hmac_clear_interrupt();
229  return OK_STATUS();
230 }
231 
232 // The following function reports error is reported when the HMAC has been
233 // incorrectly configured by software. This could include an invalid digest size
234 // for SHA-2/HMAC modes or an invalid key length for HMAC mode
235 status_t run_test_invalidconfig_digest(
236  const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
237  const dif_hmac_digest_t *expected_digest) {
238  run_hmac_enable_interrupt();
239  // Set HMAC KeyLength to 256 bit and SHA2/HMAC Digest size to SHA2_None
240  uint32_t reg = 0;
241  reg = bitfield_field32_write(reg, HMAC_CFG_KEY_LENGTH_FIELD,
242  HMAC_CFG_KEY_LENGTH_VALUE_KEY_256);
243  reg = bitfield_field32_write(reg, HMAC_CFG_DIGEST_SIZE_FIELD,
244  HMAC_CFG_DIGEST_SIZE_VALUE_SHA2_NONE);
245  reg = bitfield_bit32_write(reg, HMAC_CFG_SHA_EN_BIT, true);
246  reg = bitfield_bit32_write(reg, HMAC_CFG_HMAC_EN_BIT, true);
247  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET, reg);
248  uint32_t hmac_cmd_reg =
249  mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
250  hmac_cmd_reg =
251  bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_START_BIT, true);
252  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET,
253  hmac_cmd_reg);
254  uint32_t hmacerr_reg =
255  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
256  TRY_CHECK(hmacerr_reg == kErrorSwInvalidConfig,
257  "Error code doesn't match expected code");
258  CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
259  CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
260  run_hmac(hmac);
261  hmac_cmd_reg = mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
262  hmac_cmd_reg =
263  bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_STOP_BIT, true);
264  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET,
265  hmac_cmd_reg);
266  // Write default cfg reg values to clear the error
267  uint32_t cfg_reg_default = HMAC_CFG_REG_RESVAL;
268  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET,
269  cfg_reg_default);
270  run_hmac_clear_interrupt();
271  return OK_STATUS();
272 }
273 
274 // The following function reports error is reported when the HMAC has been
275 // incorrectly configured by software. This could include an invalid digest size
276 // for SHA-2/HMAC modes or an invalid key length for HMAC mode
277 status_t run_test_updatekey(const dif_hmac_t *hmac, const char *data,
278  size_t len, const uint8_t *key,
279  const dif_hmac_digest_t *expected_digest) {
280  run_hmac_enable_interrupt();
281  test_start(hmac, key);
282  CHECK_STATUS_OK(hmac_testutils_push_message(hmac, data, len));
283  CHECK_STATUS_OK(hmac_testutils_fifo_empty_polled(hmac));
284  // Updating the config with swap key - while hmac engine is in process state
285  CHECK_DIF_OK(dif_hmac_mode_hmac_start(hmac, key, kHmacTransactionConfig));
286  uint32_t hmacerr_reg =
287  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
288  TRY_CHECK(hmacerr_reg == kErrorSwUpdateSecretKeyInProcess,
289  "Error code doesn't match expected code");
290  run_hmac(hmac);
291  run_hmac_clear_interrupt();
292  return OK_STATUS();
293 }
294 
295 // Reported when CMD.start is received when SHA is disabled
296 status_t run_test_hashstartwhendisabled(
297  const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
298  const dif_hmac_digest_t *expected_digest) {
299  run_hmac_enable_interrupt();
300  uint32_t cfg_reg =
301  abs_mmio_read32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET);
302  // Disable SHA_EN
303  cfg_reg = bitfield_bit32_write(cfg_reg, HMAC_CFG_SHA_EN_BIT, false);
304  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET, cfg_reg);
305  // Write HASH_START_BIT
306  uint32_t hmac_cmd_reg =
307  mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
308  hmac_cmd_reg =
309  bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_START_BIT, true);
310  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET,
311  hmac_cmd_reg);
312  uint32_t hmacerr_reg =
313  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
314  TRY_CHECK(hmacerr_reg == kErrorSwHashStartWhenShaDisabled,
315  "Error code doesn't match expected code");
316  run_hmac_clear_interrupt();
317  return OK_STATUS();
318 }
319 
320 // Reported when CMD.start is received while the HMAC is running
321 status_t run_test_hashstartwhenactive(
322  const dif_hmac_t *hmac, const char *data, size_t len, const uint8_t *key,
323  const dif_hmac_digest_t *expected_digest) {
324  run_hmac_enable_interrupt();
325  test_start(hmac, key);
326  uint32_t hmac_cmd_reg =
327  mmio_region_read32(hmac->base_addr, HMAC_CMD_REG_OFFSET);
328  hmac_cmd_reg =
329  bitfield_bit32_write(hmac_cmd_reg, HMAC_CMD_HASH_START_BIT, true);
330  abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET,
331  hmac_cmd_reg);
332  uint32_t hmac_err_reg =
333  mmio_region_read32(hmac->base_addr, HMAC_ERR_CODE_REG_OFFSET);
334  TRY_CHECK(hmac_err_reg == kErrorSwHashStartWhenActive,
335  "Error code doesn't match expected code");
336  run_hmac(hmac);
337  run_hmac_clear_interrupt();
338  return OK_STATUS();
339 }
340 
341 bool test_main(void) {
342  LOG_INFO("Running HMAC Error Condition test...");
343 
344  dif_hmac_t hmac;
346  LOG_INFO("Running test push message when sha disabled...");
347  run_test_pushmsg_when_shadisabled(&hmac, kData, sizeof(kData), NULL,
348  &kExpectedHmacDigest);
349 
350  LOG_INFO("Running Hash start test when sha is disabled...");
351  run_test_hashstartwhendisabled(&hmac, kData, sizeof(kData), NULL,
352  &kExpectedShaDigest);
353 
354  LOG_INFO("Running test with key when disallowed..,");
355  run_test_updatekey(&hmac, kData, sizeof(kData), (uint8_t *)(&kHmacKey[0]),
356  &kExpectedHmacDigest);
357 
358  LOG_INFO("Running test HMAC hash start when active...");
359  run_test_hashstartwhenactive(&hmac, kData, sizeof(kData),
360  (uint8_t *)(&kHmacKey[0]), &kExpectedHmacDigest);
361 
362  LOG_INFO("Running test push message when disallowed...");
363  run_test_pushmsg_when_disallowed(&hmac, kData, sizeof(kData),
364  (uint8_t *)(&kHmacKey[0]),
365  &kExpectedHmacDigest);
366 
367  LOG_INFO("Running test HMAC invalid config keylength...");
368  run_test_invalidconfig_keylength(&hmac, kData, sizeof(kData),
369  (uint8_t *)(&kHmacKey[0]),
370  &kExpectedHmacDigest);
371 
372  LOG_INFO("Running test HMAC hash start when active...");
373  run_test_hashstartwhenactive(&hmac, kData, sizeof(kData),
374  (uint8_t *)(&kHmacKey[0]), &kExpectedHmacDigest);
375 
376  LOG_INFO("Running test HMAC invalid config digest size...");
377  run_test_invalidconfig_digest(&hmac, kData, sizeof(kData),
378  (uint8_t *)(&kHmacKey[0]),
379  &kExpectedHmacDigest);
380 
381  return true;
382 }