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.
8280297Sjkim *
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).
15280297Sjkim *
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.
22280297Sjkim *
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 :-).
37280297Sjkim * 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)"
40280297Sjkim *
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.
52280297Sjkim *
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
65280297Sjkim# include <openssl/engine.h>
66111147Snectar#endif
6755714Skris
68194206Ssimon#ifdef OPENSSL_FIPS
69280297Sjkim# include <openssl/fips.h>
70280297Sjkim# include <openssl/fips_rand.h>
71280297Sjkim# include "rand_lcl.h"
72194206Ssimon#endif
73194206Ssimon
74194206Ssimon#ifndef OPENSSL_NO_ENGINE
75109998Smarkm/* non-NULL if default_RAND_meth is ENGINE-provided */
76280297Sjkimstatic ENGINE *funct_ref = NULL;
77111147Snectar#endif
78238405Sjkimstatic const RAND_METHOD *default_RAND_meth = NULL;
7955714Skris
80109998Smarkmint RAND_set_rand_method(const RAND_METHOD *meth)
81280297Sjkim{
82111147Snectar#ifndef OPENSSL_NO_ENGINE
83280297Sjkim    if (funct_ref) {
84280297Sjkim        ENGINE_finish(funct_ref);
85280297Sjkim        funct_ref = NULL;
86280297Sjkim    }
87111147Snectar#endif
88280297Sjkim    default_RAND_meth = meth;
89280297Sjkim    return 1;
90280297Sjkim}
9155714Skris
92109998Smarkmconst RAND_METHOD *RAND_get_rand_method(void)
93280297Sjkim{
94280297Sjkim    if (!default_RAND_meth) {
95111147Snectar#ifndef OPENSSL_NO_ENGINE
96280297Sjkim        ENGINE *e = ENGINE_get_default_RAND();
97280297Sjkim        if (e) {
98280297Sjkim            default_RAND_meth = ENGINE_get_RAND(e);
99280297Sjkim            if (!default_RAND_meth) {
100280297Sjkim                ENGINE_finish(e);
101280297Sjkim                e = NULL;
102280297Sjkim            }
103280297Sjkim        }
104280297Sjkim        if (e)
105280297Sjkim            funct_ref = e;
106280297Sjkim        else
107111147Snectar#endif
108280297Sjkim            default_RAND_meth = RAND_SSLeay();
109280297Sjkim    }
110280297Sjkim    return default_RAND_meth;
111280297Sjkim}
11255714Skris
113111147Snectar#ifndef OPENSSL_NO_ENGINE
114109998Smarkmint RAND_set_rand_engine(ENGINE *engine)
115280297Sjkim{
116280297Sjkim    const RAND_METHOD *tmp_meth = NULL;
117280297Sjkim    if (engine) {
118280297Sjkim        if (!ENGINE_init(engine))
119280297Sjkim            return 0;
120280297Sjkim        tmp_meth = ENGINE_get_RAND(engine);
121280297Sjkim        if (!tmp_meth) {
122280297Sjkim            ENGINE_finish(engine);
123280297Sjkim            return 0;
124280297Sjkim        }
125280297Sjkim    }
126280297Sjkim    /* This function releases any prior ENGINE so call it first */
127280297Sjkim    RAND_set_rand_method(tmp_meth);
128280297Sjkim    funct_ref = engine;
129280297Sjkim    return 1;
130280297Sjkim}
131111147Snectar#endif
132109998Smarkm
13355714Skrisvoid RAND_cleanup(void)
134280297Sjkim{
135280297Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
136280297Sjkim    if (meth && meth->cleanup)
137280297Sjkim        meth->cleanup();
138280297Sjkim    RAND_set_rand_method(NULL);
139280297Sjkim}
14055714Skris
14155714Skrisvoid RAND_seed(const void *buf, int num)
142280297Sjkim{
143280297Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
144280297Sjkim    if (meth && meth->seed)
145280297Sjkim        meth->seed(buf, num);
146280297Sjkim}
14755714Skris
14859191Skrisvoid RAND_add(const void *buf, int num, double entropy)
149280297Sjkim{
150280297Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
151280297Sjkim    if (meth && meth->add)
152280297Sjkim        meth->add(buf, num, entropy);
153280297Sjkim}
15455714Skris
15559191Skrisint RAND_bytes(unsigned char *buf, int num)
156280297Sjkim{
157280297Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
158280297Sjkim    if (meth && meth->bytes)
159280297Sjkim        return meth->bytes(buf, num);
160280297Sjkim    return (-1);
161280297Sjkim}
16259191Skris
16359191Skrisint RAND_pseudo_bytes(unsigned char *buf, int num)
164280297Sjkim{
165280297Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
166280297Sjkim    if (meth && meth->pseudorand)
167280297Sjkim        return meth->pseudorand(buf, num);
168280297Sjkim    return (-1);
169280297Sjkim}
17059191Skris
17159191Skrisint RAND_status(void)
172280297Sjkim{
173280297Sjkim    const RAND_METHOD *meth = RAND_get_rand_method();
174280297Sjkim    if (meth && meth->status)
175280297Sjkim        return meth->status();
176280297Sjkim    return 0;
177280297Sjkim}
178238405Sjkim
179238405Sjkim#ifdef OPENSSL_FIPS
180238405Sjkim
181280297Sjkim/*
182280297Sjkim * FIPS DRBG initialisation code. This sets up the DRBG for use by the rest
183280297Sjkim * of OpenSSL.
184238405Sjkim */
185238405Sjkim
186280297Sjkim/*
187280297Sjkim * Entropy gatherer: use standard OpenSSL PRNG to seed (this will gather
188340704Sjkim * entropy internally through RAND_poll()).
189238405Sjkim */
190238405Sjkim
191238405Sjkimstatic size_t drbg_get_entropy(DRBG_CTX *ctx, unsigned char **pout,
192280297Sjkim                               int entropy, size_t min_len, size_t max_len)
193280297Sjkim{
194280297Sjkim    /* Round up request to multiple of block size */
195280297Sjkim    min_len = ((min_len + 19) / 20) * 20;
196280297Sjkim    *pout = OPENSSL_malloc(min_len);
197280297Sjkim    if (!*pout)
198280297Sjkim        return 0;
199340704Sjkim
200340704Sjkim    /* Enforces a reseed of the SSLEAY PRNG before generating random bytes */
201340704Sjkim    if (ssleay_rand_bytes_from_system(*pout, min_len) <= 0) {
202340704Sjkim        OPENSSL_free(*pout);
203340704Sjkim        *pout = NULL;
204340704Sjkim        return 0;
205340704Sjkim    }
206340704Sjkim    return min_len;
207340704Sjkim}
208340704Sjkim
209340704Sjkimstatic size_t drbg_get_nonce(DRBG_CTX *ctx, unsigned char **pout,
210340704Sjkim                               int entropy, size_t min_len, size_t max_len)
211340704Sjkim{
212340704Sjkim    /* Round up request to multiple of block size */
213340704Sjkim    min_len = ((min_len + 19) / 20) * 20;
214340704Sjkim    *pout = OPENSSL_malloc(min_len);
215340704Sjkim    if (!*pout)
216340704Sjkim        return 0;
217280297Sjkim    if (ssleay_rand_bytes(*pout, min_len, 0, 0) <= 0) {
218280297Sjkim        OPENSSL_free(*pout);
219280297Sjkim        *pout = NULL;
220280297Sjkim        return 0;
221280297Sjkim    }
222280297Sjkim    return min_len;
223280297Sjkim}
224238405Sjkim
225238405Sjkimstatic void drbg_free_entropy(DRBG_CTX *ctx, unsigned char *out, size_t olen)
226280297Sjkim{
227280297Sjkim    if (out) {
228280297Sjkim        OPENSSL_cleanse(out, olen);
229280297Sjkim        OPENSSL_free(out);
230280297Sjkim    }
231280297Sjkim}
232238405Sjkim
233280297Sjkim/*
234280297Sjkim * Set "additional input" when generating random data. This uses the current
235280297Sjkim * PID, a time value and a counter.
236238405Sjkim */
237238405Sjkim
238238405Sjkimstatic size_t drbg_get_adin(DRBG_CTX *ctx, unsigned char **pout)
239280297Sjkim{
240280297Sjkim    /* Use of static variables is OK as this happens under a lock */
241280297Sjkim    static unsigned char buf[16];
242280297Sjkim    static unsigned long counter;
243280297Sjkim    FIPS_get_timevec(buf, &counter);
244280297Sjkim    *pout = buf;
245280297Sjkim    return sizeof(buf);
246280297Sjkim}
247238405Sjkim
248280297Sjkim/*
249280297Sjkim * RAND_add() and RAND_seed() pass through to OpenSSL PRNG so it is
250238405Sjkim * correctly seeded by RAND_poll().
251238405Sjkim */
252238405Sjkim
253238405Sjkimstatic int drbg_rand_add(DRBG_CTX *ctx, const void *in, int inlen,
254280297Sjkim                         double entropy)
255280297Sjkim{
256280297Sjkim    RAND_SSLeay()->add(in, inlen, entropy);
257280297Sjkim    return 1;
258280297Sjkim}
259238405Sjkim
260238405Sjkimstatic int drbg_rand_seed(DRBG_CTX *ctx, const void *in, int inlen)
261280297Sjkim{
262280297Sjkim    RAND_SSLeay()->seed(in, inlen);
263280297Sjkim    return 1;
264280297Sjkim}
265238405Sjkim
266280297Sjkim# ifndef OPENSSL_DRBG_DEFAULT_TYPE
267280297Sjkim#  define OPENSSL_DRBG_DEFAULT_TYPE       NID_aes_256_ctr
268280297Sjkim# endif
269280297Sjkim# ifndef OPENSSL_DRBG_DEFAULT_FLAGS
270280297Sjkim#  define OPENSSL_DRBG_DEFAULT_FLAGS      DRBG_FLAG_CTR_USE_DF
271280297Sjkim# endif
272238405Sjkim
273238405Sjkimstatic int fips_drbg_type = OPENSSL_DRBG_DEFAULT_TYPE;
274238405Sjkimstatic int fips_drbg_flags = OPENSSL_DRBG_DEFAULT_FLAGS;
275238405Sjkim
276238405Sjkimvoid RAND_set_fips_drbg_type(int type, int flags)
277280297Sjkim{
278280297Sjkim    fips_drbg_type = type;
279280297Sjkim    fips_drbg_flags = flags;
280280297Sjkim}
281238405Sjkim
282238405Sjkimint RAND_init_fips(void)
283280297Sjkim{
284280297Sjkim    DRBG_CTX *dctx;
285280297Sjkim    size_t plen;
286280297Sjkim    unsigned char pers[32], *p;
287280297Sjkim# ifndef OPENSSL_ALLOW_DUAL_EC_DRBG
288280297Sjkim    if (fips_drbg_type >> 16) {
289280297Sjkim        RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_DUAL_EC_DRBG_DISABLED);
290280297Sjkim        return 0;
291280297Sjkim    }
292280297Sjkim# endif
293238405Sjkim
294280297Sjkim    dctx = FIPS_get_default_drbg();
295280297Sjkim    if (FIPS_drbg_init(dctx, fips_drbg_type, fips_drbg_flags) <= 0) {
296280297Sjkim        RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INITIALISING_DRBG);
297280297Sjkim        return 0;
298280297Sjkim    }
299238405Sjkim
300280297Sjkim    FIPS_drbg_set_callbacks(dctx,
301280297Sjkim                            drbg_get_entropy, drbg_free_entropy, 20,
302340704Sjkim                            drbg_get_nonce, drbg_free_entropy);
303280297Sjkim    FIPS_drbg_set_rand_callbacks(dctx, drbg_get_adin, 0,
304280297Sjkim                                 drbg_rand_seed, drbg_rand_add);
305280297Sjkim    /* Personalisation string: a string followed by date time vector */
306280297Sjkim    strcpy((char *)pers, "OpenSSL DRBG2.0");
307280297Sjkim    plen = drbg_get_adin(dctx, &p);
308280297Sjkim    memcpy(pers + 16, p, plen);
309280297Sjkim
310280297Sjkim    if (FIPS_drbg_instantiate(dctx, pers, sizeof(pers)) <= 0) {
311280297Sjkim        RANDerr(RAND_F_RAND_INIT_FIPS, RAND_R_ERROR_INSTANTIATING_DRBG);
312280297Sjkim        return 0;
313280297Sjkim    }
314280297Sjkim    FIPS_rand_set_method(FIPS_drbg_method());
315280297Sjkim    return 1;
316280297Sjkim}
317280297Sjkim
318238405Sjkim#endif
319