1/*
2 * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (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{-
10use OpenSSL::paramnames qw(produce_param_decoder);
11-}
12
13#include <string.h>
14#include <openssl/rand.h>
15#include <openssl/core_dispatch.h>
16#include <openssl/e_os2.h>
17#include <openssl/params.h>
18#include <openssl/core_names.h>
19#include <openssl/evp.h>
20#include <openssl/err.h>
21#include <openssl/randerr.h>
22#include <openssl/proverr.h>
23#include "internal/common.h"
24#include "prov/implementations.h"
25#include "prov/provider_ctx.h"
26#include "crypto/rand.h"
27#include "crypto/rand_pool.h"
28
29static OSSL_FUNC_rand_newctx_fn seed_src_new;
30static OSSL_FUNC_rand_freectx_fn seed_src_free;
31static OSSL_FUNC_rand_instantiate_fn seed_src_instantiate;
32static OSSL_FUNC_rand_uninstantiate_fn seed_src_uninstantiate;
33static OSSL_FUNC_rand_generate_fn seed_src_generate;
34static OSSL_FUNC_rand_reseed_fn seed_src_reseed;
35static OSSL_FUNC_rand_gettable_ctx_params_fn seed_src_gettable_ctx_params;
36static OSSL_FUNC_rand_get_ctx_params_fn seed_src_get_ctx_params;
37static OSSL_FUNC_rand_verify_zeroization_fn seed_src_verify_zeroization;
38static OSSL_FUNC_rand_enable_locking_fn seed_src_enable_locking;
39static OSSL_FUNC_rand_lock_fn seed_src_lock;
40static OSSL_FUNC_rand_unlock_fn seed_src_unlock;
41static OSSL_FUNC_rand_get_seed_fn seed_get_seed;
42static OSSL_FUNC_rand_clear_seed_fn seed_clear_seed;
43
44typedef struct {
45    void *provctx;
46    int state;
47} PROV_SEED_SRC;
48
49static void *seed_src_new(void *provctx, void *parent,
50                          const OSSL_DISPATCH *parent_dispatch)
51{
52    PROV_SEED_SRC *s;
53
54    if (parent != NULL) {
55        ERR_raise(ERR_LIB_PROV, PROV_R_SEED_SOURCES_MUST_NOT_HAVE_A_PARENT);
56        return NULL;
57    }
58
59    s = OPENSSL_zalloc(sizeof(*s));
60    if (s == NULL)
61        return NULL;
62
63    s->provctx = provctx;
64    s->state = EVP_RAND_STATE_UNINITIALISED;
65    return s;
66}
67
68static void seed_src_free(void *vseed)
69{
70    OPENSSL_free(vseed);
71}
72
73static int seed_src_instantiate(void *vseed, unsigned int strength,
74                                int prediction_resistance,
75                                const unsigned char *pstr, size_t pstr_len,
76                                ossl_unused const OSSL_PARAM params[])
77{
78    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
79
80    s->state = EVP_RAND_STATE_READY;
81    return 1;
82}
83
84static int seed_src_uninstantiate(void *vseed)
85{
86    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
87
88    s->state = EVP_RAND_STATE_UNINITIALISED;
89    return 1;
90}
91
92static int seed_src_generate(void *vseed, unsigned char *out, size_t outlen,
93                             unsigned int strength,
94                             ossl_unused int prediction_resistance,
95                             const unsigned char *adin,
96                             size_t adin_len)
97{
98    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
99    size_t entropy_available;
100    RAND_POOL *pool;
101
102    if (s->state != EVP_RAND_STATE_READY) {
103        ERR_raise(ERR_LIB_PROV,
104                  s->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE
105                                                   : PROV_R_NOT_INSTANTIATED);
106        return 0;
107    }
108
109    pool = ossl_rand_pool_new(strength, 1, outlen, outlen);
110    if (pool == NULL) {
111        ERR_raise(ERR_LIB_PROV, ERR_R_RAND_LIB);
112        return 0;
113    }
114
115    /* Get entropy by polling system entropy sources. */
116    entropy_available = ossl_pool_acquire_entropy(pool);
117
118    if (entropy_available > 0) {
119        if (!ossl_rand_pool_adin_mix_in(pool, adin, adin_len)) {
120            ossl_rand_pool_free(pool);
121            return 0;
122        }
123        memcpy(out, ossl_rand_pool_buffer(pool), ossl_rand_pool_length(pool));
124    }
125
126    ossl_rand_pool_free(pool);
127    return entropy_available > 0;
128}
129
130static int seed_src_reseed(void *vseed,
131                           ossl_unused int prediction_resistance,
132                           ossl_unused const unsigned char *ent,
133                           ossl_unused size_t ent_len,
134                           ossl_unused const unsigned char *adin,
135                           ossl_unused size_t adin_len)
136{
137    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
138
139    if (s->state != EVP_RAND_STATE_READY) {
140        ERR_raise(ERR_LIB_PROV,
141                  s->state == EVP_RAND_STATE_ERROR ? PROV_R_IN_ERROR_STATE
142                                                   : PROV_R_NOT_INSTANTIATED);
143        return 0;
144    }
145    return 1;
146}
147
148{- produce_param_decoder('seed_src_get_ctx_params',
149                         (['RAND_PARAM_STATE',                   'state',  'int'],
150                          ['RAND_PARAM_STRENGTH',                'str',    'uint'],
151                          ['RAND_PARAM_MAX_REQUEST',             'maxreq', 'size_t'],
152                        )); -}
153
154static int seed_src_get_ctx_params(void *vseed, OSSL_PARAM params[])
155{
156    PROV_SEED_SRC *s = (PROV_SEED_SRC *)vseed;
157    struct seed_src_get_ctx_params_st p;
158
159    if (s == NULL || !seed_src_get_ctx_params_decoder(params, &p))
160        return 0;
161
162    if (p.state != NULL && !OSSL_PARAM_set_int(p.state, s->state))
163        return 0;
164
165    if (p.str != NULL && !OSSL_PARAM_set_uint(p.str, 1024))
166        return 0;
167
168    if (p.maxreq != NULL && !OSSL_PARAM_set_size_t(p.maxreq, 128))
169        return 0;
170    return 1;
171}
172
173static const OSSL_PARAM *seed_src_gettable_ctx_params(ossl_unused void *vseed,
174                                                      ossl_unused void *provctx)
175{
176    return seed_src_get_ctx_params_list;
177}
178
179static int seed_src_verify_zeroization(ossl_unused void *vseed)
180{
181    return 1;
182}
183
184static size_t seed_get_seed(void *vseed, unsigned char **pout,
185                            int entropy, size_t min_len, size_t max_len,
186                            int prediction_resistance,
187                            const unsigned char *adin, size_t adin_len)
188{
189    size_t ret = 0;
190    size_t entropy_available = 0;
191    RAND_POOL *pool;
192
193    pool = ossl_rand_pool_new(entropy, 1, min_len, max_len);
194    if (pool == NULL) {
195        ERR_raise(ERR_LIB_PROV, ERR_R_RAND_LIB);
196        return 0;
197    }
198
199    /* Get entropy by polling system entropy sources. */
200    entropy_available = ossl_pool_acquire_entropy(pool);
201
202    if (entropy_available > 0
203        && ossl_rand_pool_adin_mix_in(pool, adin, adin_len)) {
204        ret = ossl_rand_pool_length(pool);
205        *pout = ossl_rand_pool_detach(pool);
206    } else {
207        ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK);
208    }
209    ossl_rand_pool_free(pool);
210    return ret;
211}
212
213static void seed_clear_seed(ossl_unused void *vdrbg,
214                            unsigned char *out, size_t outlen)
215{
216    OPENSSL_secure_clear_free(out, outlen);
217}
218
219static int seed_src_enable_locking(ossl_unused void *vseed)
220{
221    return 1;
222}
223
224int seed_src_lock(ossl_unused void *vctx)
225{
226    return 1;
227}
228
229void seed_src_unlock(ossl_unused void *vctx)
230{
231}
232
233const OSSL_DISPATCH ossl_seed_src_functions[] = {
234    { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))seed_src_new },
235    { OSSL_FUNC_RAND_FREECTX, (void(*)(void))seed_src_free },
236    { OSSL_FUNC_RAND_INSTANTIATE,
237      (void(*)(void))seed_src_instantiate },
238    { OSSL_FUNC_RAND_UNINSTANTIATE,
239      (void(*)(void))seed_src_uninstantiate },
240    { OSSL_FUNC_RAND_GENERATE, (void(*)(void))seed_src_generate },
241    { OSSL_FUNC_RAND_RESEED, (void(*)(void))seed_src_reseed },
242    { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))seed_src_enable_locking },
243    { OSSL_FUNC_RAND_LOCK, (void(*)(void))seed_src_lock },
244    { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))seed_src_unlock },
245    { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,
246      (void(*)(void))seed_src_gettable_ctx_params },
247    { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))seed_src_get_ctx_params },
248    { OSSL_FUNC_RAND_VERIFY_ZEROIZATION,
249      (void(*)(void))seed_src_verify_zeroization },
250    { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))seed_get_seed },
251    { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))seed_clear_seed },
252    OSSL_DISPATCH_END
253};
254