xref: /openbsd-src/usr.sbin/unbound/util/random.c (revision eaf2578e3a266f0990ea9f6289203e0efa2b0211)
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