950cc629d73ed042794ca19ad051e923f6d68a05
[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 "crypto/rand.h"
18 #include "internal/thread_once.h"
19 #include "internal/cryptlib.h"
20 #include "rand_local.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 *, RAND_POOL *, unsigned char *,
28                          unsigned char *, 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, 1, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) {
49         OPENSSL_free(crngt_glob);
50         return NULL;
51     }
52     if (crngt_get_entropy(ctx, crngt_glob->crngt_pool, buf,
53                           crngt_glob->crngt_prev, NULL)) {
54         OPENSSL_cleanse(buf, sizeof(buf));
55         return crngt_glob;
56     }
57     rand_pool_free(crngt_glob->crngt_pool);
58     OPENSSL_free(crngt_glob);
59     return NULL;
60 }
61
62 static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = {
63     rand_crng_ossl_ctx_new,
64     rand_crng_ossl_ctx_free,
65 };
66
67 int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx,
68                               RAND_POOL *pool,
69                               unsigned char *buf,
70                               unsigned char *md,
71                               unsigned int *md_size)
72 {
73     int r;
74     size_t n;
75     unsigned char *p;
76
77     if (pool == NULL)
78         return 0;
79
80     n = rand_pool_acquire_entropy(pool);
81     if (n >= CRNGT_BUFSIZ) {
82         EVP_MD *fmd = EVP_MD_fetch(ctx, "SHA256", "");
83         if (fmd == NULL)
84             return 0;
85         p = rand_pool_detach(pool);
86         r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, fmd, NULL);
87         if (r != 0)
88             memcpy(buf, p, CRNGT_BUFSIZ);
89         rand_pool_reattach(pool, p);
90         EVP_MD_free(fmd);
91         return r;
92     }
93     return 0;
94 }
95
96 size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
97                               unsigned char **pout,
98                               int entropy, size_t min_len, size_t max_len,
99                               int prediction_resistance)
100 {
101     unsigned char buf[CRNGT_BUFSIZ], md[EVP_MAX_MD_SIZE];
102     unsigned int sz;
103     RAND_POOL *pool;
104     size_t q, r = 0, s, t = 0;
105     int attempts = 3;
106     CRNG_TEST_GLOBAL *crngt_glob
107         = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
108                                &rand_crng_ossl_ctx_method);
109
110     if (crngt_glob == NULL)
111         return 0;
112
113     if ((pool = rand_pool_new(entropy, 1, min_len, max_len)) == NULL)
114         return 0;
115
116     while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) {
117         s = q > sizeof(buf) ? sizeof(buf) : q;
118         if (!crngt_get_entropy(drbg->libctx, crngt_glob->crngt_pool, buf, md,
119                                &sz)
120             || memcmp(crngt_glob->crngt_prev, md, sz) == 0
121             || !rand_pool_add(pool, buf, s, s * 8))
122             goto err;
123         memcpy(crngt_glob->crngt_prev, md, sz);
124         t += s;
125         attempts++;
126     }
127     r = t;
128     *pout = rand_pool_detach(pool);
129 err:
130     OPENSSL_cleanse(buf, sizeof(buf));
131     rand_pool_free(pool);
132     return r;
133 }
134
135 void rand_crngt_cleanup_entropy(RAND_DRBG *drbg,
136                                 unsigned char *out, size_t outlen)
137 {
138     OPENSSL_secure_clear_free(out, outlen);
139 }