mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
Move curlx_ functions into its own subdir. The idea is to use the curlx_ prefix proper on these functions, and use these same function names both in tool, lib and test suite source code. Stop the previous special #define setup for curlx_ names. The printf defines are now done for the library alone. Tests no longer use the printf defines. The tool code sets its own defines. The printf functions are not curlx, they are publicly available. The strcase defines are not curlx_ functions and should not be used by tool or server code. dynbuf, warnless, base64, strparse, timeval, timediff are now proper curlx functions. When libcurl is built statically, the functions from the library can be used as-is. The key is then that the functions must work as-is, without having to be recompiled for use in tool/tests. This avoids symbol collisions - when libcurl is built statically, we use those functions directly when building the tool/tests. When libcurl is shared, we build/link them separately for the tool/tests. Assisted-by: Jay Satiro Closes #17253
304 lines
7.7 KiB
C
304 lines
7.7 KiB
C
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
* SPDX-License-Identifier: curl
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "curl_setup.h"
|
|
|
|
#include <limits.h>
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
#ifdef HAVE_ARPA_INET_H
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#include <curl/curl.h>
|
|
#include "urldata.h"
|
|
#include "vtls/vtls.h"
|
|
#include "sendf.h"
|
|
#include "curlx/timeval.h"
|
|
#include "rand.h"
|
|
#include "escape.h"
|
|
|
|
/* The last 3 #include files should be in this order */
|
|
#include "curl_printf.h"
|
|
#include "curl_memory.h"
|
|
#include "memdebug.h"
|
|
|
|
#ifdef _WIN32
|
|
|
|
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \
|
|
!defined(CURL_WINDOWS_UWP)
|
|
# define HAVE_WIN_BCRYPTGENRANDOM
|
|
# include <bcrypt.h>
|
|
# ifdef _MSC_VER
|
|
# pragma comment(lib, "bcrypt.lib")
|
|
# endif
|
|
# ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG
|
|
# define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
|
|
# endif
|
|
# ifndef STATUS_SUCCESS
|
|
# define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
|
# endif
|
|
#elif defined(USE_WIN32_CRYPTO)
|
|
# include <wincrypt.h>
|
|
# ifdef _MSC_VER
|
|
# pragma comment(lib, "advapi32.lib")
|
|
# endif
|
|
#endif
|
|
|
|
CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
|
|
{
|
|
memset(entropy, 0, length);
|
|
|
|
#if defined(HAVE_WIN_BCRYPTGENRANDOM)
|
|
if(BCryptGenRandom(NULL, entropy, (ULONG)length,
|
|
BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS)
|
|
return CURLE_FAILED_INIT;
|
|
|
|
return CURLE_OK;
|
|
#elif defined(USE_WIN32_CRYPTO)
|
|
{
|
|
HCRYPTPROV hCryptProv = 0;
|
|
|
|
if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
|
return CURLE_FAILED_INIT;
|
|
|
|
if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
|
|
CryptReleaseContext(hCryptProv, 0UL);
|
|
return CURLE_FAILED_INIT;
|
|
}
|
|
|
|
CryptReleaseContext(hCryptProv, 0UL);
|
|
}
|
|
return CURLE_OK;
|
|
#else
|
|
return CURLE_NOT_BUILT_IN;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if !defined(USE_SSL)
|
|
/* ---- possibly non-cryptographic version following ---- */
|
|
static CURLcode weak_random(struct Curl_easy *data,
|
|
unsigned char *entropy,
|
|
size_t length) /* always 4, size of int */
|
|
{
|
|
unsigned int r;
|
|
DEBUGASSERT(length == sizeof(int));
|
|
|
|
/* Trying cryptographically secure functions first */
|
|
#ifdef _WIN32
|
|
(void)data;
|
|
{
|
|
CURLcode result = Curl_win32_random(entropy, length);
|
|
if(result != CURLE_NOT_BUILT_IN)
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_ARC4RANDOM)
|
|
(void)data;
|
|
r = (unsigned int)arc4random();
|
|
memcpy(entropy, &r, length);
|
|
#else
|
|
infof(data, "WARNING: using weak random seed");
|
|
{
|
|
static unsigned int randseed;
|
|
static bool seeded = FALSE;
|
|
unsigned int rnd;
|
|
if(!seeded) {
|
|
struct curltime now = curlx_now();
|
|
randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
|
|
randseed = randseed * 1103515245 + 12345;
|
|
randseed = randseed * 1103515245 + 12345;
|
|
randseed = randseed * 1103515245 + 12345;
|
|
seeded = TRUE;
|
|
}
|
|
|
|
/* Return an unsigned 32-bit pseudo-random number. */
|
|
r = randseed = randseed * 1103515245 + 12345;
|
|
rnd = (r << 16) | ((r >> 16) & 0xFFFF);
|
|
memcpy(entropy, &rnd, length);
|
|
}
|
|
#endif
|
|
return CURLE_OK;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SSL
|
|
#define _random(x,y,z) Curl_ssl_random(x,y,z)
|
|
#else
|
|
#define _random(x,y,z) weak_random(x,y,z)
|
|
#endif
|
|
|
|
static CURLcode randit(struct Curl_easy *data, unsigned int *rnd,
|
|
bool env_override)
|
|
{
|
|
#ifdef DEBUGBUILD
|
|
if(env_override) {
|
|
char *force_entropy = getenv("CURL_ENTROPY");
|
|
if(force_entropy) {
|
|
static unsigned int randseed;
|
|
static bool seeded = FALSE;
|
|
|
|
if(!seeded) {
|
|
unsigned int seed = 0;
|
|
size_t elen = strlen(force_entropy);
|
|
size_t clen = sizeof(seed);
|
|
size_t min = elen < clen ? elen : clen;
|
|
memcpy((char *)&seed, force_entropy, min);
|
|
randseed = ntohl(seed);
|
|
seeded = TRUE;
|
|
}
|
|
else
|
|
randseed++;
|
|
*rnd = randseed;
|
|
return CURLE_OK;
|
|
}
|
|
}
|
|
#else
|
|
(void)env_override;
|
|
#endif
|
|
|
|
/* data may be NULL! */
|
|
return _random(data, (unsigned char *)rnd, sizeof(*rnd));
|
|
}
|
|
|
|
/*
|
|
* Curl_rand() stores 'num' number of random unsigned characters in the buffer
|
|
* 'rnd' points to.
|
|
*
|
|
* If libcurl is built without TLS support or arc4random, this function will
|
|
* use "weak" random.
|
|
*
|
|
* When built *with* TLS support, it will return error if it cannot provide
|
|
* strong random values.
|
|
*
|
|
* NOTE: 'data' may be passed in as NULL when coming from external API without
|
|
* easy handle!
|
|
*
|
|
*/
|
|
|
|
CURLcode Curl_rand_bytes(struct Curl_easy *data,
|
|
#ifdef DEBUGBUILD
|
|
bool env_override,
|
|
#endif
|
|
unsigned char *rnd, size_t num)
|
|
{
|
|
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
|
|
#ifndef DEBUGBUILD
|
|
const bool env_override = FALSE;
|
|
#endif
|
|
|
|
DEBUGASSERT(num);
|
|
|
|
while(num) {
|
|
unsigned int r;
|
|
size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int);
|
|
|
|
result = randit(data, &r, env_override);
|
|
if(result)
|
|
return result;
|
|
|
|
while(left) {
|
|
*rnd++ = (unsigned char)(r & 0xFF);
|
|
r >>= 8;
|
|
--num;
|
|
--left;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
|
|
* hexadecimal digits PLUS a null-terminating byte. It must be an odd number
|
|
* size.
|
|
*/
|
|
|
|
CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
|
|
size_t num)
|
|
{
|
|
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
|
|
unsigned char buffer[128];
|
|
DEBUGASSERT(num > 1);
|
|
|
|
#ifdef __clang_analyzer__
|
|
/* This silences a scan-build warning about accessing this buffer with
|
|
uninitialized memory. */
|
|
memset(buffer, 0, sizeof(buffer));
|
|
#endif
|
|
|
|
if((num/2 >= sizeof(buffer)) || !(num&1)) {
|
|
/* make sure it fits in the local buffer and that it is an odd number! */
|
|
DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex"));
|
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
|
}
|
|
|
|
num--; /* save one for null-termination */
|
|
|
|
result = Curl_rand(data, buffer, num/2);
|
|
if(result)
|
|
return result;
|
|
|
|
Curl_hexencode(buffer, num/2, rnd, num + 1);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random
|
|
* alphanumerical chars PLUS a null-terminating byte.
|
|
*/
|
|
|
|
static const char alnum[] =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
|
CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
|
|
size_t num)
|
|
{
|
|
CURLcode result = CURLE_OK;
|
|
const unsigned int alnumspace = sizeof(alnum) - 1;
|
|
unsigned int r;
|
|
DEBUGASSERT(num > 1);
|
|
|
|
num--; /* save one for null-termination */
|
|
|
|
while(num) {
|
|
do {
|
|
result = randit(data, &r, TRUE);
|
|
if(result)
|
|
return result;
|
|
} while(r >= (UINT_MAX - UINT_MAX % alnumspace));
|
|
|
|
*rnd++ = (unsigned char)alnum[r % alnumspace];
|
|
num--;
|
|
}
|
|
*rnd = 0;
|
|
|
|
return result;
|
|
}
|