5bc6bcf82d
Fixes #5849 In pull request #5503 a fallback was added which adds a random nonce of security_strength/2 bits if no nonce callback is provided. This change raised the entropy requirements form 256 to 384 bit, which can cause problems on some platforms (e.g. VMS, see issue #5849). The requirements for the nonce are given in section 8.6.7 of NIST SP 800-90Ar1: A nonce may be required in the construction of a seed during instantiation in order to provide a security cushion to block certain attacks. The nonce shall be either: a) A value with at least (security_strength/2) bits of entropy, or b) A value that is expected to repeat no more often than a (security_strength/2)-bit random string would be expected to repeat. Each nonce shall be unique to the cryptographic module in which instantiation is performed, but need not be secret. When used, the nonce shall be considered to be a critical security parameter. This commit implements a nonce of type b) in order to lower the entropy requirements during instantiation back to 256 bits. The formulation "shall be unique to the cryptographic module" above implies that the nonce needs to be unique among (with high probability) among all DRBG instances in "space" and "time". We try to achieve this goal by creating a nonce of the following form nonce = app-specific-data || high-resolution-utc-timestamp || counter Where || denotes concatenation. The application specific data can be something like the process or group id of the application. A utc timestamp is used because it increases monotonically, provided the system time is synchronized. This approach may not be perfect yet for a FIPS evaluation, but it should be good enough for the moment. This commit also harmonizes the implementation of the get_nonce() and the get_additional_data() callbacks and moves the platform specific parts from rand_lib.c into rand_unix.c, rand_win.c, and rand_vms.c. Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/5920)
172 lines
5 KiB
C
172 lines
5 KiB
C
/*
|
|
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the OpenSSL license (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include "internal/cryptlib.h"
|
|
#include <openssl/rand.h>
|
|
#include "rand_lcl.h"
|
|
#include "internal/rand_int.h"
|
|
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
|
|
|
|
# ifndef OPENSSL_RAND_SEED_OS
|
|
# error "Unsupported seeding method configured; must be os"
|
|
# endif
|
|
|
|
# include <windows.h>
|
|
/* On Windows 7 or higher use BCrypt instead of the legacy CryptoAPI */
|
|
# if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0601
|
|
# define USE_BCRYPTGENRANDOM
|
|
# endif
|
|
|
|
# ifdef USE_BCRYPTGENRANDOM
|
|
# include <bcrypt.h>
|
|
# pragma comment(lib, "bcrypt.lib")
|
|
# ifndef STATUS_SUCCESS
|
|
# define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
|
# endif
|
|
# else
|
|
# include <wincrypt.h>
|
|
/*
|
|
* Intel hardware RNG CSP -- available from
|
|
* http://developer.intel.com/design/security/rng/redist_license.htm
|
|
*/
|
|
# define PROV_INTEL_SEC 22
|
|
# define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
|
|
# endif
|
|
|
|
size_t rand_pool_acquire_entropy(RAND_POOL *pool)
|
|
{
|
|
# ifndef USE_BCRYPTGENRANDOM
|
|
HCRYPTPROV hProvider;
|
|
# endif
|
|
unsigned char *buffer;
|
|
size_t bytes_needed;
|
|
size_t entropy_available = 0;
|
|
|
|
|
|
# ifdef OPENSSL_RAND_SEED_RDTSC
|
|
entropy_available = rand_acquire_entropy_from_tsc(pool);
|
|
if (entropy_available > 0)
|
|
return entropy_available;
|
|
# endif
|
|
|
|
# ifdef OPENSSL_RAND_SEED_RDCPU
|
|
entropy_available = rand_acquire_entropy_from_cpu(pool);
|
|
if (entropy_available > 0)
|
|
return entropy_available;
|
|
# endif
|
|
|
|
# ifdef USE_BCRYPTGENRANDOM
|
|
bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/);
|
|
buffer = rand_pool_add_begin(pool, bytes_needed);
|
|
if (buffer != NULL) {
|
|
size_t bytes = 0;
|
|
if (BCryptGenRandom(NULL, buffer, bytes_needed,
|
|
BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS)
|
|
bytes = bytes_needed;
|
|
|
|
rand_pool_add_end(pool, bytes, 8 * bytes);
|
|
entropy_available = rand_pool_entropy_available(pool);
|
|
}
|
|
if (entropy_available > 0)
|
|
return entropy_available;
|
|
# else
|
|
bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/);
|
|
buffer = rand_pool_add_begin(pool, bytes_needed);
|
|
if (buffer != NULL) {
|
|
size_t bytes = 0;
|
|
/* poll the CryptoAPI PRNG */
|
|
if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
|
|
if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
|
|
bytes = bytes_needed;
|
|
|
|
CryptReleaseContext(hProvider, 0);
|
|
}
|
|
|
|
rand_pool_add_end(pool, bytes, 8 * bytes);
|
|
entropy_available = rand_pool_entropy_available(pool);
|
|
}
|
|
if (entropy_available > 0)
|
|
return entropy_available;
|
|
|
|
bytes_needed = rand_pool_bytes_needed(pool, 8 /*entropy_per_byte*/);
|
|
buffer = rand_pool_add_begin(pool, bytes_needed);
|
|
if (buffer != NULL) {
|
|
size_t bytes = 0;
|
|
/* poll the Pentium PRG with CryptoAPI */
|
|
if (CryptAcquireContextW(&hProvider, NULL,
|
|
INTEL_DEF_PROV, PROV_INTEL_SEC,
|
|
CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
|
|
if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
|
|
bytes = bytes_needed;
|
|
|
|
CryptReleaseContext(hProvider, 0);
|
|
}
|
|
rand_pool_add_end(pool, bytes, 8 * bytes);
|
|
entropy_available = rand_pool_entropy_available(pool);
|
|
}
|
|
if (entropy_available > 0)
|
|
return entropy_available;
|
|
# endif
|
|
|
|
return rand_pool_entropy_available(pool);
|
|
}
|
|
|
|
|
|
int rand_pool_add_nonce_data(RAND_POOL *pool)
|
|
{
|
|
struct {
|
|
DWORD pid;
|
|
DWORD tid;
|
|
FILETIME time;
|
|
} data = { 0 };
|
|
|
|
/*
|
|
* Add process id, thread id, and a high resolution timestamp to
|
|
* ensure that the nonce is unique whith high probability for
|
|
* different process instances.
|
|
*/
|
|
data.pid = GetCurrentProcessId();
|
|
data.tid = GetCurrentThreadId();
|
|
GetSystemTimeAsFileTime(&data.time);
|
|
|
|
return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
|
|
}
|
|
|
|
int rand_pool_add_additional_data(RAND_POOL *pool)
|
|
{
|
|
struct {
|
|
DWORD tid;
|
|
LARGE_INTEGER time;
|
|
} data = { 0 };
|
|
|
|
/*
|
|
* Add some noise from the thread id and a high resolution timer.
|
|
* The thread id adds a little randomness if the drbg is accessed
|
|
* concurrently (which is the case for the <master> drbg).
|
|
*/
|
|
data.tid = GetCurrentThreadId();
|
|
QueryPerformanceCounter(&data.time);
|
|
return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
|
|
}
|
|
|
|
# if OPENSSL_API_COMPAT < 0x10100000L
|
|
int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
RAND_poll();
|
|
return RAND_status();
|
|
}
|
|
|
|
void RAND_screen(void)
|
|
{
|
|
RAND_poll();
|
|
}
|
|
# endif
|
|
|
|
#endif
|