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.
8280304Sjkim *
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).
15280304Sjkim *
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.
22280304Sjkim *
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 :-).
37280304Sjkim * 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)"
40280304Sjkim *
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.
52280304Sjkim *
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
65280304Sjkim# include <openssl/engine.h>
66111147Snectar#endif
6755714Skris
68194206Ssimon#ifdef OPENSSL_FIPS
69280304Sjkim# include <openssl/fips.h>
70280304Sjkim# include <openssl/fips_rand.h>
71280304Sjkim# include "rand_lcl.h"
72194206Ssimon#endif
73194206Ssimon
74194206Ssimon#ifndef OPENSSL_NO_ENGINE
75109998Smarkm/* non-NULL if default_RAND_meth is ENGINE-provided */
76280304Sjkimstatic ENGINE *funct_ref = NULL;
77111147Snectar#endif
78238405Sjkimstatic const RAND_METHOD *default_RAND_meth = NULL;
7955714Skris
80109998Smarkmint RAND_set_rand_method(const RAND_METHOD *meth)
81280304Sjkim{
82111147Snectar#ifndef OPENSSL_NO_ENGINE
83280304Sjkim    if (funct_ref) {
84280304Sjkim        ENGINE_finish(funct_ref);
85280304Sjkim        funct_ref = NULL;
86280304Sjkim    }
87111147Snectar#endif
88280304Sjkim    default_RAND_meth = meth;
89280304Sjkim    return 1;
90280304Sjkim}
9155714Skris
92109998Smarkmconst RAND_METHOD *RAND_get_rand_method(void)
93280304Sjkim{
94280304Sjkim    if (!default_RAND_meth) {
95111147Snectar#ifndef OPENSSL_NO_ENGINE
96280304Sjkim        ENGINE *e = ENGINE_get_default_RAND();
97280304Sjkim        if (e) {
98280304Sjkim            default_RAND_meth = ENGINE_get_RAND(e);
99280304Sjkim            if (!default_RAND_meth) {
100280304Sjkim                ENGINE_finish(e);
101280304Sjkim                e = NULL;
102280304Sjkim            }
103280304Sjkim        }
104280304Sjkim        if (e)
105280304Sjkim            funct_ref = e;
106280304Sjkim        else
107111147Snectar#endif
108280304Sjkim            default_RAND_meth = RAND_SSLeay();
109280304Sjkim    }
110280304Sjkim    return default_RAND_meth;
111280304Sjkim}
11255714Skris
113111147Snectar#ifndef OPENSSL_NO_ENGINE
114109998Smarkmint RAND_set_rand_engine(ENGINE *engine)
115280304Sjkim{
116280304Sjkim    const RAND_METHOD *tmp_meth = NULL;
117280304Sjkim    if (engine) {
118280304Sjkim        if (!ENGINE_init(engine))
119280304Sjkim            return 0;
120280304Sjkim        tmp_meth = ENGINE_get_RAND(engine);
121280304Sjkim        if (!tmp_meth) {
122280304Sjkim            ENGINE_finish(engine);
123280304Sjkim            return 0;
124280304Sjkim        }
125280304Sjkim    }
126280304Sjkim    /* This function releases any prior ENGINE so call it first */
127280304Sjkim    RAND_set_rand_method(tmp_meth);
128280304Sjkim    funct_ref = engine;
129280304Sjkim    return 1;
130280304Sjkim}
131111147Snectar#endif
132109998Smarkm
13355714Skrisvoid RAND_cleanup(void)
134280304Sjkim{
135280304Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
136280304Sjkim    if (meth && meth->cleanup)
137280304Sjkim        meth->cleanup();
138280304Sjkim    RAND_set_rand_method(NULL);
139280304Sjkim}
14055714Skris
14155714Skrisvoid RAND_seed(const void *buf, int num)
142280304Sjkim{
143280304Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
144280304Sjkim    if (meth && meth->seed)
145280304Sjkim        meth->seed(buf, num);
146280304Sjkim}
14755714Skris
14859191Skrisvoid RAND_add(const void *buf, int num, double entropy)
149280304Sjkim{
150280304Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
151280304Sjkim    if (meth && meth->add)
152280304Sjkim        meth->add(buf, num, entropy);
153280304Sjkim}
15455714Skris
15559191Skrisint RAND_bytes(unsigned char *buf, int num)
156280304Sjkim{
157280304Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
158280304Sjkim    if (meth && meth->bytes)
159280304Sjkim        return meth->bytes(buf, num);
160280304Sjkim    return (-1);
161280304Sjkim}
16259191Skris
16359191Skrisint RAND_pseudo_bytes(unsigned char *buf, int num)
164280304Sjkim{
165280304Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
166280304Sjkim    if (meth && meth->pseudorand)
167280304Sjkim        return meth->pseudorand(buf, num);
168280304Sjkim    return (-1);
169280304Sjkim}
17059191Skris
17159191Skrisint RAND_status(void)
172280304Sjkim{
173280304Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
174280304Sjkim    if (meth && meth->status)
175280304Sjkim        return meth->status();
176280304Sjkim    return 0;
177280304Sjkim}
178238405Sjkim
179238405Sjkim#ifdef OPENSSL_FIPS
180238405Sjkim
181280304Sjkim/*
182280304Sjkim * FIPS DRBG initialisation code. This sets up the DRBG for use by the rest
183280304Sjkim * of OpenSSL.
184238405Sjkim */
185238405Sjkim
186280304Sjkim/*
187280304Sjkim * Entropy gatherer: use standard OpenSSL PRNG to seed (this will gather
188238405Sjkim * entropy internally through RAND_poll().
189238405Sjkim */
190238405Sjkim
191238405Sjkimstatic size_t drbg_get_entropy(DRBG_CTX *ctx, unsigned char **pout,
192280304Sjkim                               int entropy, size_t min_len, size_t max_len)
193280304Sjkim{
194280304Sjkim    /* Round up request to multiple of block size */
195280304Sjkim    min_len = ((min_len + 19) / 20) * 20;
196280304Sjkim    *pout = OPENSSL_malloc(min_len);
197280304Sjkim    if (!*pout)
198280304Sjkim        return 0;
199280304Sjkim    if (ssleay_rand_bytes(*pout, min_len, 0, 0) <= 0) {
200280304Sjkim        OPENSSL_free(*pout);
201280304Sjkim        *pout = NULL;
202280304Sjkim        return 0;
203280304Sjkim    }
204280304Sjkim    return min_len;
205280304Sjkim}
206238405Sjkim
207238405Sjkimstatic void drbg_free_entropy(DRBG_CTX *ctx, unsigned char *out, size_t olen)
208280304Sjkim{
209280304Sjkim    if (out) {
210280304Sjkim        OPENSSL_cleanse(out, olen);
211280304Sjkim        OPENSSL_free(out);
212280304Sjkim    }
213280304Sjkim}
214238405Sjkim
215280304Sjkim/*
216280304Sjkim * Set "additional input" when generating random data. This uses the current
217280304Sjkim * PID, a time value and a counter.
218238405Sjkim */
219238405Sjkim
220238405Sjkimstatic size_t drbg_get_adin(DRBG_CTX *ctx, unsigned char **pout)
221280304Sjkim{
222280304Sjkim    /* Use of static variables is OK as this happens under a lock */
223280304Sjkim    static unsigned char buf[16];
224280304Sjkim    static unsigned long counter;
225280304Sjkim    FIPS_get_timevec(buf, &counter);
226280304Sjkim    *pout = buf;
227280304Sjkim    return sizeof(buf);
228280304Sjkim}
229238405Sjkim
230280304Sjkim/*
231280304Sjkim * RAND_add() and RAND_seed() pass through to OpenSSL PRNG so it is
232238405Sjkim * correctly seeded by RAND_poll().
233238405Sjkim */
234238405Sjkim
235238405Sjkimstatic int drbg_rand_add(DRBG_CTX *ctx, const void *in, int inlen,
236280304Sjkim                         double entropy)
237280304Sjkim{
238280304Sjkim    RAND_SSLeay()->add(in, inlen, entropy);
239280304Sjkim    return 1;
240280304Sjkim}
241238405Sjkim
242238405Sjkimstatic int drbg_rand_seed(DRBG_CTX *ctx, const void *in, int inlen)
243280304Sjkim{
244280304Sjkim    RAND_SSLeay()->seed(in, inlen);
245280304Sjkim    return 1;
246280304Sjkim}
247238405Sjkim
248280304Sjkim# ifndef OPENSSL_DRBG_DEFAULT_TYPE
249280304Sjkim#  define OPENSSL_DRBG_DEFAULT_TYPE       NID_aes_256_ctr
250280304Sjkim# endif
251280304Sjkim# ifndef OPENSSL_DRBG_DEFAULT_FLAGS
252280304Sjkim#  define OPENSSL_DRBG_DEFAULT_FLAGS      DRBG_FLAG_CTR_USE_DF
253280304Sjkim# endif
254238405Sjkim
255238405Sjkimstatic int fips_drbg_type = OPENSSL_DRBG_DEFAULT_TYPE;
256238405Sjkimstatic int fips_drbg_flags = OPENSSL_DRBG_DEFAULT_FLAGS;
257238405Sjkim
258238405Sjkimvoid RAND_set_fips_drbg_type(int type, int flags)
259280304Sjkim{
260280304Sjkim    fips_drbg_type = type;
261280304Sjkim    fips_drbg_flags = flags;
262280304Sjkim}
263238405Sjkim
264238405Sjkimint RAND_init_fips(void)
265280304Sjkim{
266280304Sjkim    DRBG_CTX *dctx;
267280304Sjkim    size_t plen;
268280304Sjkim    unsigned char pers[32], *p;
269280304Sjkim# ifndef OPENSSL_ALLOW_DUAL_EC_DRBG
270280304Sjkim    if (fips_drbg_type >> 16) {
271280304Sjkim        RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_DUAL_EC_DRBG_DISABLED);
272280304Sjkim        return 0;
273280304Sjkim    }
274280304Sjkim# endif
275238405Sjkim
276280304Sjkim    dctx = FIPS_get_default_drbg();
277280304Sjkim    if (FIPS_drbg_init(dctx, fips_drbg_type, fips_drbg_flags) <= 0) {
278280304Sjkim        RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INITIALISING_DRBG);
279280304Sjkim        return 0;
280280304Sjkim    }
281238405Sjkim
282280304Sjkim    FIPS_drbg_set_callbacks(dctx,
283280304Sjkim                            drbg_get_entropy, drbg_free_entropy, 20,
284280304Sjkim                            drbg_get_entropy, drbg_free_entropy);
285280304Sjkim    FIPS_drbg_set_rand_callbacks(dctx, drbg_get_adin, 0,
286280304Sjkim                                 drbg_rand_seed, drbg_rand_add);
287280304Sjkim    /* Personalisation string: a string followed by date time vector */
288280304Sjkim    strcpy((char *)pers, "OpenSSL DRBG2.0");
289280304Sjkim    plen = drbg_get_adin(dctx, &p);
290280304Sjkim    memcpy(pers + 16, p, plen);
291280304Sjkim
292280304Sjkim    if (FIPS_drbg_instantiate(dctx, pers, sizeof(pers)) <= 0) {
293280304Sjkim        RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INSTANTIATING_DRBG);
294280304Sjkim        return 0;
295280304Sjkim    }
296280304Sjkim    FIPS_rand_set_method(FIPS_drbg_method());
297280304Sjkim    return 1;
298280304Sjkim}
299280304Sjkim
300238405Sjkim#endif
301