VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/rand.c@ 98326

Last change on this file since 98326 was 98326, checked in by vboxsync, 2 years ago

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

  • Property svn:eol-style set to native
File size: 6.9 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
30#ifdef HAVE_ARPA_INET_H
31#include <arpa/inet.h>
32#endif
33
34#include <curl/curl.h>
35#include "vtls/vtls.h"
36#include "sendf.h"
37#include "timeval.h"
38#include "rand.h"
39
40/* The last 3 #include files should be in this order */
41#include "curl_printf.h"
42#include "curl_memory.h"
43#include "memdebug.h"
44
45#ifdef WIN32
46
47#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
48# define HAVE_MINGW_ORIGINAL
49#endif
50
51#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \
52 !defined(HAVE_MINGW_ORIGINAL)
53# define HAVE_WIN_BCRYPTGENRANDOM
54# include <bcrypt.h>
55# ifdef _MSC_VER
56# pragma comment(lib, "bcrypt.lib")
57# endif
58# ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG
59# define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
60# endif
61# ifndef STATUS_SUCCESS
62# define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
63# endif
64#elif defined(USE_WIN32_CRYPTO)
65# include <wincrypt.h>
66# ifdef _MSC_VER
67# pragma comment(lib, "advapi32.lib")
68# endif
69#endif
70
71CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
72{
73 memset(entropy, 0, length);
74
75#if defined(HAVE_WIN_BCRYPTGENRANDOM)
76 if(BCryptGenRandom(NULL, entropy, (ULONG)length,
77 BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS)
78 return CURLE_FAILED_INIT;
79
80 return CURLE_OK;
81#elif defined(USE_WIN32_CRYPTO)
82 {
83 HCRYPTPROV hCryptProv = 0;
84
85 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
86 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
87 return CURLE_FAILED_INIT;
88
89 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
90 CryptReleaseContext(hCryptProv, 0UL);
91 return CURLE_FAILED_INIT;
92 }
93
94 CryptReleaseContext(hCryptProv, 0UL);
95 }
96 return CURLE_OK;
97#else
98 return CURLE_NOT_BUILT_IN;
99#endif
100}
101#endif
102
103static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
104{
105 unsigned int r;
106 CURLcode result = CURLE_OK;
107 static unsigned int randseed;
108 static bool seeded = FALSE;
109
110#ifdef CURLDEBUG
111 char *force_entropy = getenv("CURL_ENTROPY");
112 if(force_entropy) {
113 if(!seeded) {
114 unsigned int seed = 0;
115 size_t elen = strlen(force_entropy);
116 size_t clen = sizeof(seed);
117 size_t min = elen < clen ? elen : clen;
118 memcpy((char *)&seed, force_entropy, min);
119 randseed = ntohl(seed);
120 seeded = TRUE;
121 }
122 else
123 randseed++;
124 *rnd = randseed;
125 return CURLE_OK;
126 }
127#endif
128
129 /* data may be NULL! */
130 result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd));
131 if(result != CURLE_NOT_BUILT_IN)
132 /* only if there is no random function in the TLS backend do the non crypto
133 version, otherwise return result */
134 return result;
135
136 /* ---- non-cryptographic version following ---- */
137
138#ifdef WIN32
139 if(!seeded) {
140 result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd));
141 if(result != CURLE_NOT_BUILT_IN)
142 return result;
143 }
144#endif
145
146#if defined(RANDOM_FILE) && !defined(WIN32)
147 if(!seeded) {
148 /* if there's a random file to read a seed from, use it */
149 int fd = open(RANDOM_FILE, O_RDONLY);
150 if(fd > -1) {
151 /* read random data into the randseed variable */
152 ssize_t nread = read(fd, &randseed, sizeof(randseed));
153 if(nread == sizeof(randseed))
154 seeded = TRUE;
155 close(fd);
156 }
157 }
158#endif
159
160 if(!seeded) {
161 struct curltime now = Curl_now();
162 infof(data, "WARNING: using weak random seed");
163 randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
164 randseed = randseed * 1103515245 + 12345;
165 randseed = randseed * 1103515245 + 12345;
166 randseed = randseed * 1103515245 + 12345;
167 seeded = TRUE;
168 }
169
170 /* Return an unsigned 32-bit pseudo-random number. */
171 r = randseed = randseed * 1103515245 + 12345;
172 *rnd = (r << 16) | ((r >> 16) & 0xFFFF);
173 return CURLE_OK;
174}
175
176/*
177 * Curl_rand() stores 'num' number of random unsigned integers in the buffer
178 * 'rndptr' points to.
179 *
180 * If libcurl is built without TLS support or with a TLS backend that lacks a
181 * proper random API (rustls, Gskit or mbedTLS), this function will use "weak"
182 * random.
183 *
184 * When built *with* TLS support and a backend that offers strong random, it
185 * will return error if it cannot provide strong random values.
186 *
187 * NOTE: 'data' may be passed in as NULL when coming from external API without
188 * easy handle!
189 *
190 */
191
192CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num)
193{
194 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
195
196 DEBUGASSERT(num > 0);
197
198 while(num) {
199 unsigned int r;
200 size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int);
201
202 result = randit(data, &r);
203 if(result)
204 return result;
205
206 while(left) {
207 *rnd++ = (unsigned char)(r & 0xFF);
208 r >>= 8;
209 --num;
210 --left;
211 }
212 }
213
214 return result;
215}
216
217/*
218 * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
219 * hexadecimal digits PLUS a null-terminating byte. It must be an odd number
220 * size.
221 */
222
223CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
224 size_t num)
225{
226 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
227 const char *hex = "0123456789abcdef";
228 unsigned char buffer[128];
229 unsigned char *bufp = buffer;
230 DEBUGASSERT(num > 1);
231
232#ifdef __clang_analyzer__
233 /* This silences a scan-build warning about accessing this buffer with
234 uninitialized memory. */
235 memset(buffer, 0, sizeof(buffer));
236#endif
237
238 if((num/2 >= sizeof(buffer)) || !(num&1))
239 /* make sure it fits in the local buffer and that it is an odd number! */
240 return CURLE_BAD_FUNCTION_ARGUMENT;
241
242 num--; /* save one for null-termination */
243
244 result = Curl_rand(data, buffer, num/2);
245 if(result)
246 return result;
247
248 while(num) {
249 /* clang-tidy warns on this line without this comment: */
250 /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
251 *rnd++ = hex[(*bufp & 0xF0)>>4];
252 *rnd++ = hex[*bufp & 0x0F];
253 bufp++;
254 num -= 2;
255 }
256 *rnd = 0;
257
258 return result;
259}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette