blob: 5d4fc9f39e2e1575b1be55698e87951d20eff70e [file]
// Copyright 2014 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <assert.h>
#include <limits.h>
#include <string.h>
#if defined(BORINGSSL_FIPS)
#include <unistd.h>
#endif
#include <openssl/chacha.h>
#include <openssl/ctrdrbg.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "../../bcm_support.h"
#include "../../mem_internal.h"
#include "../bcm_interface.h"
#include "../delocate.h"
#include "internal.h"
#if defined(BORINGSSL_FIPS)
#include "../entropy/internal.h"
#endif
using namespace bssl;
// # Entropy design
//
// Each thread gets its own, thread-local DRBG. These are `rand_thread_state`
// objects. In non-FIPS mode these are seeded from the operating system. It's
// assumed that the operating system always has an unfailing source of entropy
// which is accessed via `CRYPTO_sysrand`. (If the operating system entropy
// source fails, it's up to `CRYPTO_sysrand` to abort the process—we don't try
// to handle it.)
//
// If running in FIPS mode, a compliant entropy source must be used to seed the
// thread-local DRBGs instead. That is either the BoringCrypto jitter source or,
// on Android, a source provided by the OS which is accessed via a UNIX domain
// socket. When seeding from these sources, OS entropy is still used via the
// "additional data" input to the DRBG. But, from a compliance perspective,
// this input is irrelevent.
//
// Since the jitter source takes some time to run, there is a single jitter
// source per address space. It's used to seed a DRBG (`core_drbg`) which, in
// turn, seeds the thread-local DRBGs. Android also uses this core DRBG design
// in order to keep things more uniform across platforms.
//
// The core DRBG will be reseeded in accordance with NIST's reseeding
// requirements. However, since our DRBG configuration allows for 2**48
// generate calls before reseeding, it's unlikely that any process would
// observe a reseed of that DRBG.
//
// The thread-local DRBGs mean that we have to worry about the process fork()ing
// or the underlying VM getting cloned. Thus we try to mix entropy into each
// generation from the thread-local DRBGs. The hardware may provide a
// low-latency RNG. (Intel's rdrand instruction is the canonical example of
// this.) If available, that'll be used for this additional data. Otherwise
// we'll draw from the OS if it doesn't provide other fork-detection APIs.
//
// (We assume that the OS entropy is safe from fork()ing and VM duplication.
// This might be a bit of a leap of faith, esp on Windows, but there's nothing
// that we can do about it.)
#if defined(BORINGSSL_FIPS)
// This #if-block needs to be outside of the anonymous namespace:
struct core_drbg {
CTR_DRBG_STATE drbg;
// calls is the number of generate calls made on `drbg` since it was last
// (re)seeded. This is bound by `kCoreReseedInterval`.
uint64_t calls = 0;
};
DEFINE_BSS_GET(struct core_drbg *, g_core_drbg, = nullptr)
DEFINE_STATIC_MUTEX(g_core_drbg_lock)
#endif // FIPS
namespace {
#if defined(BORINGSSL_FIPS)
// The number of times we'll generate from the core DRBG before reseeding.
// This is within the permitted bounds but so high that this effectively means
// that we'll never reseed it. See SP 800-90Ar1 table 3.
constexpr uint64_t kCoreReseedInterval = (UINT64_C(1) << 48) - 1;
constexpr size_t kCoreDRBGEntropySize = 48;
#if defined(OPENSSL_ANDROID)
// Android seeds from a system daemon which is responsible for getting
// entropy from a validated source.
void core_drbg_get_entropy(uint8_t entropy[kCoreDRBGEntropySize]) {
uint8_t daemon_buffer[BSSL_ENTROPY_DAEMON_RESPONSE_LEN];
size_t daemon_buffer_len = sizeof(daemon_buffer);
if (!bssl_get_seed_from_daemon(daemon_buffer, &daemon_buffer_len)) {
// If the daemon isn't running then fallback to system entropy.
CRYPTO_sysrand(entropy, kCoreDRBGEntropySize);
return;
}
SHA384(daemon_buffer, daemon_buffer_len, entropy);
}
#else
// Non-Android platforms use the jitter source.
void core_drbg_get_entropy(uint8_t entropy[kCoreDRBGEntropySize]) {
// This runs the jitter source and takes some milliseconds.
for (unsigned i = 0; i < 100; i++) {
// The internal health checks of the jitter source may cause spurious
// failures, therefore we retry a number of times because failure
// to get entropy is fatal.
if (entropy::GetSeed(entropy)) {
return;
}
}
fprintf(stderr, "Persistent jitter source failure.\n");
BORINGSSL_FIPS_abort();
}
#endif
struct core_drbg *core_drbg_get_locked() {
struct core_drbg **core = g_core_drbg_bss_get();
if (*core != nullptr) {
return *core;
}
uint8_t entropy[kCoreDRBGEntropySize];
core_drbg_get_entropy(entropy);
*core = New<core_drbg>();
if (!*core) {
BORINGSSL_FIPS_abort();
}
uint8_t nonce[CTR_DRBG_NONCE_LEN] = {0};
static constexpr char kPersonalization[] = "BoringSSL";
if (!CTR_DRBG_init(&(*core)->drbg, /*df=*/1, entropy, sizeof(entropy), nonce,
reinterpret_cast<const uint8_t *>(kPersonalization),
sizeof(kPersonalization))) {
BORINGSSL_FIPS_abort();
}
return *core;
}
// Draw a seed for a thread-local DRBG from the core DRBG.
void core_drbg_draw_seed(uint8_t *out_seed, size_t len) {
MutexWriteLock lock(g_core_drbg_lock_bss_get());
struct core_drbg *const core = core_drbg_get_locked();
if (core->calls > kCoreReseedInterval) {
uint8_t reseed_entropy[kCoreDRBGEntropySize];
core_drbg_get_entropy(reseed_entropy);
if (!CTR_DRBG_reseed(&core->drbg, reseed_entropy,
/*additional_data=*/nullptr, 0)) {
BORINGSSL_FIPS_abort();
}
core->calls = 0;
}
if (!CTR_DRBG_generate(&core->drbg, out_seed, len,
/*additional_data=*/nullptr, 0)) {
BORINGSSL_FIPS_abort();
}
core->calls++;
}
#endif // BORINGSSL_FIPS
// kReseedInterval is the number of generate calls made to a thread-local
// CTR-DRBG before reseeding.
static const unsigned kReseedInterval = 4096;
// rand_thread_state contains the per-thread state for the RNG.
struct rand_thread_state {
CTR_DRBG_STATE drbg;
uint64_t fork_generation;
// calls is the number of generate calls made on `drbg` since it was last
// (re)seeded. This is bound by `kReseedInterval`.
unsigned calls;
// fork_unsafe_buffering is non-zero iff, when `drbg` was last (re)seeded,
// fork-unsafe buffering was enabled.
int fork_unsafe_buffering;
#if defined(BORINGSSL_FIPS)
// next and prev form a nullptr-terminated, double-linked list of all states
// in a process.
struct rand_thread_state *next, *prev;
// clear_drbg_lock synchronizes between uses of `drbg` and
// `rand_thread_state_clear_all` clearing it. This lock should be uncontended
// in the common case, except on shutdown.
Mutex clear_drbg_lock;
#endif
};
} // namespace
#if defined(BORINGSSL_FIPS)
// thread_states_list is the head of a linked-list of all `rand_thread_state`
// objects in the process, one per thread. This is needed because FIPS requires
// the ability to zero them on demand (AS09.28). BoringSSL triggers this with a
// destructor function.
DEFINE_BSS_GET(struct rand_thread_state *, thread_states_list, = nullptr)
DEFINE_STATIC_MUTEX(thread_states_list_lock)
static void rand_thread_state_clear_all() __attribute__((destructor));
static void rand_thread_state_clear_all() {
thread_states_list_lock_bss_get()->LockWrite();
for (struct rand_thread_state *cur = *thread_states_list_bss_get();
cur != nullptr; cur = cur->next) {
cur->clear_drbg_lock.LockWrite();
CTR_DRBG_clear(&cur->drbg);
}
g_core_drbg_lock_bss_get()->LockWrite();
struct core_drbg **core = g_core_drbg_bss_get();
if (*core) {
CTR_DRBG_clear(&(*core)->drbg);
}
// The locks are deliberately left locked so that any threads that are still
// running will hang if they try to call `BCM_rand_bytes`. It also ensures
// `rand_thread_state_free` cannot free any thread state while we've taken the
// lock.
}
#endif
// rand_thread_state_free frees a `rand_thread_state`. This is called when a
// thread exits.
static void rand_thread_state_free(void *state_in) {
struct rand_thread_state *state =
reinterpret_cast<rand_thread_state *>(state_in);
if (state_in == nullptr) {
return;
}
#if defined(BORINGSSL_FIPS)
thread_states_list_lock_bss_get()->LockWrite();
if (state->prev != nullptr) {
state->prev->next = state->next;
} else if (*thread_states_list_bss_get() == state) {
// `state->prev` may be nullptr either if it is the head of the list,
// or if `state` is freed before it was added to the list at all.
// Compare against the head of the list to distinguish these cases.
*thread_states_list_bss_get() = state->next;
}
if (state->next != nullptr) {
state->next->prev = state->prev;
}
thread_states_list_lock_bss_get()->UnlockWrite();
CTR_DRBG_clear(&state->drbg);
#endif
Delete(state);
}
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
!defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
// rdrand should only be called if either `have_rdrand` or `have_fast_rdrand`
// returned true.
static int rdrand(uint8_t *buf, const size_t len) {
const size_t len_multiple8 = len & ~7;
if (!CRYPTO_rdrand_multiple8_buf(buf, len_multiple8)) {
return 0;
}
const size_t remainder = len - len_multiple8;
if (remainder != 0) {
assert(remainder < 8);
uint8_t rand_buf[8];
if (!CRYPTO_rdrand(rand_buf)) {
return 0;
}
OPENSSL_memcpy(buf + len_multiple8, rand_buf, remainder);
}
return 1;
}
#else
static int rdrand(uint8_t *buf, size_t len) { return 0; }
#endif
bcm_status bssl::BCM_rand_bytes_hwrng(uint8_t *buf, const size_t len) {
if (!have_rdrand()) {
return bcm_status::failure;
}
if (rdrand(buf, len)) {
return bcm_status::not_approved;
}
return bcm_status::failure;
}
#if defined(BORINGSSL_FIPS)
// rand_get_seed fills `seed` with entropy. Since, in FIPS mode, this entropy
// comes from the jitter source / system daemon, `additional_input` will also be
// filled with system entropy.
static void rand_get_seed(struct rand_thread_state *state,
uint8_t seed[CTR_DRBG_ENTROPY_LEN],
uint8_t additional_input[CTR_DRBG_SEED_LEN],
size_t *out_additional_input_len) {
core_drbg_draw_seed(seed, CTR_DRBG_ENTROPY_LEN);
CRYPTO_sysrand(additional_input, CTR_DRBG_SEED_LEN);
*out_additional_input_len = CTR_DRBG_SEED_LEN;
}
#else
// rand_get_seed fills `seed` with system entropy in a non-FIPS build.
static void rand_get_seed(struct rand_thread_state *state,
uint8_t seed[CTR_DRBG_ENTROPY_LEN],
uint8_t additional_input[CTR_DRBG_SEED_LEN],
size_t *out_additional_input_len) {
CRYPTO_sysrand(seed, CTR_DRBG_ENTROPY_LEN);
*out_additional_input_len = 0;
}
#endif
bcm_infallible bssl::BCM_rand_bytes_with_additional_data(
uint8_t *out, size_t out_len, const uint8_t user_additional_data[32]) {
if (out_len == 0) {
return bcm_infallible::approved;
}
const uint64_t fork_generation = CRYPTO_get_fork_generation();
const int fork_unsafe_buffering = rand_fork_unsafe_buffering_enabled();
// Additional data is mixed into every CTR-DRBG call to protect, as best we
// can, against forks & VM clones. We do not over-read this information and
// don't reseed with it so, from the point of view of FIPS, this doesn't
// provide “prediction resistance”. But, in practice, it does.
uint8_t additional_data[32];
// Intel chips have fast RDRAND instructions while, in other cases, RDRAND can
// be _slower_ than a system call.
if (!have_fast_rdrand() ||
!rdrand(additional_data, sizeof(additional_data))) {
// Without a hardware RNG to save us from address-space duplication, the OS
// entropy is used. This can be expensive (one read per `RAND_bytes` call)
// and so is disabled when we have fork detection, or if the application has
// promised not to fork.
if (fork_generation != 0 || fork_unsafe_buffering) {
OPENSSL_memset(additional_data, 0, sizeof(additional_data));
} else {
CRYPTO_sysrand(additional_data, sizeof(additional_data));
}
}
for (size_t i = 0; i < sizeof(additional_data); i++) {
additional_data[i] ^= user_additional_data[i];
}
struct rand_thread_state stack_state;
struct rand_thread_state *state = reinterpret_cast<rand_thread_state *>(
CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND));
if (state == nullptr) {
state = New<rand_thread_state>();
if (state == nullptr ||
!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state,
rand_thread_state_free)) {
// If the system is out of memory, use an ephemeral state on the
// stack.
Delete(state);
state = &stack_state;
}
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
uint8_t personalization[CTR_DRBG_SEED_LEN] = {0};
size_t personalization_len = 0;
rand_get_seed(state, seed, personalization, &personalization_len);
if (!CTR_DRBG_init(&state->drbg, /*df=*/true, seed,
sizeof(seed) - CTR_DRBG_NONCE_LEN,
seed + sizeof(seed) - CTR_DRBG_NONCE_LEN,
personalization, personalization_len)) {
abort();
}
state->calls = 0;
state->fork_generation = fork_generation;
state->fork_unsafe_buffering = fork_unsafe_buffering;
#if defined(BORINGSSL_FIPS)
if (state != &stack_state) {
MutexWriteLock lock(thread_states_list_lock_bss_get());
struct rand_thread_state **states_list = thread_states_list_bss_get();
state->next = *states_list;
if (state->next != nullptr) {
state->next->prev = state;
}
state->prev = nullptr;
*states_list = state;
}
#endif
}
if (state->calls >= kReseedInterval ||
// If we've forked since `state` was last seeded, reseed.
state->fork_generation != fork_generation ||
// If `state` was seeded from a state with different fork-safety
// preferences, reseed. Suppose `state` was fork-safe, then forked into
// two children, but each of the children never fork and disable fork
// safety. The children must reseed to avoid working from the same PRNG
// state.
state->fork_unsafe_buffering != fork_unsafe_buffering) {
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
uint8_t reseed_additional_data[CTR_DRBG_SEED_LEN] = {0};
size_t reseed_additional_data_len = 0;
rand_get_seed(state, seed, reseed_additional_data,
&reseed_additional_data_len);
#if defined(BORINGSSL_FIPS)
// Take a read lock around accesses to `state->drbg`. This is needed to
// avoid returning bad entropy if we race with
// `rand_thread_state_clear_all`.
state->clear_drbg_lock.LockRead();
#endif
if (!CTR_DRBG_reseed_ex(&state->drbg, seed, sizeof(seed),
reseed_additional_data,
reseed_additional_data_len)) {
abort();
}
state->calls = 0;
state->fork_generation = fork_generation;
state->fork_unsafe_buffering = fork_unsafe_buffering;
} else {
#if defined(BORINGSSL_FIPS)
state->clear_drbg_lock.LockRead();
#endif
}
int first_call = 1;
while (out_len > 0) {
size_t todo = out_len;
if (todo > CTR_DRBG_MAX_GENERATE_LENGTH) {
todo = CTR_DRBG_MAX_GENERATE_LENGTH;
}
if (!CTR_DRBG_generate(&state->drbg, out, todo, additional_data,
first_call ? sizeof(additional_data) : 0)) {
abort();
}
out += todo;
out_len -= todo;
// Though we only check before entering the loop, this cannot add enough to
// overflow a `size_t`.
state->calls++;
first_call = 0;
}
if (state == &stack_state) {
CTR_DRBG_clear(&state->drbg);
}
#if defined(BORINGSSL_FIPS)
state->clear_drbg_lock.UnlockRead();
#endif
return bcm_infallible::approved;
}
bcm_infallible bssl::BCM_rand_bytes(uint8_t *out, size_t out_len) {
static const uint8_t kZeroAdditionalData[32] = {0};
BCM_rand_bytes_with_additional_data(out, out_len, kZeroAdditionalData);
return bcm_infallible::approved;
}