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

Make PRNG model slightly more readable #1079

Merged
merged 3 commits into from
Jul 5, 2023
Merged
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
85 changes: 55 additions & 30 deletions crypto/fipsmodule/rand/urandom_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
#define PTRACE_O_TRACESYSGOOD (1)
#endif

#if defined(AWSLC_FIPS)
torben-hansen marked this conversation as resolved.
Show resolved Hide resolved
static const bool kIsFIPS = true;
#else
static const bool kIsFIPS = false;
#endif


// This test can be run with $OPENSSL_ia32cap=~0x4000000000000000 in order to
// simulate the absence of RDRAND of machines that have it.

Expand Down Expand Up @@ -390,11 +397,6 @@ static bool have_fork_detection() {
// |TestFunction| is run. It should return the same trace of events that
// |GetTrace| will observe the real code making.
static std::vector<Event> TestFunctionPRNGModel(unsigned flags) {
#if defined(BORINGSSL_FIPS)
static const bool is_fips = true;
#else
static const bool is_fips = false;
#endif

std::vector<Event> ret;
bool urandom_probed = false;
Expand All @@ -413,7 +415,7 @@ static std::vector<Event> TestFunctionPRNGModel(unsigned flags) {
}

wait_for_entropy = [&ret, &urandom_probed, flags] {
if (!is_fips || urandom_probed) {
if (!kIsFIPS || urandom_probed) {
return;
}

Expand Down Expand Up @@ -471,39 +473,62 @@ static std::vector<Event> TestFunctionPRNGModel(unsigned flags) {

const size_t kSeedLength = CTR_DRBG_ENTROPY_LEN;
const size_t kAdditionalDataLength = 32;

if (!have_rdrand()) {
if ((!have_fork_detection() && !sysrand(true, kAdditionalDataLength)) ||
// Initialise CRNGT. In FIPS mode we use a blocking sysrand call for
// a personalization string, while in non-FIPS mode the same call is
// used for generating entropy for a seed. Note that the length
// of the personalization string is the same as that of the seed.
!sysrand(true, kSeedLength) ||
// Second entropy draw.
(!have_fork_detection() && !sysrand(true, kAdditionalDataLength))) {
const size_t kPersonalizationStringLength = CTR_DRBG_ENTROPY_LEN;
torben-hansen marked this conversation as resolved.
Show resolved Hide resolved
const bool kHaveRdrand = have_rdrand();
const bool kHaveFastRdrand = have_fast_rdrand();
const bool kHaveForkDetection = have_fork_detection();

// Additional data might be drawn on each invocation of RAND_bytes(). In case
// it is and there is no rdrand at all, the call is blocking. In the case
// where there is at least a "slow" rdrand, first a non-blocking call to
// system random is performed followed by an rdrand call.

// First call to RAND_bytes() will do two things:
// * maybe draw for additional data
// * seed the CTR-DRBG
// First is deciding on additional data.
if (!kHaveRdrand || !kHaveFastRdrand) {
if (!kHaveForkDetection) {
// If no rdrand, we use additional data if fork detection is not enabled.
if (!sysrand(!kHaveRdrand, kAdditionalDataLength)) {
return ret;
}
}
}
// Now the entropy for seeding.
if (kIsFIPS) {
// In FIPS mode we use Jitter Entropy for the seed but Jitter is not modeled
torben-hansen marked this conversation as resolved.
Show resolved Hide resolved
// A blocking system random call for a personalization string always follows.
if (!sysrand(true, kPersonalizationStringLength)) {
return ret;
}
} else {
// In non-FIPS mode entropy for the seed is drawn from system random.
if (!sysrand(true, kSeedLength)) {
return ret;
}
} else if (
// First additional data. If fast RDRAND isn't available then a
// non-blocking OS entropy draw will be tried.
(!have_fast_rdrand() && !have_fork_detection() &&
!sysrand(false, kAdditionalDataLength)) ||
// Initialise CRNGT. In FIPS mode we use a blocking sysrand call for
// a personalization string, while in non-FIPS mode the same call is
// used for generating entropy for a seed. Note that the length
// of the personalization string is the same as that of the seed.
!sysrand(true, kSeedLength) ||
// Second entropy draw's additional data.
(!have_fast_rdrand() && !have_fork_detection() &&
!sysrand(false, kAdditionalDataLength))) {
return ret;
}

// Second RAND_bytes() call. No seeding or re-seeding, but in some cases
// entropy is drawn for additional data as in the first call to RAND_bytes().
if (!kHaveRdrand || !kHaveFastRdrand) {
if (!kHaveForkDetection) {
if (!sysrand(!kHaveRdrand, kAdditionalDataLength)) {
return ret;
}
}
}

return ret;
}

// Tests that |TestFunctionPRNGModel| is a correct model for the code in
// urandom.c, at least to the limits of the the |Event| type.
//
// |TestFunctionPRNGModel| creates the entropy function call model, for
// various configs. |GetTrace| records the actual entropy function calls for
// each config and compares it against the model.
// Only system entropy function calls are modeled e.g. /dev/random and getrandom.
TEST(URandomTest, Test) {
char buf[256];

Expand Down