Skip to content

Commit e79649b

Browse files
quidityBoringssl LUCI CQ
authored and
Boringssl LUCI CQ
committed
Use ProcessPrng instead of RtlGenRandom on Windows
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>
1 parent bc97b7a commit e79649b

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

crypto/fipsmodule/rand/internal.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,27 @@ void CRYPTO_sysrand(uint8_t *buf, size_t len);
7070
// depending on the vendor's configuration.
7171
void CRYPTO_sysrand_for_seed(uint8_t *buf, size_t len);
7272

73-
#if defined(OPENSSL_URANDOM)
73+
#if defined(OPENSSL_URANDOM) || defined(OPENSSL_WINDOWS)
7474
// CRYPTO_init_sysrand initializes long-lived resources needed to draw entropy
7575
// from the operating system.
7676
void CRYPTO_init_sysrand(void);
77+
#else
78+
OPENSSL_INLINE void CRYPTO_init_sysrand(void) {}
79+
#endif // defined(OPENSSL_URANDOM) || defined(OPENSSL_WINDOWS)
7780

81+
#if defined(OPENSSL_URANDOM)
7882
// CRYPTO_sysrand_if_available fills |len| bytes at |buf| with entropy from the
7983
// operating system, or early /dev/urandom data, and returns 1, _if_ the entropy
8084
// pool is initialized or if getrandom() is not available and not in FIPS mode.
8185
// Otherwise it will not block and will instead fill |buf| with all zeros and
8286
// return 0.
8387
int CRYPTO_sysrand_if_available(uint8_t *buf, size_t len);
8488
#else
85-
OPENSSL_INLINE void CRYPTO_init_sysrand(void) {}
86-
8789
OPENSSL_INLINE int CRYPTO_sysrand_if_available(uint8_t *buf, size_t len) {
8890
CRYPTO_sysrand(buf, len);
8991
return 1;
9092
}
91-
#endif
93+
#endif // defined(OPENSSL_URANDOM)
9294

9395
// rand_fork_unsafe_buffering_enabled returns whether fork-unsafe buffering has
9496
// been enabled via |RAND_enable_fork_unsafe_buffering|.

crypto/rand_extra/windows.c

+35-15
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,63 @@ OPENSSL_MSVC_PRAGMA(warning(push, 3))
2727
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
2828
#include <bcrypt.h>
2929
OPENSSL_MSVC_PRAGMA(comment(lib, "bcrypt.lib"))
30-
#else
31-
// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
32-
// "Community Additions" comment on MSDN here:
33-
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
34-
#define SystemFunction036 NTAPI SystemFunction036
35-
#include <ntsecapi.h>
36-
#undef SystemFunction036
3730
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
3831

3932
OPENSSL_MSVC_PRAGMA(warning(pop))
4033

4134
#include "../fipsmodule/rand/internal.h"
4235

36+
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
37+
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
38+
void CRYPTO_init_sysrand(void) {}
39+
#else
40+
// See: https://learn.microsoft.com/en-us/windows/win32/seccng/processprng
41+
typedef BOOL (WINAPI *ProcessPrngFunction)(PBYTE pbData, SIZE_T cbData);
42+
static ProcessPrngFunction g_processprng_fn = NULL;
43+
44+
static void init_processprng(void) {
45+
HMODULE hmod = LoadLibraryW(L"bcryptprimitives");
46+
if (hmod == NULL) {
47+
abort();
48+
}
49+
g_processprng_fn = (ProcessPrngFunction)GetProcAddress(hmod, "ProcessPrng");
50+
if (g_processprng_fn == NULL) {
51+
abort();
52+
}
53+
}
54+
55+
void CRYPTO_init_sysrand(void) {
56+
static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
57+
CRYPTO_once(&once, init_processprng);
58+
}
59+
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
4360

4461
void CRYPTO_sysrand(uint8_t *out, size_t requested) {
62+
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
63+
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
4564
while (requested > 0) {
4665
ULONG output_bytes_this_pass = ULONG_MAX;
4766
if (requested < output_bytes_this_pass) {
4867
output_bytes_this_pass = (ULONG)requested;
4968
}
50-
// On non-UWP configurations, use RtlGenRandom instead of BCryptGenRandom
51-
// to avoid accessing resources that may be unavailable inside the
52-
// Chromium sandbox. See https://crbug.com/boringssl/307
53-
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
54-
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
5569
if (!BCRYPT_SUCCESS(BCryptGenRandom(
5670
/*hAlgorithm=*/NULL, out, output_bytes_this_pass,
5771
BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
58-
#else
59-
if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) {
60-
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
6172
abort();
6273
}
6374
requested -= output_bytes_this_pass;
6475
out += output_bytes_this_pass;
6576
}
6677
return;
78+
#else
79+
CRYPTO_init_sysrand();
80+
// On non-UWP configurations, use ProcessPrng instead of BCryptGenRandom
81+
// to avoid accessing resources that may be unavailable inside the
82+
// Chromium sandbox. See https://crbug.com/74242
83+
if (!g_processprng_fn(out, requested)) {
84+
abort();
85+
}
86+
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
6787
}
6888

6989
void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) {

0 commit comments

Comments
 (0)