The Windows system RNG[1] lives in bcryptprimitives.dll which exports the function ProcessPrng[2] to supply random bytes from its internal generators. These are seeded and reseeded from the operating system using a device connection to \\Device\CNG which is opened when bcryptprimitives.dll is first loaded. After this CL boringssl calls ProcessPrng() directly. Before this CL boringssl got its system randomness (on non-UWP desktop Windows) from calls to RtlGenRandom[3]. This function is undocumented and unsupported, but has always been available by linking to SystemFunction036 in advadpi32.dll. In Windows 10 and later, this export simply forwards to cryptbase.dll!SystemFunction036 which calls ProcessPrng() directly. cryptbase!SystemFunction036 decompiled: ``` BOOLEAN SystemFunction036(PVOID RandomBuffer,ULONG RandomBufferLength) { BOOL retval; retval = ProcessPrng(RandomBuffer,RandomBufferLength); return retval != 0; } ``` Loading cryptbase.dll has the side effect of opening a device handle to \\Device\KsecDD which is not used by boringssl's random number wrappers. Calling ProcessPrng() directly allows sandboxed programs such as Chromium to avoid having this handle if they do not need it. ProcessPrng() also takes a size_t length rather than a u32 length, allowing some simplification of the calling code. After this CL we require bcryptprimitives to be loaded before the first call to CRYPTO_srand(). Applications using the library should either load the module themselves or call CRYPTO_pre_sandbox_init(). Before this CL boringssl required that advapi32, cryptbase and bcryptprimitives were all loaded so this should not represent a breaking change. [1] https://learn.microsoft.com/en-us/windows/win32/seccng/processprng [2] https://download.microsoft.com/download/1/c/9/1c9813b8-089c-4fef-b2ad-ad80e79403ba/Whitepaper%20-%20The%20Windows%2010%20random%20number%20generation%20infrastructure.pdf [3] https://docs.google.com/document/d/13n1t5ak0yofzcadQCF7Ew5TewSUkNfQ3n-IYodjeRYc/edit Bug: chromium:74242 Change-Id: Ifb1d6ef1a4539ff6e9a2c36cc119b7700ca2be8f Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/60825 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: David Benjamin <davidben@google.com>
94 lines
3.1 KiB
C
94 lines
3.1 KiB
C
/* Copyright (c) 2014, Google Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
|
|
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
|
|
|
#include <windows.h>
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
|
|
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
|
#include <bcrypt.h>
|
|
OPENSSL_MSVC_PRAGMA(comment(lib, "bcrypt.lib"))
|
|
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
|
|
|
|
OPENSSL_MSVC_PRAGMA(warning(pop))
|
|
|
|
#include "../fipsmodule/rand/internal.h"
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
|
|
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
|
void CRYPTO_init_sysrand(void) {}
|
|
#else
|
|
// See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng
|
|
typedef BOOL (WINAPI *ProcessPrngFunction)(PBYTE pbData, SIZE_T cbData);
|
|
static ProcessPrngFunction g_processprng_fn = NULL;
|
|
|
|
static void init_processprng(void) {
|
|
HMODULE hmod = LoadLibraryW(L"bcryptprimitives");
|
|
if (hmod == NULL) {
|
|
abort();
|
|
}
|
|
g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng");
|
|
if (g_processprng_fn == NULL) {
|
|
abort();
|
|
}
|
|
}
|
|
|
|
void CRYPTO_init_sysrand(void) {
|
|
static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
|
|
CRYPTO_once(&once, init_processprng);
|
|
}
|
|
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
|
|
|
|
void CRYPTO_sysrand(uint8_t *out, size_t requested) {
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
|
|
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
|
while (requested > 0) {
|
|
ULONG output_bytes_this_pass = ULONG_MAX;
|
|
if (requested < output_bytes_this_pass) {
|
|
output_bytes_this_pass = (ULONG)requested;
|
|
}
|
|
if (!BCRYPT_SUCCESS(BCryptGenRandom(
|
|
/*hAlgorithm=*/NULL, out, output_bytes_this_pass,
|
|
BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
|
|
abort();
|
|
}
|
|
requested -= output_bytes_this_pass;
|
|
out += output_bytes_this_pass;
|
|
}
|
|
return;
|
|
#else
|
|
CRYPTO_init_sysrand();
|
|
// On non-UWP configurations, use ProcessPrng instead of BCryptGenRandom
|
|
// to avoid accessing resources that may be unavailable inside the
|
|
// Chromium sandbox. See https://crbug.com/74242
|
|
if (!g_processprng_fn(out, requested)) {
|
|
abort();
|
|
}
|
|
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
|
|
}
|
|
|
|
void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {
|
|
CRYPTO_sysrand(out, requested);
|
|
}
|
|
|
|
#endif // OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE
|