Make the rand_crng code OPENSSL_CTX aware
[openssl.git] / crypto / rand / rand_crng_test.c
1 /*
2  * Copyright 2019 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 "internal/rand_int.h"
18 #include "internal/thread_once.h"
19 #include "internal/cryptlib.h"
20 #include "rand_lcl.h"
21
22 typedef struct crng_test_global_st {
23     unsigned char crngt_prev[EVP_MAX_MD_SIZE];
24     RAND_POOL *crngt_pool;
25 } CRNG_TEST_GLOBAL;
26
27 int (*crngt_get_entropy)(OPENSSL_CTX *, unsigned char *, unsigned char *,
28                          unsigned int *)
29     = &rand_crngt_get_entropy_cb;
30
31 static void rand_crng_ossl_ctx_free(void *vcrngt_glob)
32 {
33     CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob;
34
35     rand_pool_free(crngt_glob->crngt_pool);
36     OPENSSL_free(crngt_glob);
37 }
38
39 static void *rand_crng_ossl_ctx_new(OPENSSL_CTX *ctx)
40 {
41     unsigned char buf[CRNGT_BUFSIZ];
42     CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob));
43
44     if (crngt_glob == NULL)
45         return NULL;
46
47     if ((crngt_glob->crngt_pool
48          = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) {
49         OPENSSL_free(crngt_glob);
50         return NULL;
51     }
52     if (crngt_get_entropy(ctx, buf, crngt_glob->crngt_prev, NULL)) {
53         OPENSSL_cleanse(buf, sizeof(buf));
54         return crngt_glob;
55     }
56     rand_pool_free(crngt_glob->crngt_pool);
57     OPENSSL_free(crngt_glob);
58     return NULL;
59 }
60
61 static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = {
62     rand_crng_ossl_ctx_new,
63     rand_crng_ossl_ctx_free,
64 };
65
66 int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx,
67                               unsigned char *buf,
68                               unsigned char *md,
69                               unsigned int *md_size)
70 {
71     int r;
72     size_t n;
73     unsigned char *p;
74     CRNG_TEST_GLOBAL *crngt_glob
75         = openssl_ctx_get_data(ctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
76                                &rand_crng_ossl_ctx_method);
77
78     if (crngt_glob == NULL)
79         return 0;
80
81     n = rand_pool_acquire_entropy(crngt_glob->crngt_pool);
82     if (n >= CRNGT_BUFSIZ) {
83         p = rand_pool_detach(crngt_glob->crngt_pool);
84         r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, EVP_sha256(), NULL);
85         if (r != 0)
86             memcpy(buf, p, CRNGT_BUFSIZ);
87         rand_pool_reattach(crngt_glob->crngt_pool, p);
88         return r;
89     }
90     return 0;
91 }
92
93 size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
94                               unsigned char **pout,
95                               int entropy, size_t min_len, size_t max_len,
96                               int prediction_resistance)
97 {
98     unsigned char buf[CRNGT_BUFSIZ], md[EVP_MAX_MD_SIZE];
99     unsigned int sz;
100     RAND_POOL *pool;
101     size_t q, r = 0, s, t = 0;
102     int attempts = 3;
103     CRNG_TEST_GLOBAL *crngt_glob
104         = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
105                                &rand_crng_ossl_ctx_method);
106
107     if (crngt_glob == NULL)
108         return 0;
109
110     if ((pool = rand_pool_new(entropy, min_len, max_len)) == NULL)
111         return 0;
112
113     while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) {
114         s = q > sizeof(buf) ? sizeof(buf) : q;
115         if (!crngt_get_entropy(drbg->libctx, buf, md, &sz)
116             || memcmp(crngt_glob->crngt_prev, md, sz) == 0
117             || !rand_pool_add(pool, buf, s, s * 8))
118             goto err;
119         memcpy(crngt_glob->crngt_prev, md, sz);
120         t += s;
121         attempts++;
122     }
123     r = t;
124     *pout = rand_pool_detach(pool);
125 err:
126     OPENSSL_cleanse(buf, sizeof(buf));
127     rand_pool_free(pool);
128     return r;
129 }
130
131 void rand_crngt_cleanup_entropy(RAND_DRBG *drbg,
132                                 unsigned char *out, size_t outlen)
133 {
134     OPENSSL_secure_clear_free(out, outlen);
135 }