1933707f3Ssthen /*
2933707f3Ssthen * util/random.c - thread safe random generator, which is reasonably secure.
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen */
35933707f3Ssthen
36933707f3Ssthen /**
37933707f3Ssthen * \file
38933707f3Ssthen * Thread safe random functions. Similar to arc4random() with an explicit
39933707f3Ssthen * initialisation routine.
40933707f3Ssthen *
41933707f3Ssthen * The code in this file is based on arc4random from
42933707f3Ssthen * openssh-4.0p1/openbsd-compat/bsd-arc4random.c
43933707f3Ssthen * That code is also BSD licensed. Here is their statement:
44933707f3Ssthen *
45933707f3Ssthen * Copyright (c) 1996, David Mazieres <dm@uun.org>
46933707f3Ssthen * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
47933707f3Ssthen *
48933707f3Ssthen * Permission to use, copy, modify, and distribute this software for any
49933707f3Ssthen * purpose with or without fee is hereby granted, provided that the above
50933707f3Ssthen * copyright notice and this permission notice appear in all copies.
51933707f3Ssthen *
52933707f3Ssthen * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
53933707f3Ssthen * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
54933707f3Ssthen * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
55933707f3Ssthen * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
56933707f3Ssthen * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
57933707f3Ssthen * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
58933707f3Ssthen * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
59933707f3Ssthen */
60933707f3Ssthen #include "config.h"
61933707f3Ssthen #include "util/random.h"
62933707f3Ssthen #include "util/log.h"
635d76a658Ssthen #include <time.h>
64933707f3Ssthen
65e10d3884Sbrad #ifdef HAVE_NSS
66e10d3884Sbrad /* nspr4 */
67e10d3884Sbrad #include "prerror.h"
68e10d3884Sbrad /* nss3 */
69e10d3884Sbrad #include "secport.h"
70e10d3884Sbrad #include "pk11pub.h"
7124893edcSsthen #elif defined(HAVE_NETTLE)
7224893edcSsthen #include "yarrow.h"
73e10d3884Sbrad #endif
74e10d3884Sbrad
75933707f3Ssthen /**
763dcb24b8Ssthen * Max random value. Similar to RAND_MAX, but more portable
773dcb24b8Ssthen * (mingw uses only 15 bits random).
783dcb24b8Ssthen */
793dcb24b8Ssthen #define MAX_VALUE 0x7fffffff
803dcb24b8Ssthen
81*eaf2578eSsthen #if defined(HAVE_SSL) || defined(HAVE_LIBBSD)
82933707f3Ssthen struct ub_randstate*
ub_initstate(struct ub_randstate * ATTR_UNUSED (from))83ebf5bb73Ssthen ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
84933707f3Ssthen {
85e10d3884Sbrad struct ub_randstate* s = (struct ub_randstate*)malloc(1);
86933707f3Ssthen if(!s) {
87933707f3Ssthen log_err("malloc failure in random init");
88933707f3Ssthen return NULL;
89933707f3Ssthen }
90933707f3Ssthen return s;
91933707f3Ssthen }
92933707f3Ssthen
93933707f3Ssthen long int
ub_random(struct ub_randstate * ATTR_UNUSED (s))94e10d3884Sbrad ub_random(struct ub_randstate* ATTR_UNUSED(s))
95933707f3Ssthen {
96165a1087Sjca /* This relies on MAX_VALUE being 0x7fffffff. */
97165a1087Sjca return (long)arc4random() & MAX_VALUE;
983dcb24b8Ssthen }
993dcb24b8Ssthen
100933707f3Ssthen long int
ub_random_max(struct ub_randstate * state,long int x)101933707f3Ssthen ub_random_max(struct ub_randstate* state, long int x)
102933707f3Ssthen {
103e10d3884Sbrad (void)state;
104e10d3884Sbrad /* on OpenBSD, this does not need _seed(), or _stir() calls */
105e10d3884Sbrad return (long)arc4random_uniform((uint32_t)x);
106933707f3Ssthen }
107933707f3Ssthen
10824893edcSsthen #elif defined(HAVE_NSS)
109e10d3884Sbrad
110e10d3884Sbrad /* not much to remember for NSS since we use its pk11_random, placeholder */
111e10d3884Sbrad struct ub_randstate {
112e10d3884Sbrad int ready;
113e10d3884Sbrad };
114e10d3884Sbrad
ub_initstate(struct ub_randstate * ATTR_UNUSED (from))115ebf5bb73Ssthen struct ub_randstate* ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
116e10d3884Sbrad {
117e10d3884Sbrad struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
118e10d3884Sbrad if(!s) {
119e10d3884Sbrad log_err("malloc failure in random init");
120e10d3884Sbrad return NULL;
121e10d3884Sbrad }
122e10d3884Sbrad return s;
123e10d3884Sbrad }
124e10d3884Sbrad
ub_random(struct ub_randstate * ATTR_UNUSED (state))125e10d3884Sbrad long int ub_random(struct ub_randstate* ATTR_UNUSED(state))
126e10d3884Sbrad {
127e10d3884Sbrad long int x;
128e10d3884Sbrad /* random 31 bit value. */
129e10d3884Sbrad SECStatus s = PK11_GenerateRandom((unsigned char*)&x, (int)sizeof(x));
130e10d3884Sbrad if(s != SECSuccess) {
131ebf5bb73Ssthen /* unbound needs secure randomness for randomized
132ebf5bb73Ssthen * ID bits and port numbers in packets to upstream servers */
133ebf5bb73Ssthen fatal_exit("PK11_GenerateRandom error: %s",
134e10d3884Sbrad PORT_ErrorToString(PORT_GetError()));
135e10d3884Sbrad }
136e10d3884Sbrad return x & MAX_VALUE;
137e10d3884Sbrad }
138e10d3884Sbrad
13924893edcSsthen #elif defined(HAVE_NETTLE)
14024893edcSsthen
14124893edcSsthen /**
14224893edcSsthen * libnettle implements a Yarrow-256 generator (SHA256 + AES),
14324893edcSsthen * and we have to ensure it is seeded before use.
14424893edcSsthen */
14524893edcSsthen struct ub_randstate {
14624893edcSsthen struct yarrow256_ctx ctx;
14724893edcSsthen int seeded;
14824893edcSsthen };
14924893edcSsthen
ub_initstate(struct ub_randstate * ATTR_UNUSED (from))150ebf5bb73Ssthen struct ub_randstate* ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
15124893edcSsthen {
15224893edcSsthen struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
15324893edcSsthen uint8_t buf[YARROW256_SEED_FILE_SIZE];
15424893edcSsthen if(!s) {
15524893edcSsthen log_err("malloc failure in random init");
15624893edcSsthen return NULL;
15724893edcSsthen }
15824893edcSsthen /* Setup Yarrow context */
15924893edcSsthen yarrow256_init(&s->ctx, 0, NULL);
16024893edcSsthen
16124893edcSsthen if(getentropy(buf, sizeof(buf)) != -1) {
16224893edcSsthen /* got entropy */
16324893edcSsthen yarrow256_seed(&s->ctx, YARROW256_SEED_FILE_SIZE, buf);
16424893edcSsthen s->seeded = yarrow256_is_seeded(&s->ctx);
16524893edcSsthen } else {
166ebf5bb73Ssthen log_err("nettle random(yarrow) cannot initialize, "
167ebf5bb73Ssthen "getentropy failed: %s", strerror(errno));
168ebf5bb73Ssthen free(s);
169ebf5bb73Ssthen return NULL;
17024893edcSsthen }
17124893edcSsthen
17224893edcSsthen return s;
17324893edcSsthen }
17424893edcSsthen
ub_random(struct ub_randstate * s)17524893edcSsthen long int ub_random(struct ub_randstate* s)
17624893edcSsthen {
17724893edcSsthen /* random 31 bit value. */
17824893edcSsthen long int x = 0;
17924893edcSsthen if (!s || !s->seeded) {
18024893edcSsthen log_err("Couldn't generate randomness, Yarrow-256 generator not yet seeded");
18124893edcSsthen } else {
18224893edcSsthen yarrow256_random(&s->ctx, sizeof(x), (uint8_t *)&x);
18324893edcSsthen }
18424893edcSsthen return x & MAX_VALUE;
18524893edcSsthen }
186*eaf2578eSsthen #endif /* HAVE_SSL or HAVE_LIBBSD or HAVE_NSS or HAVE_NETTLE */
18724893edcSsthen
18824893edcSsthen
189*eaf2578eSsthen #if defined(HAVE_NSS) || defined(HAVE_NETTLE) && !defined(HAVE_LIBBSD)
190e10d3884Sbrad long int
ub_random_max(struct ub_randstate * state,long int x)191e10d3884Sbrad ub_random_max(struct ub_randstate* state, long int x)
192e10d3884Sbrad {
193e10d3884Sbrad /* make sure we fetch in a range that is divisible by x. ignore
194e10d3884Sbrad * values from d .. MAX_VALUE, instead draw a new number */
195e10d3884Sbrad long int d = MAX_VALUE - (MAX_VALUE % x); /* d is divisible by x */
196e10d3884Sbrad long int v = ub_random(state);
197e10d3884Sbrad while(d <= v)
198e10d3884Sbrad v = ub_random(state);
199e10d3884Sbrad return (v % x);
200e10d3884Sbrad }
201*eaf2578eSsthen #endif /* HAVE_NSS or HAVE_NETTLE and !HAVE_LIBBSD */
202e10d3884Sbrad
203933707f3Ssthen void
ub_randfree(struct ub_randstate * s)204933707f3Ssthen ub_randfree(struct ub_randstate* s)
205933707f3Ssthen {
206933707f3Ssthen free(s);
207e10d3884Sbrad /* user app must do RAND_cleanup(); */
208933707f3Ssthen }
209