Coverage Report

Created: 2026-08-13 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/rand.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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
#include "curl_setup.h"
25
26
#ifdef HAVE_ARPA_INET_H
27
#include <arpa/inet.h>
28
#endif
29
30
#include "urldata.h"
31
#include "vtls/vtls.h"
32
#include "curl_trc.h"
33
#include "rand.h"
34
#include "escape.h"
35
36
#include "curlx/winapi.h"
37
38
#ifndef USE_SSL
39
/* ---- possibly non-cryptographic version following ---- */
40
static CURLcode weak_random(struct Curl_easy *data,
41
                            unsigned char *entropy,
42
                            size_t length) /* always 4, size of int */
43
{
44
  unsigned int r;
45
  DEBUGASSERT(length == sizeof(int));
46
47
  /* Trying cryptographically secure functions first */
48
#ifdef _WIN32
49
  (void)data;
50
  {
51
    CURLcode result = curlx_win32_random(entropy, length);
52
    if(result != CURLE_NOT_BUILT_IN)
53
      return result;
54
  }
55
#endif
56
57
#ifdef HAVE_ARC4RANDOM
58
  (void)data;
59
  r = (unsigned int)arc4random();
60
  memcpy(entropy, &r, length);
61
#else
62
  infof(data, "WARNING: using weak random seed");
63
  {
64
    static unsigned int randseed;
65
    static bool seeded = FALSE;
66
    unsigned int rnd;
67
    if(!seeded) {
68
      struct curltime now;
69
      curlx_pnow(&now);
70
      randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
71
      randseed = randseed * 1103515245 + 12345;
72
      randseed = randseed * 1103515245 + 12345;
73
      randseed = randseed * 1103515245 + 12345;
74
      seeded = TRUE;
75
    }
76
77
    /* Return an unsigned 32-bit pseudo-random number. */
78
    r = randseed = randseed * 1103515245 + 12345;
79
    rnd = (r << 16) | ((r >> 16) & 0xFFFF);
80
    memcpy(entropy, &rnd, length);
81
  }
82
#endif
83
  return CURLE_OK;
84
}
85
#endif
86
87
static CURLcode randit(struct Curl_easy *data, unsigned int *rnd,
88
                       bool env_override)
89
0
{
90
0
#ifdef DEBUGBUILD
91
0
  if(env_override) {
92
0
    char *force_entropy = getenv("CURL_ENTROPY");
93
0
    if(force_entropy) {
94
0
      static unsigned int randseed;
95
0
      static bool seeded = FALSE;
96
97
0
      if(!seeded) {
98
0
        unsigned int seed = 0;
99
0
        size_t elen = strlen(force_entropy);
100
0
        size_t clen = sizeof(seed);
101
0
        size_t min = elen < clen ? elen : clen;
102
0
        memcpy((char *)&seed, force_entropy, min);
103
0
        randseed = ntohl(seed);
104
0
        seeded = TRUE;
105
0
      }
106
0
      else
107
0
        randseed++;
108
0
      *rnd = randseed;
109
0
      return CURLE_OK;
110
0
    }
111
0
  }
112
#else
113
  (void)env_override;
114
#endif
115
116
  /* data may be NULL! */
117
0
#ifdef USE_SSL
118
0
  return Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd));
119
#else
120
  return weak_random(data, (unsigned char *)rnd, sizeof(*rnd));
121
#endif
122
0
}
123
124
/*
125
 * Curl_rand() stores 'num' number of random unsigned characters in the buffer
126
 * 'rnd' points to.
127
 *
128
 * If libcurl is built without TLS support or arc4random, this function will
129
 * use "weak" random.
130
 *
131
 * When built *with* TLS support, it will return error if it cannot provide
132
 * strong random values.
133
 *
134
 * NOTE: 'data' may be passed in as NULL when coming from external API without
135
 * easy handle!
136
 *
137
 */
138
139
CURLcode Curl_rand_bytes(struct Curl_easy *data,
140
#ifdef DEBUGBUILD
141
                         bool env_override,
142
#endif
143
                         unsigned char *rnd, size_t num)
144
0
{
145
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
146
#ifndef DEBUGBUILD
147
  const bool env_override = FALSE;
148
#endif
149
150
0
  DEBUGASSERT(num);
151
152
0
  while(num) {
153
0
    unsigned int r;
154
0
    size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int);
155
156
0
    result = randit(data, &r, env_override);
157
0
    if(result)
158
0
      return result;
159
160
0
    while(left) {
161
0
      *rnd++ = (unsigned char)(r & 0xFF);
162
0
      r >>= 8;
163
0
      --num;
164
0
      --left;
165
0
    }
166
0
  }
167
168
0
  return result;
169
0
}
170
171
/*
172
 * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
173
 * hexadecimal digits PLUS a null-terminator byte. It must be an odd number
174
 * size.
175
 */
176
177
CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, size_t num)
178
0
{
179
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
180
0
  unsigned char buffer[128];
181
0
  DEBUGASSERT(num > 1);
182
183
0
  if((num / 2 >= sizeof(buffer)) || !(num & 1)) {
184
    /* make sure it fits in the local buffer and that it is an odd number! */
185
0
    DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex"));
186
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
187
0
  }
188
189
0
  num--; /* save one for null-termination */
190
191
0
  result = Curl_rand(data, buffer, num / 2);
192
0
  if(result)
193
0
    return result;
194
195
0
  Curl_hexencode(buffer, num / 2, rnd, num + 1);
196
0
  return result;
197
0
}
198
199
/*
200
 * Curl_rand_alnum() fills the 'rnd' buffer with a given 'num' size with random
201
 * alphanumerical chars PLUS a null-terminator byte.
202
 */
203
204
static const char alnum[] =
205
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
206
207
CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
208
                         size_t num)
209
0
{
210
0
  CURLcode result = CURLE_OK;
211
0
  const unsigned int alnumspace = CURL_CSTRLEN(alnum);
212
0
  unsigned int r;
213
0
  DEBUGASSERT(num > 1);
214
215
0
  num--; /* save one for null-termination */
216
217
0
  while(num) {
218
0
    do {
219
0
      result = randit(data, &r, TRUE);
220
0
      if(result)
221
0
        return result;
222
0
    } while(r >= (UINT_MAX - UINT_MAX % alnumspace));
223
224
0
    *rnd++ = (unsigned char)alnum[r % alnumspace];
225
0
    num--;
226
0
  }
227
0
  *rnd = 0;
228
229
0
  return result;
230
0
}