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