Fix reseeding issues of the public RAND_DRBG
[openssl.git] / crypto / rand / rand_win.c
1 /*
2  * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/cryptlib.h"
11 #include <openssl/rand.h>
12 #include "rand_lcl.h"
13 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
14
15 # ifndef OPENSSL_RAND_SEED_OS
16 #  error "Unsupported seeding method configured; must be os"
17 # endif
18
19 # include <windows.h>
20 /* On Windows 7 or higher use BCrypt instead of the legacy CryptoAPI */
21 # if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0601
22 #  define USE_BCRYPTGENRANDOM
23 # endif
24
25 # ifdef USE_BCRYPTGENRANDOM
26 #  include <bcrypt.h>
27 #  pragma comment(lib, "bcrypt.lib")
28 #  ifndef STATUS_SUCCESS
29 #   define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
30 #  endif
31 # else
32 #  include <wincrypt.h>
33 /*
34  * Intel hardware RNG CSP -- available from
35  * http://developer.intel.com/design/security/rng/redist_license.htm
36  */
37 #  define PROV_INTEL_SEC 22
38 #  define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
39 # endif
40
41 size_t RAND_POOL_acquire_entropy(RAND_POOL *pool)
42 {
43 # ifndef USE_BCRYPTGENRANDOM
44     HCRYPTPROV hProvider;
45 # endif
46     unsigned char *buffer;
47     size_t bytes_needed;
48     size_t entropy_available = 0;
49
50
51 # ifdef OPENSSL_RAND_SEED_RDTSC
52     entropy_available = rand_acquire_entropy_from_tsc(pool);
53     if (entropy_available > 0)
54         return entropy_available;
55 # endif
56
57 # ifdef OPENSSL_RAND_SEED_RDCPU
58     entropy_available = rand_acquire_entropy_from_cpu(pool);
59     if (entropy_available > 0)
60         return entropy_available;
61 # endif
62
63 # ifdef USE_BCRYPTGENRANDOM
64     bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
65     buffer = RAND_POOL_add_begin(pool, bytes_needed);
66     if (buffer != NULL) {
67         size_t bytes = 0;
68         if (BCryptGenRandom(NULL, buffer, bytes_needed,
69             BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS)
70             bytes = bytes_needed;
71
72         entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
73     }
74     if (entropy_available > 0)
75         return entropy_available;
76 # else
77     bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
78     buffer = RAND_POOL_add_begin(pool, bytes_needed);
79     if (buffer != NULL) {
80         size_t bytes = 0;
81         /* poll the CryptoAPI PRNG */
82         if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
83             CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
84             if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
85                 bytes = bytes_needed;
86
87             CryptReleaseContext(hProvider, 0);
88         }
89
90         entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
91     }
92     if (entropy_available > 0)
93         return entropy_available;
94
95     bytes_needed = RAND_POOL_bytes_needed(pool, 8 /*entropy_per_byte*/);
96     buffer = RAND_POOL_add_begin(pool, bytes_needed);
97     if (buffer != NULL) {
98         size_t bytes = 0;
99         /* poll the Pentium PRG with CryptoAPI */
100         if (CryptAcquireContextW(&hProvider, NULL,
101                                  INTEL_DEF_PROV, PROV_INTEL_SEC,
102                                  CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
103             if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
104                 bytes = bytes_needed;
105
106             CryptReleaseContext(hProvider, 0);
107         }
108         entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
109     }
110     if (entropy_available > 0)
111         return entropy_available;
112 # endif
113
114     return RAND_POOL_entropy_available(pool);
115 }
116
117 # if OPENSSL_API_COMPAT < 0x10100000L
118 int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
119 {
120     RAND_poll();
121     return RAND_status();
122 }
123
124 void RAND_screen(void)
125 {
126     RAND_poll();
127 }
128 # endif
129
130 #endif