155714Skris/* crypto/rand/rand_lib.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
855714Skris *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1555714Skris *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
2255714Skris *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
3755714Skris * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4055714Skris *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
5255714Skris *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <time.h>
61109998Smarkm#include "cryptlib.h"
6255714Skris#include <openssl/rand.h>
63194206Ssimon
64111147Snectar#ifndef OPENSSL_NO_ENGINE
65109998Smarkm#include <openssl/engine.h>
66111147Snectar#endif
6755714Skris
68194206Ssimon#ifdef OPENSSL_FIPS
69238405Sjkim#include <openssl/fips.h>
70238405Sjkim#include <openssl/fips_rand.h>
71279264Sdelphij#include "rand_lcl.h"
72194206Ssimon#endif
73194206Ssimon
74194206Ssimon#ifndef OPENSSL_NO_ENGINE
75109998Smarkm/* non-NULL if default_RAND_meth is ENGINE-provided */
76109998Smarkmstatic ENGINE *funct_ref =NULL;
77111147Snectar#endif
78238405Sjkimstatic const RAND_METHOD *default_RAND_meth = NULL;
7955714Skris
80109998Smarkmint RAND_set_rand_method(const RAND_METHOD *meth)
8155714Skris	{
82111147Snectar#ifndef OPENSSL_NO_ENGINE
83109998Smarkm	if(funct_ref)
84109998Smarkm		{
85109998Smarkm		ENGINE_finish(funct_ref);
86109998Smarkm		funct_ref = NULL;
87109998Smarkm		}
88111147Snectar#endif
89109998Smarkm	default_RAND_meth = meth;
90109998Smarkm	return 1;
9155714Skris	}
9255714Skris
93109998Smarkmconst RAND_METHOD *RAND_get_rand_method(void)
9455714Skris	{
95109998Smarkm	if (!default_RAND_meth)
96109998Smarkm		{
97111147Snectar#ifndef OPENSSL_NO_ENGINE
98109998Smarkm		ENGINE *e = ENGINE_get_default_RAND();
99109998Smarkm		if(e)
100109998Smarkm			{
101109998Smarkm			default_RAND_meth = ENGINE_get_RAND(e);
102109998Smarkm			if(!default_RAND_meth)
103109998Smarkm				{
104109998Smarkm				ENGINE_finish(e);
105109998Smarkm				e = NULL;
106109998Smarkm				}
107109998Smarkm			}
108109998Smarkm		if(e)
109109998Smarkm			funct_ref = e;
110109998Smarkm		else
111111147Snectar#endif
112109998Smarkm			default_RAND_meth = RAND_SSLeay();
113109998Smarkm		}
114109998Smarkm	return default_RAND_meth;
11555714Skris	}
11655714Skris
117111147Snectar#ifndef OPENSSL_NO_ENGINE
118109998Smarkmint RAND_set_rand_engine(ENGINE *engine)
119109998Smarkm	{
120109998Smarkm	const RAND_METHOD *tmp_meth = NULL;
121109998Smarkm	if(engine)
122109998Smarkm		{
123109998Smarkm		if(!ENGINE_init(engine))
124109998Smarkm			return 0;
125109998Smarkm		tmp_meth = ENGINE_get_RAND(engine);
126109998Smarkm		if(!tmp_meth)
127109998Smarkm			{
128109998Smarkm			ENGINE_finish(engine);
129109998Smarkm			return 0;
130109998Smarkm			}
131109998Smarkm		}
132109998Smarkm	/* This function releases any prior ENGINE so call it first */
133109998Smarkm	RAND_set_rand_method(tmp_meth);
134109998Smarkm	funct_ref = engine;
135109998Smarkm	return 1;
136109998Smarkm	}
137111147Snectar#endif
138109998Smarkm
13955714Skrisvoid RAND_cleanup(void)
14055714Skris	{
141109998Smarkm	const RAND_METHOD *meth = RAND_get_rand_method();
142109998Smarkm	if (meth && meth->cleanup)
143109998Smarkm		meth->cleanup();
144109998Smarkm	RAND_set_rand_method(NULL);
14555714Skris	}
14655714Skris
14755714Skrisvoid RAND_seed(const void *buf, int num)
14855714Skris	{
149109998Smarkm	const RAND_METHOD *meth = RAND_get_rand_method();
150109998Smarkm	if (meth && meth->seed)
151109998Smarkm		meth->seed(buf,num);
15255714Skris	}
15355714Skris
15459191Skrisvoid RAND_add(const void *buf, int num, double entropy)
15555714Skris	{
156109998Smarkm	const RAND_METHOD *meth = RAND_get_rand_method();
157109998Smarkm	if (meth && meth->add)
158109998Smarkm		meth->add(buf,num,entropy);
15955714Skris	}
16055714Skris
16159191Skrisint RAND_bytes(unsigned char *buf, int num)
16259191Skris	{
163109998Smarkm	const RAND_METHOD *meth = RAND_get_rand_method();
164109998Smarkm	if (meth && meth->bytes)
165109998Smarkm		return meth->bytes(buf,num);
16659191Skris	return(-1);
16759191Skris	}
16859191Skris
16959191Skrisint RAND_pseudo_bytes(unsigned char *buf, int num)
17059191Skris	{
171109998Smarkm	const RAND_METHOD *meth = RAND_get_rand_method();
172109998Smarkm	if (meth && meth->pseudorand)
173109998Smarkm		return meth->pseudorand(buf,num);
17459191Skris	return(-1);
17559191Skris	}
17659191Skris
17759191Skrisint RAND_status(void)
17859191Skris	{
179109998Smarkm	const RAND_METHOD *meth = RAND_get_rand_method();
180109998Smarkm	if (meth && meth->status)
181109998Smarkm		return meth->status();
18259191Skris	return 0;
18359191Skris	}
184238405Sjkim
185238405Sjkim#ifdef OPENSSL_FIPS
186238405Sjkim
187238405Sjkim/* FIPS DRBG initialisation code. This sets up the DRBG for use by the
188238405Sjkim * rest of OpenSSL.
189238405Sjkim */
190238405Sjkim
191238405Sjkim/* Entropy gatherer: use standard OpenSSL PRNG to seed (this will gather
192238405Sjkim * entropy internally through RAND_poll().
193238405Sjkim */
194238405Sjkim
195238405Sjkimstatic size_t drbg_get_entropy(DRBG_CTX *ctx, unsigned char **pout,
196238405Sjkim                                int entropy, size_t min_len, size_t max_len)
197238405Sjkim        {
198238405Sjkim	/* Round up request to multiple of block size */
199238405Sjkim	min_len = ((min_len + 19) / 20) * 20;
200238405Sjkim	*pout = OPENSSL_malloc(min_len);
201238405Sjkim	if (!*pout)
202238405Sjkim		return 0;
203279264Sdelphij	if (ssleay_rand_bytes(*pout, min_len, 0, 0) <= 0)
204238405Sjkim		{
205238405Sjkim		OPENSSL_free(*pout);
206238405Sjkim		*pout = NULL;
207238405Sjkim		return 0;
208238405Sjkim		}
209238405Sjkim        return min_len;
210238405Sjkim        }
211238405Sjkim
212238405Sjkimstatic void drbg_free_entropy(DRBG_CTX *ctx, unsigned char *out, size_t olen)
213238405Sjkim	{
214246772Sjkim	if (out)
215246772Sjkim		{
216246772Sjkim		OPENSSL_cleanse(out, olen);
217246772Sjkim		OPENSSL_free(out);
218246772Sjkim		}
219238405Sjkim	}
220238405Sjkim
221238405Sjkim/* Set "additional input" when generating random data. This uses the
222238405Sjkim * current PID, a time value and a counter.
223238405Sjkim */
224238405Sjkim
225238405Sjkimstatic size_t drbg_get_adin(DRBG_CTX *ctx, unsigned char **pout)
226238405Sjkim    	{
227238405Sjkim	/* Use of static variables is OK as this happens under a lock */
228238405Sjkim	static unsigned char buf[16];
229238405Sjkim	static unsigned long counter;
230238405Sjkim	FIPS_get_timevec(buf, &counter);
231238405Sjkim	*pout = buf;
232238405Sjkim	return sizeof(buf);
233238405Sjkim	}
234238405Sjkim
235238405Sjkim/* RAND_add() and RAND_seed() pass through to OpenSSL PRNG so it is
236238405Sjkim * correctly seeded by RAND_poll().
237238405Sjkim */
238238405Sjkim
239238405Sjkimstatic int drbg_rand_add(DRBG_CTX *ctx, const void *in, int inlen,
240238405Sjkim				double entropy)
241238405Sjkim	{
242238405Sjkim	RAND_SSLeay()->add(in, inlen, entropy);
243238405Sjkim	return 1;
244238405Sjkim	}
245238405Sjkim
246238405Sjkimstatic int drbg_rand_seed(DRBG_CTX *ctx, const void *in, int inlen)
247238405Sjkim	{
248238405Sjkim	RAND_SSLeay()->seed(in, inlen);
249238405Sjkim	return 1;
250238405Sjkim	}
251238405Sjkim
252238405Sjkim#ifndef OPENSSL_DRBG_DEFAULT_TYPE
253238405Sjkim#define OPENSSL_DRBG_DEFAULT_TYPE	NID_aes_256_ctr
254238405Sjkim#endif
255238405Sjkim#ifndef OPENSSL_DRBG_DEFAULT_FLAGS
256238405Sjkim#define OPENSSL_DRBG_DEFAULT_FLAGS	DRBG_FLAG_CTR_USE_DF
257238405Sjkim#endif
258238405Sjkim
259238405Sjkimstatic int fips_drbg_type = OPENSSL_DRBG_DEFAULT_TYPE;
260238405Sjkimstatic int fips_drbg_flags = OPENSSL_DRBG_DEFAULT_FLAGS;
261238405Sjkim
262238405Sjkimvoid RAND_set_fips_drbg_type(int type, int flags)
263238405Sjkim	{
264238405Sjkim	fips_drbg_type = type;
265238405Sjkim	fips_drbg_flags = flags;
266238405Sjkim	}
267238405Sjkim
268238405Sjkimint RAND_init_fips(void)
269238405Sjkim	{
270238405Sjkim	DRBG_CTX *dctx;
271238405Sjkim	size_t plen;
272238405Sjkim	unsigned char pers[32], *p;
273279264Sdelphij#ifndef OPENSSL_ALLOW_DUAL_EC_DRBG
274279264Sdelphij	if (fips_drbg_type >> 16)
275279264Sdelphij		{
276279264Sdelphij		RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_DUAL_EC_DRBG_DISABLED);
277279264Sdelphij		return 0;
278279264Sdelphij		}
279279264Sdelphij#endif
280279264Sdelphij
281238405Sjkim	dctx = FIPS_get_default_drbg();
282238405Sjkim        if (FIPS_drbg_init(dctx, fips_drbg_type, fips_drbg_flags) <= 0)
283238405Sjkim		{
284238405Sjkim		RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INITIALISING_DRBG);
285238405Sjkim		return 0;
286238405Sjkim		}
287238405Sjkim
288238405Sjkim        FIPS_drbg_set_callbacks(dctx,
289238405Sjkim				drbg_get_entropy, drbg_free_entropy, 20,
290238405Sjkim				drbg_get_entropy, drbg_free_entropy);
291238405Sjkim	FIPS_drbg_set_rand_callbacks(dctx, drbg_get_adin, 0,
292238405Sjkim					drbg_rand_seed, drbg_rand_add);
293238405Sjkim	/* Personalisation string: a string followed by date time vector */
294238405Sjkim	strcpy((char *)pers, "OpenSSL DRBG2.0");
295238405Sjkim	plen = drbg_get_adin(dctx, &p);
296238405Sjkim	memcpy(pers + 16, p, plen);
297238405Sjkim
298238405Sjkim        if (FIPS_drbg_instantiate(dctx, pers, sizeof(pers)) <= 0)
299238405Sjkim		{
300238405Sjkim		RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INSTANTIATING_DRBG);
301238405Sjkim		return 0;
302238405Sjkim		}
303238405Sjkim        FIPS_rand_set_method(FIPS_drbg_method());
304238405Sjkim	return 1;
305238405Sjkim	}
306238405Sjkim
307238405Sjkim#endif
308