Start to overhaul RAND API
[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 }
53
54 int RAND_set_rand_method(const RAND_METHOD *meth)
55 {
56     if (!RUN_ONCE(&rand_init, do_rand_init))
57         return 0;
58
59     CRYPTO_THREAD_write_lock(rand_meth_lock);
60 #ifndef OPENSSL_NO_ENGINE
61     ENGINE_finish(funct_ref);
62     funct_ref = NULL;
63 #endif
64     default_RAND_meth = meth;
65     CRYPTO_THREAD_unlock(rand_meth_lock);
66     return 1;
67 }
68
69 const RAND_METHOD *RAND_get_rand_method(void)
70 {
71     const RAND_METHOD *tmp_meth = NULL;
72
73     if (!RUN_ONCE(&rand_init, do_rand_init))
74         return NULL;
75
76     CRYPTO_THREAD_write_lock(rand_meth_lock);
77     if (default_RAND_meth == NULL) {
78 #ifndef OPENSSL_NO_ENGINE
79         ENGINE *e;
80
81         /* If we have an engine that can do RAND, use it. */
82         if ((e = ENGINE_get_default_RAND()) != NULL
83                 && (tmp_meth = ENGINE_get_RAND(e)) != NULL) {
84             funct_ref = e;
85             default_RAND_meth = tmp_meth;
86         } else {
87             ENGINE_finish(e);
88             default_RAND_meth = &openssl_rand_meth;
89         }
90 #else
91         default_RAND_meth = &openssl_rand_meth;
92 #endif
93     }
94     tmp_meth = default_RAND_meth;
95     CRYPTO_THREAD_unlock(rand_meth_lock);
96     return tmp_meth;
97 }
98
99 #ifndef OPENSSL_NO_ENGINE
100 int RAND_set_rand_engine(ENGINE *engine)
101 {
102     const RAND_METHOD *tmp_meth = NULL;
103
104     if (!RUN_ONCE(&rand_init, do_rand_init))
105         return 0;
106
107     if (engine != NULL) {
108         if (!ENGINE_init(engine))
109             return 0;
110         tmp_meth = ENGINE_get_RAND(engine);
111         if (tmp_meth == NULL) {
112             ENGINE_finish(engine);
113             return 0;
114         }
115     }
116     CRYPTO_THREAD_write_lock(rand_engine_lock);
117     /* This function releases any prior ENGINE so call it first */
118     RAND_set_rand_method(tmp_meth);
119     funct_ref = engine;
120     CRYPTO_THREAD_unlock(rand_engine_lock);
121     return 1;
122 }
123 #endif
124
125 void RAND_seed(const void *buf, int num)
126 {
127     const RAND_METHOD *meth = RAND_get_rand_method();
128
129     if (meth->seed != NULL)
130         meth->seed(buf, num);
131 }
132
133 void RAND_add(const void *buf, int num, double randomness)
134 {
135     const RAND_METHOD *meth = RAND_get_rand_method();
136
137     if (meth->add != NULL)
138         meth->add(buf, num, randomness);
139 }
140
141 int RAND_bytes(unsigned char *buf, int num)
142 {
143     const RAND_METHOD *meth = RAND_get_rand_method();
144
145     if (meth->bytes != NULL)
146         return meth->bytes(buf, num);
147     RANDerr(RAND_F_RAND_BYTES, RAND_R_FUNC_NOT_IMPLEMENTED);
148     return -1;
149 }
150
151 #if OPENSSL_API_COMPAT < 0x10100000L
152 int RAND_pseudo_bytes(unsigned char *buf, int num)
153 {
154     const RAND_METHOD *meth = RAND_get_rand_method();
155
156     if (meth->pseudorand != NULL)
157         return meth->pseudorand(buf, num);
158     return -1;
159 }
160 #endif
161
162 int RAND_status(void)
163 {
164     const RAND_METHOD *meth = RAND_get_rand_method();
165
166     if (meth->status != NULL)
167         return meth->status();
168     return 0;
169 }