Software APIs
dif_csrng_unittest.cc
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 
6 
7 #include <array>
8 #include <vector>
9 
10 #include "gtest/gtest.h"
12 #include "sw/device/lib/base/mock_mmio.h"
14 
15 #include "csrng_regs.h" // Generated
16 
17 namespace dif_csrng_unittest {
18 namespace {
19 
20 using ::testing::ElementsAreArray;
21 
22 class DifCsrngTest : public testing::Test, public mock_mmio::MmioTest {
23  protected:
24  const dif_csrng_t csrng_ = {.base_addr = dev().region()};
25 };
26 
27 class ConfigTest : public DifCsrngTest {};
28 
29 TEST_F(ConfigTest, NullArgs) {
31 }
32 
33 TEST_F(ConfigTest, ConfigOk) {
34  constexpr uint32_t exp = kMultiBitBool4True | kMultiBitBool4True << 4 |
35  kMultiBitBool4True << 8 | kMultiBitBool4False << 12;
36  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 1);
37  EXPECT_WRITE32(CSRNG_CTRL_REG_OFFSET, exp);
39 }
40 
41 TEST_F(ConfigTest, Locked) {
42  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 0);
43  EXPECT_EQ(dif_csrng_configure(&csrng_), kDifLocked);
44 }
45 
47 
48 TEST_F(GetCmdInterfaceStatusTest, NullArgs) {
51 
53 }
54 
56  bool cmd_ready;
57  bool cmd_ack;
58  uint32_t cmd_status;
59  dif_csrng_cmd_status_t expected_status;
60 };
61 
64  public testing::WithParamInterface<StatusTestCase> {};
65 
66 TEST_P(GetCmdInterfaceStatusTestAllParams, ValidConfigurationMode) {
67  const auto &test_param = GetParam();
69  uint32_t ctrl_reg = 0;
70  ctrl_reg = bitfield_bit32_write(ctrl_reg, CSRNG_SW_CMD_STS_CMD_RDY_BIT,
71  test_param.cmd_ready);
72  ctrl_reg = bitfield_bit32_write(ctrl_reg, CSRNG_SW_CMD_STS_CMD_ACK_BIT,
73  test_param.cmd_ack);
74  ctrl_reg = bitfield_field32_write(ctrl_reg, CSRNG_SW_CMD_STS_CMD_STS_FIELD,
75  test_param.cmd_status);
76  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET, ctrl_reg);
78  EXPECT_EQ(status.kind, test_param.expected_status.kind);
79  EXPECT_EQ(status.cmd_sts, test_param.expected_status.cmd_sts);
80 }
81 
82 INSTANTIATE_TEST_SUITE_P(
83  GetCmdInterfaceStatusTestAllParams, GetCmdInterfaceStatusTestAllParams,
84  testing::Values(StatusTestCase{true, 0, 0x0, {kDifCsrngCmdStatusReady}},
85  StatusTestCase{false, 0, 0x0, {kDifCsrngCmdStatusBusy}},
86  StatusTestCase{true, 1, 0x0, {kDifCsrngCmdStatusReady}},
87  StatusTestCase{
88  false,
89  1,
91  {
93  .cmd_sts = kDifCsrngCmdStsInvalidAcmd,
94  },
95  }));
96 
97 class ForceErrorTest : public DifCsrngTest {};
98 
99 TEST_F(ForceErrorTest, BadArgs) {
101  &csrng_, static_cast<dif_csrng_fifo_t>(-1)));
103  dif_csrng_get_cmd_force_unhealthy_fifo(nullptr, kDifCsrngFifoGenBits));
105  &csrng_, static_cast<dif_csrng_error_t>(-1)));
108 }
109 
110 TEST_F(ForceErrorTest, ForceFifo) {
111  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 1);
112  EXPECT_WRITE32(CSRNG_ERR_CODE_TEST_REG_OFFSET,
113  CSRNG_ERR_CODE_SFIFO_GENBITS_ERR_BIT);
115  dif_csrng_get_cmd_force_unhealthy_fifo(&csrng_, kDifCsrngFifoGenBits));
116 }
117 
118 TEST_F(ForceErrorTest, ForceError) {
119  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 1);
120  EXPECT_WRITE32(CSRNG_ERR_CODE_TEST_REG_OFFSET,
121  CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT);
123 }
124 
125 TEST_F(ForceErrorTest, Locked) {
126  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 0);
127  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 0);
128  EXPECT_EQ(
129  dif_csrng_get_cmd_force_unhealthy_fifo(&csrng_, kDifCsrngFifoGenBits),
130  kDifLocked);
132  kDifLocked);
133 }
134 
135 class MiscStatusTest : public DifCsrngTest {};
136 
137 TEST_F(MiscStatusTest, BadArgs) {
138  uint32_t out;
144 }
145 
146 TEST_F(MiscStatusTest, GetMainSm) {
147  EXPECT_READ32(CSRNG_MAIN_SM_STATE_REG_OFFSET, 42);
148 
149  uint32_t out;
151  EXPECT_EQ(out, 42);
152 }
153 
154 TEST_F(MiscStatusTest, GetExceptions) {
155  EXPECT_READ32(CSRNG_HW_EXC_STS_REG_OFFSET, 42);
156 
157  uint32_t out;
159  EXPECT_EQ(out, 42);
160 }
161 
162 TEST_F(MiscStatusTest, ClearExceptions) {
163  EXPECT_WRITE32(CSRNG_HW_EXC_STS_REG_OFFSET, 0);
165 }
166 
168 
169 TEST_F(GetOutputStatusTest, NullArgs) {
172 
174 }
175 
176 TEST_F(GetOutputStatusTest, ValidStatus) {
177  // Each option is initialized to a boolean complement of the other so
178  // that we can test both fields toggling in one pass.
179  dif_csrng_output_status_t status = {.valid_data = false, .fips_mode = true};
180  EXPECT_READ32(CSRNG_GENBITS_VLD_REG_OFFSET,
181  {
182  {CSRNG_GENBITS_VLD_GENBITS_VLD_BIT, true},
183  {CSRNG_GENBITS_VLD_GENBITS_FIPS_BIT, false},
184  });
185 
187  EXPECT_EQ(status.valid_data, true);
188  EXPECT_EQ(status.fips_mode, false);
189 }
190 
191 /**
192  * DRBG commands are tested using this test group as the underlying
193  * command interface is shared across API functions.
194  */
195 class CommandTest : public DifCsrngTest {
196  protected:
197  dif_csrng_seed_material_t seed_material_ = {
198  .seed_material_len = 0,
199  .seed_material = {0},
200  };
201 };
202 
203 TEST_F(CommandTest, InstantiateOk) {
204  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
205  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
206  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
207  0x00000001 | kMultiBitBool4True << 8);
209  &seed_material_));
210 
211  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
212  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
213  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
214  0x00000001 | kMultiBitBool4False << 8);
216  &seed_material_));
217 
218  seed_material_.seed_material[0] = 0x5a5a5a5a;
219  seed_material_.seed_material_len = 1;
220  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
221  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
222  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
223  0x00000011 | kMultiBitBool4False << 8);
224  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
225  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
226  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET, 0x5a5a5a5a);
228  &seed_material_));
229 }
230 
231 TEST_F(CommandTest, InstantiateBadArgs) {
233  nullptr, kDifCsrngEntropySrcToggleDisable, &seed_material_));
234 
235  // Failed overflow check.
236  seed_material_.seed_material_len = 16;
238  &csrng_, kDifCsrngEntropySrcToggleDisable, &seed_material_));
239 }
240 
241 TEST_F(CommandTest, ReseedOk) {
242  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
243  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
244  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
245  0x00000002 | kMultiBitBool4False << 8);
246  EXPECT_DIF_OK(dif_csrng_reseed(&csrng_, &seed_material_));
247 
248  seed_material_.seed_material[0] = 0x5a5a5a5a;
249  seed_material_.seed_material_len = 1;
250  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
251  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
252  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
253  0x00000012 | kMultiBitBool4False << 8);
254  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
255  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
256  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET, 0x5a5a5a5a);
257  EXPECT_DIF_OK(dif_csrng_reseed(&csrng_, &seed_material_));
258 }
259 
260 TEST_F(CommandTest, ReseedBadArgs) {
261  EXPECT_DIF_BADARG(dif_csrng_reseed(nullptr, &seed_material_));
262 
263  // Failed overflow check.
264  seed_material_.seed_material_len = 16;
265  EXPECT_DIF_BADARG(dif_csrng_reseed(&csrng_, &seed_material_));
266 }
267 
268 TEST_F(CommandTest, UpdateOk) {
269  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
270  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
271  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
272  0x00000004 | kMultiBitBool4False << 8);
273  EXPECT_DIF_OK(dif_csrng_update(&csrng_, &seed_material_));
274 
275  seed_material_.seed_material[0] = 0x5a5a5a5a;
276  seed_material_.seed_material_len = 1;
277  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
278  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
279  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
280  0x00000014 | kMultiBitBool4False << 8);
281  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
282  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
283  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET, 0x5a5a5a5a);
284  EXPECT_DIF_OK(dif_csrng_update(&csrng_, &seed_material_));
285 }
286 
287 TEST_F(CommandTest, UpdateBadArgs) {
288  EXPECT_DIF_BADARG(dif_csrng_update(nullptr, &seed_material_));
289 }
290 
291 TEST_F(CommandTest, GenerateOk) {
292  // 512bits = 16 x 32bit = 4 x 128bit blocks
293  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
294  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
295  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
296  0x00004003 | kMultiBitBool4False << 8);
297  EXPECT_DIF_OK(dif_csrng_generate_start(&csrng_, /*len=*/16));
298 
299  // 576bits = 18 x 32bit = 5 x 128bit blocks (rounded up)
300  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
301  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
302  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
303  0x00005003 | kMultiBitBool4False << 8);
304  EXPECT_DIF_OK(dif_csrng_generate_start(&csrng_, /*len=*/18));
305 }
306 
307 TEST_F(CommandTest, GenerateBadArgs) {
308  EXPECT_DIF_BADARG(dif_csrng_generate_start(nullptr, /*len=*/1));
309  EXPECT_DIF_BADARG(dif_csrng_generate_start(&csrng_, /*len=*/0));
310 }
311 
312 TEST_F(CommandTest, GenerateOutOfRange) {
313  enum {
314  // The maximum allowed is 0x800 128-bit blocks. Multiply by 4 to get the
315  // number of uint32 words and add one to trigger the error.
316  kGenerateLenOutOfRange = 0x800 * 4 + 1,
317  };
319  dif_csrng_generate_start(&csrng_, kGenerateLenOutOfRange));
320 }
321 
322 TEST_F(CommandTest, UninstantiateOk) {
323  EXPECT_READ32(CSRNG_SW_CMD_STS_REG_OFFSET,
324  {{CSRNG_SW_CMD_STS_CMD_RDY_BIT, true}});
325  EXPECT_WRITE32(CSRNG_CMD_REQ_REG_OFFSET,
326  0x00000005 | kMultiBitBool4False << 8);
328 }
329 
330 class GenerateEndTest : public DifCsrngTest {};
331 
332 TEST_F(GenerateEndTest, ReadOk) {
333  constexpr std::array<uint32_t, 4> kExpected = {
334  0x00000000,
335  0x11111111,
336  0x22222222,
337  0x33333333,
338  };
339 
340  EXPECT_READ32(CSRNG_GENBITS_VLD_REG_OFFSET,
341  {
342  {CSRNG_GENBITS_VLD_GENBITS_VLD_BIT, true},
343  });
344  for (const uint32_t val : kExpected) {
345  EXPECT_READ32(CSRNG_GENBITS_REG_OFFSET, val);
346  }
347 
348  std::vector<uint32_t> got(kExpected.size());
349  EXPECT_DIF_OK(dif_csrng_generate_read(&csrng_, got.data(), got.size()));
350  EXPECT_THAT(got, testing::ElementsAreArray(kExpected));
351 }
352 
353 TEST_F(GenerateEndTest, ReadBadArgs) {
354  EXPECT_DIF_BADARG(dif_csrng_generate_read(&csrng_, nullptr, /*len=*/0));
355 
356  uint32_t data;
357  EXPECT_DIF_BADARG(dif_csrng_generate_read(nullptr, &data, /*len=*/1));
358 }
359 
361 
362 TEST_F(GetInternalStateTest, GetInternalStateOk) {
364 
365  EXPECT_WRITE32(CSRNG_INT_STATE_NUM_REG_OFFSET,
366  {
367  {CSRNG_INT_STATE_NUM_INT_STATE_NUM_OFFSET,
368  static_cast<uint32_t>(instance_id)},
369  });
370  EXPECT_READ32(CSRNG_INT_STATE_NUM_REG_OFFSET,
371  {
372  {CSRNG_INT_STATE_NUM_INT_STATE_NUM_OFFSET,
373  static_cast<uint32_t>(instance_id)},
374  });
375 
376  dif_csrng_internal_state_t expected = {
377  .reseed_counter = 0,
378  .v = {1, 2, 3, 4},
379  .key = {1, 2, 3, 4, 5, 6, 7, 8},
380  .instantiated = true,
381  .fips_compliance = true,
382  };
383  EXPECT_READ32(CSRNG_INT_STATE_VAL_REG_OFFSET, expected.reseed_counter);
384  for (size_t i = 0; i < 4; ++i) {
385  EXPECT_READ32(CSRNG_INT_STATE_VAL_REG_OFFSET, expected.v[i]);
386  }
387  for (size_t i = 0; i < 8; ++i) {
388  EXPECT_READ32(CSRNG_INT_STATE_VAL_REG_OFFSET, expected.key[i]);
389  }
390  EXPECT_READ32(CSRNG_INT_STATE_VAL_REG_OFFSET, 3);
391 
393  EXPECT_DIF_OK(dif_csrng_get_internal_state(&csrng_, instance_id, &got));
394 
395  EXPECT_EQ(got.reseed_counter, expected.reseed_counter);
396  EXPECT_THAT(got.key, ElementsAreArray(expected.key));
397  EXPECT_THAT(got.v, ElementsAreArray(expected.v));
398  EXPECT_EQ(got.instantiated, expected.instantiated);
399  EXPECT_EQ(got.fips_compliance, expected.fips_compliance);
400 }
401 
402 TEST_F(GetInternalStateTest, BadIntStateNumWrite) {
403  EXPECT_WRITE32(CSRNG_INT_STATE_NUM_REG_OFFSET,
404  {
405  {CSRNG_INT_STATE_NUM_INT_STATE_NUM_OFFSET,
406  static_cast<uint32_t>(kCsrngInternalStateIdSw)},
407  });
408  EXPECT_READ32(CSRNG_INT_STATE_NUM_REG_OFFSET,
409  {
410  {CSRNG_INT_STATE_NUM_INT_STATE_NUM_OFFSET, 0},
411  });
412 
414  EXPECT_EQ(
416  kDifError);
417 }
418 
419 TEST_F(GetInternalStateTest, GetInternalStateBadArgs) {
422 
426 }
427 
429 
430 TEST_F(GetReseedCounterTest, GetReseedCounterOk) {
432  uint32_t reseed_counter;
433 
434  EXPECT_READ32(
435  (CSRNG_RESEED_COUNTER_0_REG_OFFSET + ((uint32_t)(instance_id) << 2)), 0);
437  dif_csrng_get_reseed_counter(&csrng_, instance_id, &reseed_counter));
438 }
439 
440 TEST_F(GetReseedCounterTest, GetReseedCounterBadArgs) {
443 
444  uint32_t unused;
447 
449  &csrng_, static_cast<dif_csrng_internal_state_id_t>(-1), &unused));
450 }
451 
452 class LockTest : public DifCsrngTest {};
453 
454 TEST_F(LockTest, BadArgs) {
455  bool flag;
457  EXPECT_DIF_BADARG(dif_csrng_is_locked(nullptr, &flag));
458  EXPECT_DIF_BADARG(dif_csrng_is_locked(&csrng_, nullptr));
459 }
460 
461 TEST_F(LockTest, Lock) {
462  EXPECT_WRITE32(CSRNG_REGWEN_REG_OFFSET, 0);
463  EXPECT_DIF_OK(dif_csrng_lock(&csrng_));
464 }
465 
466 TEST_F(LockTest, IsLocked) {
467  bool flag;
468 
469  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 1);
470  EXPECT_DIF_OK(dif_csrng_is_locked(&csrng_, &flag));
471  EXPECT_FALSE(flag);
472 
473  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 0);
474  EXPECT_DIF_OK(dif_csrng_is_locked(&csrng_, &flag));
475  EXPECT_TRUE(flag);
476 }
477 
478 class StopTest : public DifCsrngTest {};
479 
480 TEST_F(StopTest, BadArgs) { EXPECT_DIF_BADARG(dif_csrng_stop(nullptr)); }
481 
482 TEST_F(StopTest, Stop) {
483  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 1);
484  EXPECT_WRITE32(CSRNG_CTRL_REG_OFFSET, CSRNG_CTRL_REG_RESVAL);
485  EXPECT_DIF_OK(dif_csrng_stop(&csrng_));
486 }
487 
488 TEST_F(StopTest, Locked) {
489  EXPECT_READ32(CSRNG_REGWEN_REG_OFFSET, 0);
490  EXPECT_EQ(dif_csrng_stop(&csrng_), kDifLocked);
491 }
492 
493 class AlertTest : public DifCsrngTest {};
494 
495 TEST_F(AlertTest, BadArgs) {
496  uint32_t out;
500 }
501 
502 TEST_F(AlertTest, Get) {
503  uint32_t out;
504  EXPECT_READ32(CSRNG_RECOV_ALERT_STS_REG_OFFSET,
505  {
506  {CSRNG_RECOV_ALERT_STS_ENABLE_FIELD_ALERT_BIT, true},
507  {CSRNG_RECOV_ALERT_STS_CS_BUS_CMP_ALERT_BIT, true},
508  });
510  EXPECT_EQ(out, kDifCsrngRecoverableAlertBadEnable |
512 }
513 
514 TEST_F(AlertTest, Clear) {
515  EXPECT_WRITE32(CSRNG_RECOV_ALERT_STS_REG_OFFSET, 0);
517 }
518 
519 } // namespace
520 } // namespace dif_csrng_unittest