Coverage Report

Created: 2025-08-26 06:34

/src/unbound/util/random.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * util/random.c - thread safe random generator, which is reasonably secure.
3
 * 
4
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5
 * 
6
 * This software is open source.
7
 * 
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 
12
 * Redistributions of source code must retain the above copyright notice,
13
 * this list of conditions and the following disclaimer.
14
 * 
15
 * Redistributions in binary form must reproduce the above copyright notice,
16
 * this list of conditions and the following disclaimer in the documentation
17
 * and/or other materials provided with the distribution.
18
 * 
19
 * Neither the name of the NLNET LABS nor the names of its contributors may
20
 * be used to endorse or promote products derived from this software without
21
 * specific prior written permission.
22
 * 
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 */
35
36
/**
37
 * \file
38
 * Thread safe random functions. Similar to arc4random() with an explicit
39
 * initialisation routine.
40
 *
41
 * The code in this file is based on arc4random from
42
 * openssh-4.0p1/openbsd-compat/bsd-arc4random.c
43
 * That code is also BSD licensed. Here is their statement:
44
 *
45
 * Copyright (c) 1996, David Mazieres <dm@uun.org>
46
 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
47
 *
48
 * Permission to use, copy, modify, and distribute this software for any
49
 * purpose with or without fee is hereby granted, provided that the above
50
 * copyright notice and this permission notice appear in all copies.
51
 *
52
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
53
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
54
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
55
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
56
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
57
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
58
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
59
 */
60
#include "config.h"
61
#include "util/random.h"
62
#include "util/log.h"
63
#include <time.h>
64
65
#ifdef HAVE_NSS
66
/* nspr4 */
67
#include "prerror.h"
68
/* nss3 */
69
#include "secport.h"
70
#include "pk11pub.h"
71
#elif defined(HAVE_NETTLE)
72
#include "yarrow.h"
73
#endif
74
75
/** 
76
 * Max random value.  Similar to RAND_MAX, but more portable
77
 * (mingw uses only 15 bits random).
78
 */
79
0
#define MAX_VALUE 0x7fffffff
80
81
/* If the build mode is for fuzzing this removes randomness from the output.
82
 * This helps fuzz engines from having state increase due to the randomness. */
83
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
84
struct ub_randstate {
85
       unsigned int dummy;
86
};
87
88
struct ub_randstate* ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
89
0
{
90
0
       struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
91
0
       if(!s) {
92
0
               log_err("malloc failure in random init");
93
0
               return NULL;
94
0
       }
95
0
       return s;
96
0
}
97
98
long int ub_random(struct ub_randstate* state)
99
0
{
100
0
       state->dummy++;
101
0
       return (long int)(state->dummy & MAX_VALUE);
102
0
}
103
104
long int
105
ub_random_max(struct ub_randstate* state, long int x)
106
0
{
107
0
       state->dummy++;
108
0
       return ((long int)state->dummy % x);
109
0
}
110
#else /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
111
112
#if defined(HAVE_SSL) || defined(HAVE_LIBBSD)
113
struct ub_randstate* 
114
ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
115
{
116
  struct ub_randstate* s = (struct ub_randstate*)malloc(1);
117
  if(!s) {
118
    log_err("malloc failure in random init");
119
    return NULL;
120
  }
121
  return s;
122
}
123
124
long int 
125
ub_random(struct ub_randstate* ATTR_UNUSED(s))
126
{
127
  /* This relies on MAX_VALUE being 0x7fffffff. */
128
  return (long)arc4random() & MAX_VALUE;
129
}
130
131
long int
132
ub_random_max(struct ub_randstate* state, long int x)
133
{
134
  (void)state;
135
  /* on OpenBSD, this does not need _seed(), or _stir() calls */
136
  return (long)arc4random_uniform((uint32_t)x);
137
}
138
139
#elif defined(HAVE_NSS)
140
141
/* not much to remember for NSS since we use its pk11_random, placeholder */
142
struct ub_randstate {
143
  int ready;
144
};
145
146
struct ub_randstate* ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
147
{
148
  struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
149
  if(!s) {
150
    log_err("malloc failure in random init");
151
    return NULL;
152
  }
153
  return s;
154
}
155
156
long int ub_random(struct ub_randstate* ATTR_UNUSED(state))
157
{
158
  long int x;
159
  /* random 31 bit value. */
160
  SECStatus s = PK11_GenerateRandom((unsigned char*)&x, (int)sizeof(x));
161
  if(s != SECSuccess) {
162
    /* unbound needs secure randomness for randomized
163
     * ID bits and port numbers in packets to upstream servers */
164
    fatal_exit("PK11_GenerateRandom error: %s",
165
      PORT_ErrorToString(PORT_GetError()));
166
  }
167
  return x & MAX_VALUE;
168
}
169
170
#elif defined(HAVE_NETTLE)
171
172
/**
173
 * libnettle implements a Yarrow-256 generator (SHA256 + AES),
174
 * and we have to ensure it is seeded before use.
175
 */
176
struct ub_randstate {
177
  struct yarrow256_ctx ctx;
178
  int seeded;
179
};
180
181
struct ub_randstate* ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
182
{
183
  struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
184
  uint8_t buf[YARROW256_SEED_FILE_SIZE];
185
  if(!s) {
186
    log_err("malloc failure in random init");
187
    return NULL;
188
  }
189
  /* Setup Yarrow context */
190
  yarrow256_init(&s->ctx, 0, NULL);
191
192
  if(getentropy(buf, sizeof(buf)) != -1) {
193
    /* got entropy */
194
    yarrow256_seed(&s->ctx, YARROW256_SEED_FILE_SIZE, buf);
195
    s->seeded = yarrow256_is_seeded(&s->ctx);
196
  } else {
197
    log_err("nettle random(yarrow) cannot initialize, "
198
      "getentropy failed: %s", strerror(errno));
199
    free(s);
200
    return NULL;
201
  }
202
203
  return s;
204
}
205
206
long int ub_random(struct ub_randstate* s)
207
{
208
  /* random 31 bit value. */
209
  long int x = 0;
210
  if (!s || !s->seeded) {
211
    log_err("Couldn't generate randomness, Yarrow-256 generator not yet seeded");
212
  } else {
213
    yarrow256_random(&s->ctx, sizeof(x), (uint8_t *)&x);
214
  }
215
  return x & MAX_VALUE;
216
}
217
#endif /* HAVE_SSL or HAVE_LIBBSD or HAVE_NSS or HAVE_NETTLE */
218
219
220
#if defined(HAVE_NSS) || defined(HAVE_NETTLE) && !defined(HAVE_LIBBSD)
221
long int
222
ub_random_max(struct ub_randstate* state, long int x)
223
{
224
  /* make sure we fetch in a range that is divisible by x. ignore
225
   * values from d .. MAX_VALUE, instead draw a new number */
226
  long int d = MAX_VALUE - (MAX_VALUE % x); /* d is divisible by x */
227
  long int v = ub_random(state);
228
  while(d <= v)
229
    v = ub_random(state);
230
  return (v % x);
231
}
232
#endif /* HAVE_NSS or HAVE_NETTLE and !HAVE_LIBBSD */
233
234
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
235
236
void 
237
ub_randfree(struct ub_randstate* s)
238
0
{
239
0
  free(s);
240
  /* user app must do RAND_cleanup(); */
241
0
}