Skip to content

Commit

Permalink
Tree DRBG with Jitter Entropy root (#1958)
Browse files Browse the repository at this point in the history
Implements a tree-DRBG using CPU Jitter as root. I had to implement some implementation-defined state, so switched from an immutable entropy source object entropy_source to a mutable one. Instead I factored out the vtable into a immutable object that defines the API to the entropy source.

The tree-DRBG is quite straightforward. The painful part is managing memory.

Steady-state is straightforward. No global locks, just thread-local ones except if one goes to the global DRBG.
In the graceful thread exit, the callback free_thread will manage thread-local memory.
When the process exists, we make sure to zeroize all thread-local data zeroize_thread in case they haven't been properly closed. A destructor in the tree-DRBG implementation will make sure to free the global DRBG + CPU Jitter object. This should also mean that we can safely unload DSO's.
Changes to CPU Jitter code entails:

__int64 is a language extension, old compilers aren't happy with that. Fix by replacing with portableint64_t

time is shadowing a global declaration from some imported header file. Fix by renaming parameters and local variables.

There are warnings, that turns into errors, originating from -Wconversion on the oldest GCC. These are false-positives because prior to GCC 4.3, -Wconversion didn't have anything to do with finding troublesome implicit conversions, it was an aid in converting from old C to modern C. Disable on those old compilers.

jitterentropy-base-windows.h distributes definitions of jent_get_nstime() throughout compilation units. However, many of these doesn't use the function causing unused function warnings for Windows clang builds. One could inline the function, but annotate as allowed unused instead to make it clear this is an AWS-LC local change.
  • Loading branch information
torben-hansen authored Nov 13, 2024
1 parent 3b6651c commit ddaf6d3
Show file tree
Hide file tree
Showing 13 changed files with 585 additions and 91 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ enable_language(C)
if(FIPS)
message(STATUS "FIPS build mode configured")

# Keep below to allow existing rand.c implementation and testing to function.
if(ENABLE_FIPS_ENTROPY_CPU_JITTER)
add_definitions(-DFIPS_ENTROPY_SOURCE_JITTER_CPU)
add_subdirectory(third_party/jitterentropy)
message(STATUS "FIPS entropy source method configured: CPU Jitter")
else()
add_definitions(-DFIPS_ENTROPY_SOURCE_PASSIVE)
Expand Down Expand Up @@ -1020,6 +1020,7 @@ if(BUILD_TESTING)
endmacro()
endif()

add_subdirectory(third_party/jitterentropy)
add_subdirectory(crypto)
if(BUILD_LIBSSL)
add_subdirectory(ssl)
Expand Down
8 changes: 1 addition & 7 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -592,13 +592,7 @@ target_include_directories(crypto_objects BEFORE PRIVATE ${PROJECT_BINARY_DIR}/s
target_include_directories(crypto_objects PRIVATE ${PROJECT_SOURCE_DIR}/include)

function(build_libcrypto name module_source)
if(FIPS AND ENABLE_FIPS_ENTROPY_CPU_JITTER)
# If the jitter cpu entropy source is enabled add an object dependency to
# the libcrypto target.
add_library(${name} $<TARGET_OBJECTS:crypto_objects> ${CRYPTO_FIPS_OBJECTS} ${module_source} $<TARGET_OBJECTS:jitterentropy>)
else()
add_library(${name} $<TARGET_OBJECTS:crypto_objects> ${CRYPTO_FIPS_OBJECTS} ${module_source})
endif()
add_library(${name} $<TARGET_OBJECTS:crypto_objects> ${CRYPTO_FIPS_OBJECTS} ${module_source} $<TARGET_OBJECTS:jitterentropy>)

if(FIPS_DELOCATE OR FIPS_SHARED)
add_dependencies(${name} bcm_o_target)
Expand Down
3 changes: 1 addition & 2 deletions crypto/fipsmodule/bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include "rand/new_rand.c"
#include "rand/entropy/entropy_sources.c"
#include "rand/entropy/tree_drbg_jitter_entropy.c"

#include <openssl/digest.h>
#include <openssl/hmac.h>
Expand Down Expand Up @@ -263,12 +264,10 @@ static void BORINGSSL_bcm_power_on_self_test(void) {
OPENSSL_cpuid_setup();
#endif

#if defined(FIPS_ENTROPY_SOURCE_JITTER_CPU)
if (jent_entropy_init()) {
fprintf(stderr, "CPU Jitter entropy RNG initialization failed.\n");
goto err;
}
#endif

#if !defined(OPENSSL_ASAN)
// Integrity tests cannot run under ASAN because it involves reading the full
Expand Down
4 changes: 0 additions & 4 deletions crypto/fipsmodule/rand/cpu_jitter_test.cc
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#if defined(BORINGSSL_FIPS) && defined(FIPS_ENTROPY_SOURCE_JITTER_CPU)

#include <gtest/gtest.h>

#include "../../test/test_util.h"
Expand Down Expand Up @@ -67,5 +65,3 @@ TEST(CPUJitterEntropyTest, Basic) {
unsigned int jitter_version = 3040000;
EXPECT_EQ(jitter_version, jent_version());
}

#endif
63 changes: 31 additions & 32 deletions crypto/fipsmodule/rand/entropy/entropy_sources.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,8 @@
#include "../internal.h"
#include "../../delocate.h"

static int entropy_default_initialize(void) {
return 1;
}

static void entropy_default_cleanup(void) {
}

static int entropy_default_get_seed(uint8_t seed[CTR_DRBG_ENTROPY_LEN]) {
CRYPTO_sysrand_for_seed(seed, CTR_DRBG_ENTROPY_LEN);
return 1;
}

static int entropy_default_get_prediction_resistance(
static int entropy_get_prediction_resistance(
const struct entropy_source_t *entropy_source,
uint8_t pred_resistance[RAND_PRED_RESISTANCE_LEN]) {
if (have_fast_rdrand() == 1 &&
rdrand(pred_resistance, RAND_PRED_RESISTANCE_LEN) != 1) {
Expand All @@ -31,41 +20,51 @@ static int entropy_default_get_prediction_resistance(
return 1;
}

static int entropy_default_randomize(void) {
static int entropy_get_extra_entropy(
const struct entropy_source_t *entropy_source,
uint8_t extra_entropy[CTR_DRBG_ENTROPY_LEN]) {
CRYPTO_sysrand(extra_entropy, CTR_DRBG_ENTROPY_LEN);
return 1;
}

// The default entropy source configuration using
// - OS randomness source for seeding.
// - Doesn't have a extra entropy source.
// - Tree DRBG with Jitter Entropy as root for seeding.
// - OS as personalization string source.
// - If run-time is on an Intel CPU and it supports rdrand, use it as a source
// for prediction resistance. Otherwise, no source.
DEFINE_LOCAL_DATA(struct entropy_source, default_entropy_source) {
out->initialize = entropy_default_initialize;
out->cleanup = entropy_default_cleanup;
out->get_seed = entropy_default_get_seed;
out->get_extra_entropy = NULL;
DEFINE_LOCAL_DATA(struct entropy_source_methods, tree_jitter_entropy_source_methods) {
out->initialize = tree_jitter_initialize;
out->zeroize_thread = tree_jitter_zeroize_thread_drbg;
out->free_thread = tree_jitter_free_thread_drbg;
out->get_seed = tree_jitter_get_seed;
out->get_extra_entropy = entropy_get_extra_entropy;
if (have_fast_rdrand() == 1) {
out->get_prediction_resistance = entropy_default_get_prediction_resistance;
out->get_prediction_resistance = entropy_get_prediction_resistance;
} else {
out->get_prediction_resistance = NULL;
}
out->randomize = entropy_default_randomize;
}

const struct entropy_source * get_entropy_source(void) {
const struct entropy_source *ent_source = default_entropy_source();
struct entropy_source_t * get_entropy_source(void) {

struct entropy_source_t *entropy_source = OPENSSL_zalloc(sizeof(struct entropy_source_t));
if (entropy_source == NULL) {
return NULL;
}

entropy_source->methods = tree_jitter_entropy_source_methods();

// Make sure that the function table contains the minimal number of callbacks
// that we expect. Also make sure that the entropy source is initialized such
// that calling code can assume that.
if (ent_source->cleanup == NULL ||
ent_source->get_seed == NULL ||
ent_source->randomize == NULL ||
ent_source->initialize == NULL ||
ent_source->initialize() != 1) {
if (entropy_source->methods == NULL ||
entropy_source->methods->zeroize_thread == NULL ||
entropy_source->methods->free_thread == NULL ||
entropy_source->methods->get_seed == NULL ||
entropy_source->methods->initialize == NULL ||
entropy_source->methods->initialize(entropy_source) != 1) {
OPENSSL_free(entropy_source);
return NULL;
}

return ent_source;
return entropy_source;
}
33 changes: 24 additions & 9 deletions crypto/fipsmodule/rand/entropy/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,33 @@
extern "C" {
#endif

// I could make these array types!
struct entropy_source {
int (*initialize)(void);
void (*cleanup)(void);
int (*get_seed)(uint8_t seed[CTR_DRBG_ENTROPY_LEN]);
int (*get_extra_entropy)(uint8_t extra_entropy[CTR_DRBG_ENTROPY_LEN]);
int (*get_prediction_resistance)(uint8_t pred_resistance[RAND_PRED_RESISTANCE_LEN]);
int (*randomize)(void);
#define ENTROPY_JITTER_MAX_NUM_TRIES (3)

struct entropy_source_t {
void *state;
const struct entropy_source_methods *methods;
};

struct entropy_source_methods {
int (*initialize)(struct entropy_source_t *entropy_source);
void (*zeroize_thread)(struct entropy_source_t *entropy_source);
void (*free_thread)(struct entropy_source_t *entropy_source);
int (*get_seed)(const struct entropy_source_t *entropy_source,
uint8_t seed[CTR_DRBG_ENTROPY_LEN]);
int (*get_extra_entropy)(const struct entropy_source_t *entropy_source,
uint8_t extra_entropy[CTR_DRBG_ENTROPY_LEN]);
int (*get_prediction_resistance)(const struct entropy_source_t *entropy_source,
uint8_t pred_resistance[RAND_PRED_RESISTANCE_LEN]);
};

// get_entropy_source will return an entropy source configured for the platform.
const struct entropy_source * get_entropy_source(void);
struct entropy_source_t * get_entropy_source(void);

OPENSSL_EXPORT int tree_jitter_initialize(struct entropy_source_t *entropy_source);
OPENSSL_EXPORT void tree_jitter_zeroize_thread_drbg(struct entropy_source_t *entropy_source);
OPENSSL_EXPORT void tree_jitter_free_thread_drbg(struct entropy_source_t *entropy_source);
OPENSSL_EXPORT int tree_jitter_get_seed(
const struct entropy_source_t *entropy_source, uint8_t seed[CTR_DRBG_ENTROPY_LEN]);

#if defined(__cplusplus)
} // extern C
Expand Down
Loading

0 comments on commit ddaf6d3

Please sign in to comment.