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