Software APIs
csrng_testutils.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
5#include "sw/device/lib/testing/csrng_testutils.h"
6
10#include "sw/device/lib/testing/rand_testutils.h"
11#include "sw/device/lib/testing/test_framework/check.h"
12
13#include "hw/top/csrng_regs.h" // Generated
14
15#define MODULE_ID MAKE_MODULE_ID('r', 'n', 't')
16
17enum {
18 kNumOutputWordsMax = 16,
19};
20
21/**
22 * Generates randomized seed material.
23 */
24status_t csrng_testutils_seed_material_build(
25 bool disable_rand, dif_csrng_seed_material_t *seed_material) {
26 if (seed_material == NULL) {
27 return INVALID_ARGUMENT();
28 }
29 seed_material->seed_material_len =
30 disable_rand
31 ? 0
32 : rand_testutils_gen32_range(0, kDifCsrngSeedMaterialMaxWordLen);
33 for (size_t i = 0; i < seed_material->seed_material_len; ++i) {
34 seed_material->seed_material[i] = rand_testutils_gen32();
35 }
36 return OK_STATUS();
37}
38
39/**
40 * Returns a randomized CSRNG application command.
41 */
42csrng_app_cmd_t csrng_testutils_app_cmd_build(
43 bool disable_rand, csrng_app_cmd_id_t id,
44 dif_csrng_entropy_src_toggle_t entropy_src_en, unsigned int glen_val,
45 dif_csrng_seed_material_t *seed_material) {
46 CHECK_STATUS_OK(
47 csrng_testutils_seed_material_build(disable_rand, seed_material));
48
49 // If disable_rand is true, we set flag0 to the provided value.
50 // If disable_rand is false, we pick a value at random.
51 dif_csrng_entropy_src_toggle_t entropy_src_enable =
52 disable_rand ? entropy_src_en
53 : rand_testutils_gen32_range(0, 1) ? kDifCsrngEntropySrcToggleEnable
55
56 // If glen_val > 0, the generate length is set to glen_val.
57 // If disable_rand is false we pick a random value between 1 and 10 with a
58 // bias towards 1. Otherwise, if glen would be too high, we would not see
59 // any reseeds because we do not consume enough entropy.
60 unsigned int glen = glen_val ? glen_val
61 : (disable_rand || rand_testutils_gen32_range(0, 1))
62 ? 1
63 : rand_testutils_gen32_range(2, 10);
64
65 return (csrng_app_cmd_t){
66 .id = id,
67 .entropy_src_enable = entropy_src_enable,
68 .seed_material = seed_material,
69 .generate_len = glen,
70 };
71}
72
73status_t csrng_testutils_cmd_ready_wait(const dif_csrng_t *csrng) {
74 dif_csrng_cmd_status_t cmd_status;
75 do {
76 TRY(dif_csrng_get_cmd_interface_status(csrng, &cmd_status));
77 TRY_CHECK(cmd_status.kind != kDifCsrngCmdStatusError);
78 } while (cmd_status.kind != kDifCsrngCmdStatusReady);
79 return OK_STATUS();
80}
81
82status_t csrng_testutils_cmd_generate_run(
83 const dif_csrng_t *csrng, const dif_csrng_seed_material_t *additional_data,
84 uint32_t *output, size_t output_len) {
85 TRY(csrng_testutils_cmd_ready_wait(csrng));
86 TRY(dif_csrng_generate_start(csrng, additional_data, output_len));
87
88 dif_csrng_output_status_t output_status;
89 do {
90 TRY(dif_csrng_get_output_status(csrng, &output_status));
91 } while (!output_status.valid_data);
92
93 TRY(dif_csrng_generate_read(csrng, output, output_len));
94 return OK_STATUS();
95}
96
97status_t csrng_testutils_check_internal_state(
98 const dif_csrng_t *csrng, const dif_csrng_internal_state_t *expected) {
99 TRY(csrng_testutils_cmd_ready_wait(csrng));
101 TRY(dif_csrng_get_internal_state(csrng, kCsrngInternalStateIdSw, &got));
102 uint32_t reseed_counter;
103 TRY(dif_csrng_get_reseed_counter(csrng, kCsrngInternalStateIdSw,
104 &reseed_counter));
105
106 TRY_CHECK(got.instantiated == expected->instantiated);
107 TRY_CHECK(got.reseed_counter == expected->reseed_counter);
108 TRY_CHECK(reseed_counter == expected->reseed_counter);
109 TRY_CHECK(got.fips_compliance == expected->fips_compliance);
110
111 TRY_CHECK(memcmp(got.v, expected->v, sizeof(expected->v)) == 0);
112
113 TRY_CHECK(memcmp(got.key, expected->key, sizeof(expected->key)) == 0);
114 return OK_STATUS();
115}
116
117status_t csrng_testutils_kat_instantiate(
118 const dif_csrng_t *csrng, bool fail_expected,
119 const dif_csrng_seed_material_t *seed_material,
120 const dif_csrng_internal_state_t *expected_state) {
121 LOG_INFO("CSRNG KAT instantiate");
122 TRY(csrng_testutils_cmd_ready_wait(csrng));
123 TRY(dif_csrng_uninstantiate(csrng));
124
125 // Instantiate CSRNG - use the provided seed material only.
126 TRY(csrng_testutils_cmd_ready_wait(csrng));
127 TRY(dif_csrng_instantiate(csrng, kDifCsrngEntropySrcToggleDisable,
128 seed_material));
129
130 // Check the internal state of created CSRNG instance.
132 memset(&zero_state, 0, sizeof(zero_state));
133 return csrng_testutils_check_internal_state(
134 csrng, fail_expected ? &zero_state : expected_state);
135}
136
137status_t csrng_testutils_kat_generate(
138 const dif_csrng_t *csrng, size_t num_generates, size_t output_len,
139 const dif_csrng_seed_material_t *additional_data,
140 const uint32_t *expected_output,
141 const dif_csrng_internal_state_t *expected_state) {
142 LOG_INFO("CSRNG KAT generate");
143
144 // Run the generate and check the output.
145 uint32_t got[kNumOutputWordsMax];
146 for (int i = 0; i < num_generates; ++i) {
147 TRY(csrng_testutils_cmd_generate_run(csrng, additional_data, got,
148 output_len));
149 }
150
151 if (expected_output != NULL) {
152 TRY_CHECK(memcmp(got, expected_output, output_len) == 0);
153 }
154
155 // Check the internal state.
156 return csrng_testutils_check_internal_state(csrng, expected_state);
157}
158
159status_t csrng_testutils_kat_reseed(
160 const dif_csrng_t *csrng, const dif_csrng_seed_material_t *seed_material,
161 const dif_csrng_internal_state_t *expected_state) {
162 LOG_INFO("CSRNG KAT reseed");
163
164 // Reseed CSRNG - use the provided seed material only.
165 TRY(csrng_testutils_cmd_ready_wait(csrng));
166 TRY(csrng_send_app_cmd(
169 .id = kCsrngAppCmdReseed,
170 .entropy_src_enable = kDifCsrngEntropySrcToggleDisable,
171 .seed_material = seed_material,
172 }));
173
174 // Check the internal state.
175 return csrng_testutils_check_internal_state(csrng, expected_state);
176}
177
178status_t csrng_testutils_fips_instantiate_kat(const dif_csrng_t *csrng,
179 bool fail_expected) {
180 // CTR_DRBG Known-Answer-Tests (KATs).
181 //
182 // Test vector sourced from NIST's CAVP website:
183 // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/random-number-generators
184 //
185 // The number format in this docstring follows the CAVP format to simplify
186 // auditing of this test case.
187 //
188 // Test vector: CTR_DRBG AES-256 no DF from
189 // drbgvectors_no_reseed.zip/CTR_DRBG.txt with parameters
190 // - PredictionResistance = False
191 // - EntropyInputLen = 384
192 // - NonceLen = 0
193 // - PersonalizationStringLen = 0
194 // - AdditionalInputLen = 0
195 // - ReturnedBitsLen = 512
196 // - COUNT = 0
197 //
198 // - EntropyInput =
199 // df5d73faa468649edda33b5cca79b0b05600419ccb7a879ddfec9db32ee494e5531b51de16a30f769262474c73bec010
200 // - Nonce = EMPTY
201 // - PersonalizationString = EMPTY
202 //
203 // Command: Instantiate
204 // - Key = 8c52f901632d522774c08fad0eb2c33b98a701a1861aecf3d8a25860941709fd
205 // - V = 217b52142105250243c0b2c206b8f59e
206 //
207 // Command: Generate (first call):
208 // - Key = 72f4af5c93258eb3eeec8c0cacea6c1d1978a4fad44312725f1ac43b167f2d52
209 // - V = e86f6d07dfb551cebad80e6bf6830ac4
210 //
211 // Command: Generate (second call):
212 // - Key = 1a1c6e5f1cccc6974436e5fd3f015bc8e9dc0f90053b73e3c19d4dfd66d1b85a
213 // - V = 53c78ac61a0bac9d7d2e92b1e73e3392
214 // - ReturnedBits =
215 // d1c07cd95af8a7f11012c84ce48bb8cb87189e99d40fccb1771c619bdf82ab2280b1dc2f2581f39164f7ac0c510494b3a43c41b7db17514c87b107ae793e01c5
216
217 const dif_csrng_seed_material_t kEntropyInput = {
218 .seed_material = {0x73bec010, 0x9262474c, 0x16a30f76, 0x531b51de,
219 0x2ee494e5, 0xdfec9db3, 0xcb7a879d, 0x5600419c,
220 0xca79b0b0, 0xdda33b5c, 0xa468649e, 0xdf5d73fa},
221 .seed_material_len = 12,
222 };
223 const dif_csrng_internal_state_t kExpectedState = {
224 .reseed_counter = 0,
225 .v = {0x06b8f59e, 0x43c0b2c2, 0x21052502, 0x217b5214},
226 .key = {0x941709fd, 0xd8a25860, 0x861aecf3, 0x98a701a1, 0x0eb2c33b,
227 0x74c08fad, 0x632d5227, 0x8c52f901},
228 .instantiated = true,
229 .fips_compliance = false,
230 };
231 return csrng_testutils_kat_instantiate(csrng, fail_expected, &kEntropyInput,
232 &kExpectedState);
233}
234
235status_t csrng_testutils_fips_generate_kat(const dif_csrng_t *csrng) {
236 enum {
237 kExpectedOutputLen = 16,
238 };
239 // TODO(#13342): csrng does not provide a linear output order. For example,
240 // note the test vector output word order: 12,13,14,15 8,9,10,11 4,5,6,7
241 // 0,1,2,3.
242 const uint32_t kExpectedOutput[kExpectedOutputLen] = {
243 0xe48bb8cb, 0x1012c84c, 0x5af8a7f1, 0xd1c07cd9, 0xdf82ab22, 0x771c619b,
244 0xd40fccb1, 0x87189e99, 0x510494b3, 0x64f7ac0c, 0x2581f391, 0x80b1dc2f,
245 0x793e01c5, 0x87b107ae, 0xdb17514c, 0xa43c41b7,
246 };
247 const dif_csrng_internal_state_t kExpectedState = {
248 .reseed_counter = 2,
249 .v = {0xe73e3392, 0x7d2e92b1, 0x1a0bac9d, 0x53c78ac6},
250 .key = {0x66d1b85a, 0xc19d4dfd, 0x053b73e3, 0xe9dc0f90, 0x3f015bc8,
251 0x4436e5fd, 0x1cccc697, 0x1a1c6e5f},
252 .instantiated = true,
253 .fips_compliance = false,
254 };
255 return csrng_testutils_kat_generate(csrng, 2, kExpectedOutputLen, NULL,
256 kExpectedOutput, &kExpectedState);
257}
258
259status_t csrng_testutils_fips_instantiate_kat_adata(const dif_csrng_t *csrng,
260 bool fail_expected) {
261 // CTR_DRBG Known-Answer-Tests (KATs).
262 //
263 // Test vector sourced from NIST's CAVP website:
264 // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/random-number-generators
265 //
266 // The number format in this docstring follows the CAVP format to simplify
267 // auditing of this test case.
268 //
269 // Test vector: CTR_DRBG AES-256 no DF from
270 // drbgvectors_no_reseed.zip/CTR_DRBG.txt with parameters
271 // - PredictionResistance = False
272 // - EntropyInputLen = 384
273 // - NonceLen = 0
274 // - PersonalizationStringLen = 0
275 // - AdditionalInputLen = 384
276 // - ReturnedBitsLen = 512
277 // - COUNT = 0
278 //
279 // - EntropyInput =
280 // f45e9d040c1456f1c7f26e7f146469fbe3973007fe037239ad57623046e7ec52221b22eec208b22ac4cf4ca8d6253874
281 // - Nonce = EMPTY
282 // - PersonalizationString = EMPTY
283 //
284 // Command: Instantiate
285 // - Key = a75117ffcb5160486e91da8ed0af1a702d30703ab3631957aa19a7e3fc14714a
286 // - V = 507b2124f5ae985e156db926a3230dfa
287 //
288 // - AdditionalInput =
289 // 28819bc79b92fc8790ebdc99812cdcea5c96e6feab32801ec1851b9f46e80eb6800028e61fbccb6ccbe42b06bf5a0864
290 // Command: Generate (first call):
291 // - Key = d75e41010982abd243b4d75642b86ce07e13b3652a3725aad011b1097c32957a
292 // - V = 939fbb584e0103982d2e73e05779849f
293 //
294 // - AdditionalInput =
295 // 418ca848027e1b3c84d66717e6f31bf89684d5db94cd2d579233f716ac70ab66cc7b01a6f9ab8c7665fcc37dba4af1ad
296 // Command: Generate (second call):
297 // - Key = b0f80df4b33e5d2e3d72c8667ba9da1aa64a3a4936a3fdabf2c980d3104dfa13
298 // - V = 433abd3907feddce66cbcb216d5d833e
299 // - ReturnedBits =
300 // 4f11406bd303c104243441a8f828bf0293cb20ac39392061429c3f56c1f426239f8f0c687b69897a2c7c8c2b4fb520b62741ffdd29f038b7c82a9d00a890a3ed
301
302 const dif_csrng_seed_material_t kEntropyInput = {
303 .seed_material = {0xd6253874, 0xc4cf4ca8, 0xc208b22a, 0x221b22ee,
304 0x46e7ec52, 0xad576230, 0xfe037239, 0xe3973007,
305 0x146469fb, 0xc7f26e7f, 0x0c1456f1, 0xf45e9d04},
306 .seed_material_len = 12,
307 };
308 const dif_csrng_internal_state_t kExpectedState = {
309 .reseed_counter = 0,
310 .v = {0xa3230dfa, 0x156db926, 0xf5ae985e, 0x507b2124},
311 .key = {0xfc14714a, 0xaa19a7e3, 0xb3631957, 0x2d30703a, 0xd0af1a70,
312 0x6e91da8e, 0xcb516048, 0xa75117ff},
313 .instantiated = true,
314 .fips_compliance = false,
315 };
316 return csrng_testutils_kat_instantiate(csrng, fail_expected, &kEntropyInput,
317 &kExpectedState);
318}
319
320status_t csrng_testutils_fips_generate_kat_adata1(const dif_csrng_t *csrng) {
321 enum {
322 kExpectedOutputLen = 16,
323 };
324 const dif_csrng_seed_material_t kAdditionalData = {
325 .seed_material = {0xbf5a0864, 0xcbe42b06, 0x1fbccb6c, 0x800028e6,
326 0x46e80eb6, 0xc1851b9f, 0xab32801e, 0x5c96e6fe,
327 0x812cdcea, 0x90ebdc99, 0x9b92fc87, 0x28819bc7},
328 .seed_material_len = 12,
329 };
330 const dif_csrng_internal_state_t kExpectedState = {
331 .reseed_counter = 1,
332 .v = {0x5779849f, 0x2d2e73e0, 0x4e010398, 0x939fbb58},
333 .key = {0x7c32957a, 0xd011b109, 0x2a3725aa, 0x7e13b365, 0x42b86ce0,
334 0x43b4d756, 0x0982abd2, 0xd75e4101},
335 .instantiated = true,
336 .fips_compliance = false,
337 };
338 return csrng_testutils_kat_generate(csrng, 1, kExpectedOutputLen,
339 &kAdditionalData, NULL, &kExpectedState);
340}
341
342status_t csrng_testutils_fips_generate_kat_adata2(const dif_csrng_t *csrng) {
343 enum {
344 kExpectedOutputLen = 16,
345 };
346 const dif_csrng_seed_material_t kAdditionalData = {
347 .seed_material = {0xba4af1ad, 0x65fcc37d, 0xf9ab8c76, 0xcc7b01a6,
348 0xac70ab66, 0x9233f716, 0x94cd2d57, 0x9684d5db,
349 0xe6f31bf8, 0x84d66717, 0x027e1b3c, 0x418ca848},
350 .seed_material_len = 12,
351 };
352 // TODO(#13342): csrng does not provide a linear output order. For example,
353 // note the test vector output word order: 12,13,14,15 8,9,10,11 4,5,6,7
354 // 0,1,2,3.
355 const uint32_t kExpectedOutput[kExpectedOutputLen] = {
356 0xf828bf02, 0x243441a8, 0xd303c104, 0x4f11406b, 0xc1f42623, 0x429c3f56,
357 0x39392061, 0x93cb20ac, 0x4fb520b6, 0x2c7c8c2b, 0x7b69897a, 0x9f8f0c68,
358 0xa890a3ed, 0xc82a9d00, 0x29f038b7, 0x2741ffdd};
359 const dif_csrng_internal_state_t kExpectedState = {
360 .reseed_counter = 2,
361 .v = {0x6d5d833e, 0x66cbcb21, 0x07feddce, 0x433abd39},
362 .key = {0x104dfa13, 0xf2c980d3, 0x36a3fdab, 0xa64a3a49, 0x7ba9da1a,
363 0x3d72c866, 0xb33e5d2e, 0xb0f80df4},
364 .instantiated = true,
365 .fips_compliance = false,
366 };
367 return csrng_testutils_kat_generate(csrng, 1, kExpectedOutputLen,
368 &kAdditionalData, kExpectedOutput,
369 &kExpectedState);
370}
371
372status_t csrng_testutils_cmd_status_check(const dif_csrng_t *csrng) {
374 TRY(dif_csrng_get_cmd_interface_status(csrng, &status));
375 TRY_CHECK(status.cmd_sts == kDifCsrngCmdStsSuccess);
376 return OK_STATUS();
377}
378
379status_t csrng_testutils_recoverable_alerts_check(const dif_csrng_t *csrng) {
380 uint32_t alerts = UINT32_MAX;
381 TRY(dif_csrng_get_recoverable_alerts(csrng, &alerts));
382 TRY_CHECK(alerts == 0);
383 return OK_STATUS();
384}