Add DRBG random method
[openssl.git] / crypto / rand / rand_lib.c
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11 #include <time.h>
12 #include "internal/cryptlib.h"
13 #include <openssl/opensslconf.h>
14 #include "internal/rand.h"
15 #include <openssl/engine.h>
16 #include "internal/thread_once.h"
17 #include "rand_lcl.h"
18
19 #ifndef OPENSSL_NO_ENGINE
20 /* non-NULL if default_RAND_meth is ENGINE-provided */
21 static ENGINE *funct_ref;
22 static CRYPTO_RWLOCK *rand_engine_lock;
23 #endif
24 static CRYPTO_RWLOCK *rand_meth_lock;
25 static const RAND_METHOD *default_RAND_meth;
26 static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
27
28
29 DEFINE_RUN_ONCE_STATIC(do_rand_init)
30 {
31     int ret = 1;
32 #ifndef OPENSSL_NO_ENGINE
33     rand_engine_lock = CRYPTO_THREAD_lock_new();
34     ret &= rand_engine_lock != NULL;
35 #endif
36     rand_meth_lock = CRYPTO_THREAD_lock_new();
37     ret &= rand_meth_lock != NULL;
38     return ret;
39 }
40
41 void rand_cleanup_int(void)
42 {
43     const RAND_METHOD *meth = default_RAND_meth;
44
45     if (meth != NULL && meth->cleanup != NULL)
46         meth->cleanup();
47     RAND_set_rand_method(NULL);
48 #ifndef OPENSSL_NO_ENGINE
49     CRYPTO_THREAD_lock_free(rand_engine_lock);
50 #endif
51     CRYPTO_THREAD_lock_free(rand_meth_lock);
52     rand_drbg_cleanup();
53 }
54
55 int RAND_set_rand_method(const RAND_METHOD *meth)
56 {
57     if (!RUN_ONCE(&rand_init, do_rand_init))
58         return 0;
59
60     CRYPTO_THREAD_write_lock(rand_meth_lock);
61 #ifndef OPENSSL_NO_ENGINE
62     ENGINE_finish(funct_ref);
63     funct_ref = NULL;
64 #endif
65     default_RAND_meth = meth;
66     CRYPTO_THREAD_unlock(rand_meth_lock);
67     return 1;
68 }
69
70 const RAND_METHOD *RAND_get_rand_method(void)
71 {
72     const RAND_METHOD *tmp_meth = NULL;
73
74     if (!RUN_ONCE(&rand_init, do_rand_init))
75         return NULL;
76
77     CRYPTO_THREAD_write_lock(rand_meth_lock);
78     if (default_RAND_meth == NULL) {
79 #ifndef OPENSSL_NO_ENGINE
80         ENGINE *e;
81
82         /* If we have an engine that can do RAND, use it. */
83         if ((e = ENGINE_get_default_RAND()) != NULL
84                 && (tmp_meth = ENGINE_get_RAND(e)) != NULL) {
85             funct_ref = e;
86             default_RAND_meth = tmp_meth;
87         } else {
88             ENGINE_finish(e);
89             default_RAND_meth = &openssl_rand_meth;
90         }
91 #else
92         default_RAND_meth = &openssl_rand_meth;
93 #endif
94     }
95     tmp_meth = default_RAND_meth;
96     CRYPTO_THREAD_unlock(rand_meth_lock);
97     return tmp_meth;
98 }
99
100 #ifndef OPENSSL_NO_ENGINE
101 int RAND_set_rand_engine(ENGINE *engine)
102 {
103     const RAND_METHOD *tmp_meth = NULL;
104
105     if (!RUN_ONCE(&rand_init, do_rand_init))
106         return 0;
107
108     if (engine != NULL) {
109         if (!ENGINE_init(engine))
110             return 0;
111         tmp_meth = ENGINE_get_RAND(engine);
112         if (tmp_meth == NULL) {
113             ENGINE_finish(engine);
114             return 0;
115         }
116     }
117     CRYPTO_THREAD_write_lock(rand_engine_lock);
118     /* This function releases any prior ENGINE so call it first */
119     RAND_set_rand_method(tmp_meth);
120     funct_ref = engine;
121     CRYPTO_THREAD_unlock(rand_engine_lock);
122     return 1;
123 }
124 #endif
125
126 void RAND_seed(const void *buf, int num)
127 {
128     const RAND_METHOD *meth = RAND_get_rand_method();
129
130     if (meth->seed != NULL)
131         meth->seed(buf, num);
132 }
133
134 void RAND_add(const void *buf, int num, double randomness)
135 {
136     const RAND_METHOD *meth = RAND_get_rand_method();
137
138     if (meth->add != NULL)
139         meth->add(buf, num, randomness);
140 }
141
142 int RAND_bytes(unsigned char *buf, int num)
143 {
144     const RAND_METHOD *meth = RAND_get_rand_method();
145
146     if (meth->bytes != NULL)
147         return meth->bytes(buf, num);
148     RANDerr(RAND_F_RAND_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED);
149     return -1;
150 }
151
152 #if OPENSSL_API_COMPAT < 0x10100000L
153 int RAND_pseudo_bytes(unsigned char *buf, int num)
154 {
155     const RAND_METHOD *meth = RAND_get_rand_method();
156
157     if (meth->pseudorand != NULL)
158         return meth->pseudorand(buf, num);
159     return -1;
160 }
161 #endif
162
163 int RAND_status(void)
164 {
165     const RAND_METHOD *meth = RAND_get_rand_method();
166
167     if (meth->status != NULL)
168         return meth->status();
169     return 0;
170 }