2 * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
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
12 * Implementation of the FIPS 140-2 section 4.9.2 Conditional Tests.
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"
27 typedef struct crng_test_global_st
{
28 unsigned char crngt_prev
[EVP_MAX_MD_SIZE
];
29 RAND_POOL
*crngt_pool
;
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
)
44 n
= prov_pool_acquire_entropy(pool
);
45 if (n
>= CRNGT_BUFSIZ
) {
46 fmd
= EVP_MD_fetch(ctx
, "SHA256", "");
49 p
= rand_pool_detach(pool
);
50 r
= EVP_Digest(p
, CRNGT_BUFSIZ
, md
, md_size
, fmd
, NULL
);
52 memcpy(buf
, p
, CRNGT_BUFSIZ
);
53 rand_pool_reattach(pool
, p
);
60 static void rand_crng_ossl_ctx_free(void *vcrngt_glob
)
62 CRNG_TEST_GLOBAL
*crngt_glob
= vcrngt_glob
;
64 rand_pool_free(crngt_glob
->crngt_pool
);
65 OPENSSL_free(crngt_glob
);
68 static void *rand_crng_ossl_ctx_new(OSSL_LIB_CTX
*ctx
)
70 unsigned char buf
[CRNGT_BUFSIZ
];
71 CRNG_TEST_GLOBAL
*crngt_glob
= OPENSSL_zalloc(sizeof(*crngt_glob
));
73 if (crngt_glob
== NULL
)
76 if ((crngt_glob
->crngt_pool
77 = rand_pool_new(0, 1, CRNGT_BUFSIZ
, CRNGT_BUFSIZ
)) == NULL
) {
78 OPENSSL_free(crngt_glob
);
81 if (crngt_get_entropy(ctx
, crngt_glob
->crngt_pool
, buf
,
82 crngt_glob
->crngt_prev
, NULL
)) {
83 OPENSSL_cleanse(buf
, sizeof(buf
));
86 rand_pool_free(crngt_glob
->crngt_pool
);
87 OPENSSL_free(crngt_glob
);
91 static const OSSL_LIB_CTX_METHOD rand_crng_ossl_ctx_method
= {
92 rand_crng_ossl_ctx_new
,
93 rand_crng_ossl_ctx_free
,
96 static int prov_crngt_compare_previous(const unsigned char *prev
,
97 const unsigned char *cur
,
100 const int res
= memcmp(prev
, cur
, sz
) != 0;
103 ossl_set_error_state(OSSL_SELF_TEST_TYPE_CRNG
);
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
)
112 unsigned char buf
[CRNGT_BUFSIZ
], md
[EVP_MAX_MD_SIZE
];
115 size_t q
, r
= 0, s
, t
= 0;
116 int attempts
= 3, crng_test_pass
= 1;
117 OSSL_LIB_CTX
*libctx
= PROV_LIBRARY_CONTEXT_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
;
125 if (crngt_glob
== NULL
)
128 if ((pool
= rand_pool_new(entropy
, 1, min_len
, max_len
)) == NULL
)
131 OSSL_SELF_TEST_get_callback(libctx
, &stcb
, &stcbarg
);
133 st
= OSSL_SELF_TEST_new(stcb
, stcbarg
);
136 OSSL_SELF_TEST_onbegin(st
, OSSL_SELF_TEST_TYPE_CRNG
,
137 OSSL_SELF_TEST_DESC_RNG
);
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
))
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
)) {
151 if (!rand_pool_add(pool
, buf
, s
, s
* 8))
153 memcpy(crngt_glob
->crngt_prev
, md
, sz
);
158 *pout
= rand_pool_detach(pool
);
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
);
167 void prov_crngt_cleanup_entropy(PROV_DRBG
*drbg
,
168 unsigned char *out
, size_t outlen
)
170 OPENSSL_secure_clear_free(out
, outlen
);