113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#include <limits.h> 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#ifdef HAVE_FCNTL_H 3013498266Sopenharmony_ci#include <fcntl.h> 3113498266Sopenharmony_ci#endif 3213498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 3313498266Sopenharmony_ci#include <arpa/inet.h> 3413498266Sopenharmony_ci#endif 3513498266Sopenharmony_ci 3613498266Sopenharmony_ci#include <curl/curl.h> 3713498266Sopenharmony_ci#include "urldata.h" 3813498266Sopenharmony_ci#include "vtls/vtls.h" 3913498266Sopenharmony_ci#include "sendf.h" 4013498266Sopenharmony_ci#include "timeval.h" 4113498266Sopenharmony_ci#include "rand.h" 4213498266Sopenharmony_ci#include "escape.h" 4313498266Sopenharmony_ci 4413498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 4513498266Sopenharmony_ci#include "curl_printf.h" 4613498266Sopenharmony_ci#include "curl_memory.h" 4713498266Sopenharmony_ci#include "memdebug.h" 4813498266Sopenharmony_ci 4913498266Sopenharmony_ci#ifdef _WIN32 5013498266Sopenharmony_ci 5113498266Sopenharmony_ci#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 5213498266Sopenharmony_ci# define HAVE_WIN_BCRYPTGENRANDOM 5313498266Sopenharmony_ci# include <bcrypt.h> 5413498266Sopenharmony_ci# ifdef _MSC_VER 5513498266Sopenharmony_ci# pragma comment(lib, "bcrypt.lib") 5613498266Sopenharmony_ci# endif 5713498266Sopenharmony_ci# ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG 5813498266Sopenharmony_ci# define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 5913498266Sopenharmony_ci# endif 6013498266Sopenharmony_ci# ifndef STATUS_SUCCESS 6113498266Sopenharmony_ci# define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 6213498266Sopenharmony_ci# endif 6313498266Sopenharmony_ci#elif defined(USE_WIN32_CRYPTO) 6413498266Sopenharmony_ci# include <wincrypt.h> 6513498266Sopenharmony_ci# ifdef _MSC_VER 6613498266Sopenharmony_ci# pragma comment(lib, "advapi32.lib") 6713498266Sopenharmony_ci# endif 6813498266Sopenharmony_ci#endif 6913498266Sopenharmony_ci 7013498266Sopenharmony_ciCURLcode Curl_win32_random(unsigned char *entropy, size_t length) 7113498266Sopenharmony_ci{ 7213498266Sopenharmony_ci memset(entropy, 0, length); 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci#if defined(HAVE_WIN_BCRYPTGENRANDOM) 7513498266Sopenharmony_ci if(BCryptGenRandom(NULL, entropy, (ULONG)length, 7613498266Sopenharmony_ci BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS) 7713498266Sopenharmony_ci return CURLE_FAILED_INIT; 7813498266Sopenharmony_ci 7913498266Sopenharmony_ci return CURLE_OK; 8013498266Sopenharmony_ci#elif defined(USE_WIN32_CRYPTO) 8113498266Sopenharmony_ci { 8213498266Sopenharmony_ci HCRYPTPROV hCryptProv = 0; 8313498266Sopenharmony_ci 8413498266Sopenharmony_ci if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 8513498266Sopenharmony_ci CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) 8613498266Sopenharmony_ci return CURLE_FAILED_INIT; 8713498266Sopenharmony_ci 8813498266Sopenharmony_ci if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { 8913498266Sopenharmony_ci CryptReleaseContext(hCryptProv, 0UL); 9013498266Sopenharmony_ci return CURLE_FAILED_INIT; 9113498266Sopenharmony_ci } 9213498266Sopenharmony_ci 9313498266Sopenharmony_ci CryptReleaseContext(hCryptProv, 0UL); 9413498266Sopenharmony_ci } 9513498266Sopenharmony_ci return CURLE_OK; 9613498266Sopenharmony_ci#else 9713498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 9813498266Sopenharmony_ci#endif 9913498266Sopenharmony_ci} 10013498266Sopenharmony_ci#endif 10113498266Sopenharmony_ci 10213498266Sopenharmony_cistatic CURLcode randit(struct Curl_easy *data, unsigned int *rnd) 10313498266Sopenharmony_ci{ 10413498266Sopenharmony_ci CURLcode result = CURLE_OK; 10513498266Sopenharmony_ci static unsigned int randseed; 10613498266Sopenharmony_ci static bool seeded = FALSE; 10713498266Sopenharmony_ci 10813498266Sopenharmony_ci#ifdef CURLDEBUG 10913498266Sopenharmony_ci char *force_entropy = getenv("CURL_ENTROPY"); 11013498266Sopenharmony_ci if(force_entropy) { 11113498266Sopenharmony_ci if(!seeded) { 11213498266Sopenharmony_ci unsigned int seed = 0; 11313498266Sopenharmony_ci size_t elen = strlen(force_entropy); 11413498266Sopenharmony_ci size_t clen = sizeof(seed); 11513498266Sopenharmony_ci size_t min = elen < clen ? elen : clen; 11613498266Sopenharmony_ci memcpy((char *)&seed, force_entropy, min); 11713498266Sopenharmony_ci randseed = ntohl(seed); 11813498266Sopenharmony_ci seeded = TRUE; 11913498266Sopenharmony_ci } 12013498266Sopenharmony_ci else 12113498266Sopenharmony_ci randseed++; 12213498266Sopenharmony_ci *rnd = randseed; 12313498266Sopenharmony_ci return CURLE_OK; 12413498266Sopenharmony_ci } 12513498266Sopenharmony_ci#endif 12613498266Sopenharmony_ci 12713498266Sopenharmony_ci /* data may be NULL! */ 12813498266Sopenharmony_ci result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); 12913498266Sopenharmony_ci if(result != CURLE_NOT_BUILT_IN) 13013498266Sopenharmony_ci /* only if there is no random function in the TLS backend do the non crypto 13113498266Sopenharmony_ci version, otherwise return result */ 13213498266Sopenharmony_ci return result; 13313498266Sopenharmony_ci 13413498266Sopenharmony_ci /* ---- non-cryptographic version following ---- */ 13513498266Sopenharmony_ci 13613498266Sopenharmony_ci#ifdef _WIN32 13713498266Sopenharmony_ci if(!seeded) { 13813498266Sopenharmony_ci result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd)); 13913498266Sopenharmony_ci if(result != CURLE_NOT_BUILT_IN) 14013498266Sopenharmony_ci return result; 14113498266Sopenharmony_ci } 14213498266Sopenharmony_ci#endif 14313498266Sopenharmony_ci 14413498266Sopenharmony_ci#if defined(HAVE_ARC4RANDOM) && !defined(USE_OPENSSL) 14513498266Sopenharmony_ci if(!seeded) { 14613498266Sopenharmony_ci *rnd = (unsigned int)arc4random(); 14713498266Sopenharmony_ci return CURLE_OK; 14813498266Sopenharmony_ci } 14913498266Sopenharmony_ci#endif 15013498266Sopenharmony_ci 15113498266Sopenharmony_ci#if defined(RANDOM_FILE) && !defined(_WIN32) 15213498266Sopenharmony_ci if(!seeded) { 15313498266Sopenharmony_ci /* if there's a random file to read a seed from, use it */ 15413498266Sopenharmony_ci int fd = open(RANDOM_FILE, O_RDONLY); 15513498266Sopenharmony_ci if(fd > -1) { 15613498266Sopenharmony_ci /* read random data into the randseed variable */ 15713498266Sopenharmony_ci ssize_t nread = read(fd, &randseed, sizeof(randseed)); 15813498266Sopenharmony_ci if(nread == sizeof(randseed)) 15913498266Sopenharmony_ci seeded = TRUE; 16013498266Sopenharmony_ci close(fd); 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci } 16313498266Sopenharmony_ci#endif 16413498266Sopenharmony_ci 16513498266Sopenharmony_ci if(!seeded) { 16613498266Sopenharmony_ci struct curltime now = Curl_now(); 16713498266Sopenharmony_ci infof(data, "WARNING: using weak random seed"); 16813498266Sopenharmony_ci randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; 16913498266Sopenharmony_ci randseed = randseed * 1103515245 + 12345; 17013498266Sopenharmony_ci randseed = randseed * 1103515245 + 12345; 17113498266Sopenharmony_ci randseed = randseed * 1103515245 + 12345; 17213498266Sopenharmony_ci seeded = TRUE; 17313498266Sopenharmony_ci } 17413498266Sopenharmony_ci 17513498266Sopenharmony_ci { 17613498266Sopenharmony_ci unsigned int r; 17713498266Sopenharmony_ci /* Return an unsigned 32-bit pseudo-random number. */ 17813498266Sopenharmony_ci r = randseed = randseed * 1103515245 + 12345; 17913498266Sopenharmony_ci *rnd = (r << 16) | ((r >> 16) & 0xFFFF); 18013498266Sopenharmony_ci } 18113498266Sopenharmony_ci return CURLE_OK; 18213498266Sopenharmony_ci} 18313498266Sopenharmony_ci 18413498266Sopenharmony_ci/* 18513498266Sopenharmony_ci * Curl_rand() stores 'num' number of random unsigned characters in the buffer 18613498266Sopenharmony_ci * 'rnd' points to. 18713498266Sopenharmony_ci * 18813498266Sopenharmony_ci * If libcurl is built without TLS support or with a TLS backend that lacks a 18913498266Sopenharmony_ci * proper random API (rustls or mbedTLS), this function will use "weak" 19013498266Sopenharmony_ci * random. 19113498266Sopenharmony_ci * 19213498266Sopenharmony_ci * When built *with* TLS support and a backend that offers strong random, it 19313498266Sopenharmony_ci * will return error if it cannot provide strong random values. 19413498266Sopenharmony_ci * 19513498266Sopenharmony_ci * NOTE: 'data' may be passed in as NULL when coming from external API without 19613498266Sopenharmony_ci * easy handle! 19713498266Sopenharmony_ci * 19813498266Sopenharmony_ci */ 19913498266Sopenharmony_ci 20013498266Sopenharmony_ciCURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) 20113498266Sopenharmony_ci{ 20213498266Sopenharmony_ci CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; 20313498266Sopenharmony_ci 20413498266Sopenharmony_ci DEBUGASSERT(num); 20513498266Sopenharmony_ci 20613498266Sopenharmony_ci while(num) { 20713498266Sopenharmony_ci unsigned int r; 20813498266Sopenharmony_ci size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int); 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci result = randit(data, &r); 21113498266Sopenharmony_ci if(result) 21213498266Sopenharmony_ci return result; 21313498266Sopenharmony_ci 21413498266Sopenharmony_ci while(left) { 21513498266Sopenharmony_ci *rnd++ = (unsigned char)(r & 0xFF); 21613498266Sopenharmony_ci r >>= 8; 21713498266Sopenharmony_ci --num; 21813498266Sopenharmony_ci --left; 21913498266Sopenharmony_ci } 22013498266Sopenharmony_ci } 22113498266Sopenharmony_ci 22213498266Sopenharmony_ci return result; 22313498266Sopenharmony_ci} 22413498266Sopenharmony_ci 22513498266Sopenharmony_ci/* 22613498266Sopenharmony_ci * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random 22713498266Sopenharmony_ci * hexadecimal digits PLUS a null-terminating byte. It must be an odd number 22813498266Sopenharmony_ci * size. 22913498266Sopenharmony_ci */ 23013498266Sopenharmony_ci 23113498266Sopenharmony_ciCURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, 23213498266Sopenharmony_ci size_t num) 23313498266Sopenharmony_ci{ 23413498266Sopenharmony_ci CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; 23513498266Sopenharmony_ci unsigned char buffer[128]; 23613498266Sopenharmony_ci DEBUGASSERT(num > 1); 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci#ifdef __clang_analyzer__ 23913498266Sopenharmony_ci /* This silences a scan-build warning about accessing this buffer with 24013498266Sopenharmony_ci uninitialized memory. */ 24113498266Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 24213498266Sopenharmony_ci#endif 24313498266Sopenharmony_ci 24413498266Sopenharmony_ci if((num/2 >= sizeof(buffer)) || !(num&1)) { 24513498266Sopenharmony_ci /* make sure it fits in the local buffer and that it is an odd number! */ 24613498266Sopenharmony_ci DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex")); 24713498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 24813498266Sopenharmony_ci } 24913498266Sopenharmony_ci 25013498266Sopenharmony_ci num--; /* save one for null-termination */ 25113498266Sopenharmony_ci 25213498266Sopenharmony_ci result = Curl_rand(data, buffer, num/2); 25313498266Sopenharmony_ci if(result) 25413498266Sopenharmony_ci return result; 25513498266Sopenharmony_ci 25613498266Sopenharmony_ci Curl_hexencode(buffer, num/2, rnd, num + 1); 25713498266Sopenharmony_ci return result; 25813498266Sopenharmony_ci} 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci/* 26113498266Sopenharmony_ci * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random 26213498266Sopenharmony_ci * alphanumerical chars PLUS a null-terminating byte. 26313498266Sopenharmony_ci */ 26413498266Sopenharmony_ci 26513498266Sopenharmony_cistatic const char alnum[] = 26613498266Sopenharmony_ci "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 26713498266Sopenharmony_ci 26813498266Sopenharmony_ciCURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd, 26913498266Sopenharmony_ci size_t num) 27013498266Sopenharmony_ci{ 27113498266Sopenharmony_ci CURLcode result = CURLE_OK; 27213498266Sopenharmony_ci const int alnumspace = sizeof(alnum) - 1; 27313498266Sopenharmony_ci unsigned int r; 27413498266Sopenharmony_ci DEBUGASSERT(num > 1); 27513498266Sopenharmony_ci 27613498266Sopenharmony_ci num--; /* save one for null-termination */ 27713498266Sopenharmony_ci 27813498266Sopenharmony_ci while(num) { 27913498266Sopenharmony_ci do { 28013498266Sopenharmony_ci result = randit(data, &r); 28113498266Sopenharmony_ci if(result) 28213498266Sopenharmony_ci return result; 28313498266Sopenharmony_ci } while(r >= (UINT_MAX - UINT_MAX % alnumspace)); 28413498266Sopenharmony_ci 28513498266Sopenharmony_ci *rnd++ = alnum[r % alnumspace]; 28613498266Sopenharmony_ci num--; 28713498266Sopenharmony_ci } 28813498266Sopenharmony_ci *rnd = 0; 28913498266Sopenharmony_ci 29013498266Sopenharmony_ci return result; 29113498266Sopenharmony_ci} 292