blob: a9c9d5cca1dac28754e1b1b61bbf711e91c251c5 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/crypto/drivers/entropy_kat.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/crypto/drivers/entropy.h"
#include "sw/device/lib/runtime/log.h"
#include "csrng_regs.h" // Generated
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
enum {
kBaseCsrng = TOP_EARLGREY_CSRNG_BASE_ADDR,
};
/**
* CSRNG internal state selector ID.
*/
typedef enum entropy_csrng_internal_state_id {
/**
* CSRNG instance assigned to Entropy Distribution Network (EDN) 0.
*/
kCsrngInternalStateIdEdn0 = 0,
/**
* CSRNG instance assigned to Entropy Distribution Network (EDN) 1.
*/
kCsrngInternalStateIdEdn1 = 1,
/**
* CSRNG instance assigned to software interface.
*/
kCsrngInternalStateIdSw = 2,
} entropy_csrng_internal_state_id_t;
/**
* CSRNG internal state.
*/
typedef struct entropy_csrng_internal_state {
/**
* Indicates the number of requests for pseudorandom bits since instantiation
* or reseeding.
*/
uint32_t reseed_counter;
/**
* Internal V working state with a 128bit block size.
*/
uint32_t v[4];
/**
* Internal key used to configure the internal CSRNG cipher.
*/
uint32_t key[8];
/**
* Set to true when the CSRNG instance has been instantiated.
*/
bool instantiated;
/**
* Set to true when FIPS compliant entropy was provided directly by the
* entropy source to instantiate or reseed the CSRNG instance.
*/
bool fips_compliance;
} entropy_csrng_internal_state_t;
static void entropy_csrng_internal_state_get(
entropy_csrng_internal_state_id_t instance_id,
entropy_csrng_internal_state_t *state) {
// Select the instance id to read the internal state from, request a state
// machine halt, and wait for the internal registers to be ready to be read.
uint32_t reg = bitfield_field32_write(
0, CSRNG_INT_STATE_NUM_INT_STATE_NUM_FIELD, instance_id);
abs_mmio_write32(kBaseCsrng + CSRNG_INT_STATE_NUM_REG_OFFSET, reg);
// Read the internal state.
state->reseed_counter =
abs_mmio_read32(kBaseCsrng + CSRNG_INT_STATE_VAL_REG_OFFSET);
for (size_t i = 0; i < ARRAYSIZE(state->v); ++i) {
state->v[i] = abs_mmio_read32(kBaseCsrng + CSRNG_INT_STATE_VAL_REG_OFFSET);
}
for (size_t i = 0; i < ARRAYSIZE(state->key); ++i) {
state->key[i] =
abs_mmio_read32(kBaseCsrng + CSRNG_INT_STATE_VAL_REG_OFFSET);
}
uint32_t flags = abs_mmio_read32(kBaseCsrng + CSRNG_INT_STATE_VAL_REG_OFFSET);
// The following bit indexes are defined in
// https://docs.opentitan.org/hw/ip/csrng/doc/#working-state-values
state->instantiated = bitfield_bit32_read(flags, /*bit_index=*/0u);
state->fips_compliance = bitfield_bit32_read(flags, /*bit_index=*/1u);
}
/**
* Checks the CSRNG internal state against `expected` values.
*
* @param csrng A CSRNG handle.
* @param expected Expected CSRNG internal state.
*/
static status_t check_internal_state(
const entropy_csrng_internal_state_t *expected) {
entropy_csrng_internal_state_t got = {0};
entropy_csrng_internal_state_get(kCsrngInternalStateIdSw, &got);
if (memcmp(&got, expected, sizeof(entropy_csrng_internal_state_t)) == 0) {
return OK_STATUS();
}
return INTERNAL();
}
status_t entropy_csrng_kat(void) {
TRY(entropy_csrng_uninstantiate());
const entropy_seed_material_t kEntropyInput = {
.data = {0x73bec010, 0x9262474c, 0x16a30f76, 0x531b51de, 0x2ee494e5,
0xdfec9db3, 0xcb7a879d, 0x5600419c, 0xca79b0b0, 0xdda33b5c,
0xa468649e, 0xdf5d73fa},
.len = 12,
};
TRY(entropy_csrng_instantiate(
/*disable_trng_input=*/kHardenedBoolTrue, &kEntropyInput));
const entropy_csrng_internal_state_t kExpectedStateInstantiate = {
.reseed_counter = 1,
.v = {0x06b8f59e, 0x43c0b2c2, 0x21052502, 0x217b5214},
.key = {0x941709fd, 0xd8a25860, 0x861aecf3, 0x98a701a1, 0x0eb2c33b,
0x74c08fad, 0x632d5227, 0x8c52f901},
.instantiated = true,
.fips_compliance = false,
};
TRY(check_internal_state(&kExpectedStateInstantiate));
enum {
kExpectedOutputLen = 16,
};
uint32_t got[kExpectedOutputLen];
TRY(entropy_csrng_generate(/*seed_material=*/NULL, got, kExpectedOutputLen));
TRY(entropy_csrng_generate(/*seed_material=*/NULL, got, kExpectedOutputLen));
const entropy_csrng_internal_state_t kExpectedStateGenerate = {
.reseed_counter = 3,
.v = {0xe73e3392, 0x7d2e92b1, 0x1a0bac9d, 0x53c78ac6},
.key = {0x66d1b85a, 0xc19d4dfd, 0x053b73e3, 0xe9dc0f90, 0x3f015bc8,
0x4436e5fd, 0x1cccc697, 0x1a1c6e5f},
.instantiated = true,
.fips_compliance = false,
};
TRY(check_internal_state(&kExpectedStateGenerate));
// TODO(#13342): csrng does not provide a linear output order. For example,
// note the test vector output word order: 12,13,14,15 8,9,10,11 4,5,6,7
// 0,1,2,3.
const uint32_t kExpectedOutput[kExpectedOutputLen] = {
0xe48bb8cb, 0x1012c84c, 0x5af8a7f1, 0xd1c07cd9, 0xdf82ab22, 0x771c619b,
0xd40fccb1, 0x87189e99, 0x510494b3, 0x64f7ac0c, 0x2581f391, 0x80b1dc2f,
0x793e01c5, 0x87b107ae, 0xdb17514c, 0xa43c41b7,
};
if (!memcmp(got, kExpectedOutput, sizeof(kExpectedOutput))) {
return OK_STATUS();
}
return INTERNAL();
}