d5c5b592697736a087c7ca4b88aefe9b96bf4af9
[openssl.git] / providers / implementations / rands / seeding / rand_win.c
1 /*
2  * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (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 "crypto/rand_pool.h"
13 #include "crypto/rand.h"
14 #include "seeding.h"
15 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
16
17 # ifndef OPENSSL_RAND_SEED_OS
18 #  error "Unsupported seeding method configured; must be os"
19 # endif
20
21 # include <windows.h>
22 /* On Windows Vista or higher use BCrypt instead of the legacy CryptoAPI */
23 # if defined(_MSC_VER) && _MSC_VER > 1500 /* 1500 = Visual Studio 2008 */ \
24      && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
25 #  define USE_BCRYPTGENRANDOM
26 # endif
27
28 # ifdef USE_BCRYPTGENRANDOM
29 #  include <bcrypt.h>
30 #  pragma comment(lib, "bcrypt.lib")
31 #  ifndef STATUS_SUCCESS
32 #   define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
33 #  endif
34 # else
35 #  include <wincrypt.h>
36 /*
37  * Intel hardware RNG CSP -- available from
38  * http://developer.intel.com/design/security/rng/redist_license.htm
39  */
40 #  define PROV_INTEL_SEC 22
41 #  define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
42 # endif
43
44 size_t prov_pool_acquire_entropy(RAND_POOL *pool)
45 {
46 # ifndef USE_BCRYPTGENRANDOM
47     HCRYPTPROV hProvider;
48 # endif
49     unsigned char *buffer;
50     size_t bytes_needed;
51     size_t entropy_available = 0;
52
53
54 # ifdef OPENSSL_RAND_SEED_RDTSC
55     entropy_available = rand_acquire_entropy_from_tsc(pool);
56     if (entropy_available > 0)
57         return entropy_available;
58 # endif
59
60 # ifdef OPENSSL_RAND_SEED_RDCPU
61     entropy_available = rand_acquire_entropy_from_cpu(pool);
62     if (entropy_available > 0)
63         return entropy_available;
64 # endif
65
66 # ifdef USE_BCRYPTGENRANDOM
67     bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
68     buffer = rand_pool_add_begin(pool, bytes_needed);
69     if (buffer != NULL) {
70         size_t bytes = 0;
71         if (BCryptGenRandom(NULL, buffer, bytes_needed,
72                             BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS)
73             bytes = bytes_needed;
74
75         rand_pool_add_end(pool, bytes, 8 * bytes);
76         entropy_available = rand_pool_entropy_available(pool);
77     }
78     if (entropy_available > 0)
79         return entropy_available;
80 # else
81     bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
82     buffer = rand_pool_add_begin(pool, bytes_needed);
83     if (buffer != NULL) {
84         size_t bytes = 0;
85         /* poll the CryptoAPI PRNG */
86         if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
87                                  CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
88             if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
89                 bytes = bytes_needed;
90
91             CryptReleaseContext(hProvider, 0);
92         }
93
94         rand_pool_add_end(pool, bytes, 8 * bytes);
95         entropy_available = rand_pool_entropy_available(pool);
96     }
97     if (entropy_available > 0)
98         return entropy_available;
99
100     bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
101     buffer = rand_pool_add_begin(pool, bytes_needed);
102     if (buffer != NULL) {
103         size_t bytes = 0;
104         /* poll the Pentium PRG with CryptoAPI */
105         if (CryptAcquireContextW(&hProvider, NULL,
106                                  INTEL_DEF_PROV, PROV_INTEL_SEC,
107                                  CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
108             if (CryptGenRandom(hProvider, bytes_needed, buffer) != 0)
109                 bytes = bytes_needed;
110
111             CryptReleaseContext(hProvider, 0);
112         }
113         rand_pool_add_end(pool, bytes, 8 * bytes);
114         entropy_available = rand_pool_entropy_available(pool);
115     }
116     if (entropy_available > 0)
117         return entropy_available;
118 # endif
119
120     return rand_pool_entropy_available(pool);
121 }
122
123
124 int prov_pool_add_nonce_data(RAND_POOL *pool)
125 {
126     struct {
127         DWORD pid;
128         DWORD tid;
129         FILETIME time;
130     } data;
131
132     /* Erase the entire structure including any padding */
133     memset(&data, 0, sizeof(data));
134
135     /*
136      * Add process id, thread id, and a high resolution timestamp to
137      * ensure that the nonce is unique with high probability for
138      * different process instances.
139      */
140     data.pid = GetCurrentProcessId();
141     data.tid = GetCurrentThreadId();
142     GetSystemTimeAsFileTime(&data.time);
143
144     return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
145 }
146
147 int rand_pool_add_additional_data(RAND_POOL *pool)
148 {
149     struct {
150         DWORD tid;
151         LARGE_INTEGER time;
152     } data;
153
154     /* Erase the entire structure including any padding */
155     memset(&data, 0, sizeof(data));
156
157     /*
158      * Add some noise from the thread id and a high resolution timer.
159      * The thread id adds a little randomness if the drbg is accessed
160      * concurrently (which is the case for the <master> drbg).
161      */
162     data.tid = GetCurrentThreadId();
163     QueryPerformanceCounter(&data.time);
164     return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
165 }
166
167 int rand_pool_init(void)
168 {
169     return 1;
170 }
171
172 void rand_pool_cleanup(void)
173 {
174 }
175
176 void rand_pool_keep_random_devices_open(int keep)
177 {
178 }
179
180 #endif