Call RtlGenRandom directly in RAND_bytes.

It works within the Chromium sandbox, unlike CryptAcquireContext
and CryptGenRandom which requires the HCRYPTPROV be pre-warmed and held within
the sandbox. Also account for the mismatch between size_t and ULONG/DWORD.

See https://chromium.googlesource.com/chromium/src/+/master/base/rand_util_win.cc

BUG=crbug.com/429919

Change-Id: Ia684124736c0c039ca9410509973192a597856ab
Reviewed-on: https://boringssl-review.googlesource.com/2190
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2014-11-04 13:53:02 -05:00 committed by Adam Langley
parent 0e2a3cf98a
commit dfc2948c73

View File

@ -14,57 +14,36 @@
#include <openssl/rand.h>
#include <openssl/thread.h>
#if defined(OPENSSL_WINDOWS)
#include <limits.h>
#include <stdlib.h>
#include <Windows.h>
#include <Wincrypt.h>
static char global_provider_init;
static HCRYPTPROV global_provider;
/* #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
* "Community Additions" comment on MSDN here:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
#define SystemFunction036 NTAPI SystemFunction036
#include <NTSecAPI.h>
#undef SystemFunction036
void RAND_cleanup(void) {
CRYPTO_w_lock(CRYPTO_LOCK_RAND);
CryptReleaseContext(global_provider, 0);
global_provider_init = 0;
CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
}
int RAND_bytes(uint8_t *out, size_t requested) {
HCRYPTPROV provider = 0;
int ok;
CRYPTO_r_lock(CRYPTO_LOCK_RAND);
if (!global_provider_init) {
CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
CRYPTO_w_lock(CRYPTO_LOCK_RAND);
if (!global_provider_init) {
if (CryptAcquireContext(&global_provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
global_provider_init = 1;
}
while (requested > 0) {
ULONG output_bytes_this_pass = ULONG_MAX;
if (requested < output_bytes_this_pass) {
output_bytes_this_pass = requested;
}
CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
CRYPTO_r_lock(CRYPTO_LOCK_RAND);
if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) {
abort();
return 0;
}
requested -= output_bytes_this_pass;
out += output_bytes_this_pass;
}
ok = global_provider_init;
provider = global_provider;
CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
if (!ok) {
abort();
return ok;
}
if (TRUE != CryptGenRandom(provider, requested, out)) {
abort();
return 0;
}
return 1;
}