Rename some occurrences of 'library_context' and 'lib_ctx' to 'libctx'
[openssl.git] / providers / implementations / rands / crngt.c
1 /*
2  * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright (c) 2019, Oracle and/or its affiliates.  All rights reserved.
4  *
5  * Licensed under the Apache License 2.0 (the "License").  You may not use
6  * this file except in compliance with the License.  You can obtain a copy
7  * in the file LICENSE in the source distribution or at
8  * https://www.openssl.org/source/license.html
9  */
10
11 /*
12  * Implementation of the FIPS 140-2 section 4.9.2 Conditional Tests.
13  */
14
15 #include <string.h>
16 #include <openssl/evp.h>
17 #include <openssl/core_dispatch.h>
18 #include <openssl/params.h>
19 #include <openssl/self_test.h>
20 #include "prov/providercommon.h"
21 #include "prov/provider_ctx.h"
22 #include "internal/cryptlib.h"
23 #include "prov/rand_pool.h"
24 #include "drbg_local.h"
25 #include "prov/seeding.h"
26
27 typedef struct crng_test_global_st {
28     unsigned char crngt_prev[EVP_MAX_MD_SIZE];
29     RAND_POOL *crngt_pool;
30 } CRNG_TEST_GLOBAL;
31
32 static int crngt_get_entropy(OSSL_LIB_CTX *ctx, RAND_POOL *pool,
33                              unsigned char *buf, unsigned char *md,
34                              unsigned int *md_size)
35 {
36     int r;
37     size_t n;
38     unsigned char *p;
39     EVP_MD *fmd;
40
41     if (pool == NULL)
42         return 0;
43
44     n = prov_pool_acquire_entropy(pool);
45     if (n >= CRNGT_BUFSIZ) {
46         fmd = EVP_MD_fetch(ctx, "SHA256", "");
47         if (fmd == NULL)
48             return 0;
49         p = rand_pool_detach(pool);
50         r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, fmd, NULL);
51         if (r != 0)
52             memcpy(buf, p, CRNGT_BUFSIZ);
53         rand_pool_reattach(pool, p);
54         EVP_MD_free(fmd);
55         return r;
56     }
57     return 0;
58 }
59
60 static void rand_crng_ossl_ctx_free(void *vcrngt_glob)
61 {
62     CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob;
63
64     rand_pool_free(crngt_glob->crngt_pool);
65     OPENSSL_free(crngt_glob);
66 }
67
68 static void *rand_crng_ossl_ctx_new(OSSL_LIB_CTX *ctx)
69 {
70     unsigned char buf[CRNGT_BUFSIZ];
71     CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob));
72
73     if (crngt_glob == NULL)
74         return NULL;
75
76     if ((crngt_glob->crngt_pool
77          = rand_pool_new(0, 1, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) {
78         OPENSSL_free(crngt_glob);
79         return NULL;
80     }
81     if (crngt_get_entropy(ctx, crngt_glob->crngt_pool, buf,
82                           crngt_glob->crngt_prev, NULL)) {
83         OPENSSL_cleanse(buf, sizeof(buf));
84         return crngt_glob;
85     }
86     rand_pool_free(crngt_glob->crngt_pool);
87     OPENSSL_free(crngt_glob);
88     return NULL;
89 }
90
91 static const OSSL_LIB_CTX_METHOD rand_crng_ossl_ctx_method = {
92     rand_crng_ossl_ctx_new,
93     rand_crng_ossl_ctx_free,
94 };
95
96 static int prov_crngt_compare_previous(const unsigned char *prev,
97                                        const unsigned char *cur,
98                                        size_t sz)
99 {
100     const int res = memcmp(prev, cur, sz) != 0;
101
102     if (!res)
103         ossl_set_error_state(OSSL_SELF_TEST_TYPE_CRNG);
104     return res;
105 }
106
107 size_t prov_crngt_get_entropy(PROV_DRBG *drbg,
108                               unsigned char **pout,
109                               int entropy, size_t min_len, size_t max_len,
110                               int prediction_resistance)
111 {
112     unsigned char buf[CRNGT_BUFSIZ], md[EVP_MAX_MD_SIZE];
113     unsigned int sz;
114     RAND_POOL *pool;
115     size_t q, r = 0, s, t = 0;
116     int attempts = 3, crng_test_pass = 1;
117     OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(drbg->provctx);
118     CRNG_TEST_GLOBAL *crngt_glob
119         = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_RAND_CRNGT_INDEX,
120                                 &rand_crng_ossl_ctx_method);
121     OSSL_CALLBACK *stcb = NULL;
122     void *stcbarg = NULL;
123     OSSL_SELF_TEST *st = NULL;
124
125     if (crngt_glob == NULL)
126         return 0;
127
128     if ((pool = rand_pool_new(entropy, 1, min_len, max_len)) == NULL)
129         return 0;
130
131     OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg);
132     if (stcb != NULL) {
133         st = OSSL_SELF_TEST_new(stcb, stcbarg);
134         if (st == NULL)
135             goto err;
136         OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_CRNG,
137                                OSSL_SELF_TEST_DESC_RNG);
138     }
139
140     while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) {
141         s = q > sizeof(buf) ? sizeof(buf) : q;
142         if (!crngt_get_entropy(libctx, crngt_glob->crngt_pool, buf, md, &sz))
143             goto err;
144         /* Force a failure here if the callback returns 1 */
145         if (OSSL_SELF_TEST_oncorrupt_byte(st, md))
146             memcpy(md, crngt_glob->crngt_prev, sz);
147         if (!prov_crngt_compare_previous(crngt_glob->crngt_prev, md, sz)) {
148             crng_test_pass = 0;
149             goto err;
150         }
151         if (!rand_pool_add(pool, buf, s, s * 8))
152             goto err;
153         memcpy(crngt_glob->crngt_prev, md, sz);
154         t += s;
155         attempts++;
156     }
157     r = t;
158     *pout = rand_pool_detach(pool);
159 err:
160     OSSL_SELF_TEST_onend(st, crng_test_pass);
161     OSSL_SELF_TEST_free(st);
162     OPENSSL_cleanse(buf, sizeof(buf));
163     rand_pool_free(pool);
164     return r;
165 }
166
167 void prov_crngt_cleanup_entropy(PROV_DRBG *drbg,
168                                 unsigned char *out, size_t outlen)
169 {
170     OPENSSL_secure_clear_free(out, outlen);
171 }