Coverage Report

Created: 2025-06-13 06:58

/src/openssl31/providers/implementations/rands/crngt.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019-2022 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 "crypto/rand_pool.h"
24
#include "drbg_local.h"
25
#include "prov/seeding.h"
26
#include "crypto/context.h"
27
28
typedef struct crng_test_global_st {
29
    unsigned char crngt_prev[EVP_MAX_MD_SIZE];
30
    EVP_MD *md;
31
    int preloaded;
32
    CRYPTO_RWLOCK *lock;
33
} CRNG_TEST_GLOBAL;
34
35
static int crngt_get_entropy(PROV_CTX *provctx, const EVP_MD *digest,
36
                             unsigned char *buf, unsigned char *md,
37
                             unsigned int *md_size)
38
0
{
39
0
    int r;
40
0
    size_t n;
41
0
    unsigned char *p;
42
43
0
    n = ossl_prov_get_entropy(provctx, &p, 0, CRNGT_BUFSIZ, CRNGT_BUFSIZ);
44
0
    if (n == CRNGT_BUFSIZ) {
45
0
        r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, digest, NULL);
46
0
        if (r != 0)
47
0
            memcpy(buf, p, CRNGT_BUFSIZ);
48
0
        ossl_prov_cleanup_entropy(provctx, p, n);
49
0
        return r != 0;
50
0
    }
51
0
    if (n != 0)
52
0
        ossl_prov_cleanup_entropy(provctx, p, n);
53
0
    return 0;
54
0
}
55
56
void ossl_rand_crng_ctx_free(void *vcrngt_glob)
57
0
{
58
0
    CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob;
59
60
0
    CRYPTO_THREAD_lock_free(crngt_glob->lock);
61
0
    EVP_MD_free(crngt_glob->md);
62
0
    OPENSSL_free(crngt_glob);
63
0
}
64
65
void *ossl_rand_crng_ctx_new(OSSL_LIB_CTX *ctx)
66
0
{
67
0
    CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob));
68
69
0
    if (crngt_glob == NULL)
70
0
        return NULL;
71
72
0
    if ((crngt_glob->md = EVP_MD_fetch(ctx, "SHA256", "")) == NULL) {
73
0
        OPENSSL_free(crngt_glob);
74
0
        return NULL;
75
0
    }
76
77
0
    if ((crngt_glob->lock = CRYPTO_THREAD_lock_new()) == NULL) {
78
0
        EVP_MD_free(crngt_glob->md);
79
0
        OPENSSL_free(crngt_glob);
80
0
        return NULL;
81
0
    }
82
83
0
    return crngt_glob;
84
0
}
85
86
static int prov_crngt_compare_previous(const unsigned char *prev,
87
                                       const unsigned char *cur,
88
                                       size_t sz)
89
0
{
90
0
    const int res = memcmp(prev, cur, sz) != 0;
91
92
0
    if (!res)
93
0
        ossl_set_error_state(OSSL_SELF_TEST_TYPE_CRNG);
94
0
    return res;
95
0
}
96
97
size_t ossl_crngt_get_entropy(PROV_DRBG *drbg,
98
                              unsigned char **pout,
99
                              int entropy, size_t min_len, size_t max_len,
100
                              int prediction_resistance)
101
0
{
102
0
    unsigned char md[EVP_MAX_MD_SIZE];
103
0
    unsigned char buf[CRNGT_BUFSIZ];
104
0
    unsigned char *ent, *entp, *entbuf;
105
0
    unsigned int sz;
106
0
    size_t bytes_needed;
107
0
    size_t r = 0, s, t;
108
0
    int crng_test_pass = 1;
109
0
    OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(drbg->provctx);
110
0
    CRNG_TEST_GLOBAL *crngt_glob
111
0
        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_RAND_CRNGT_INDEX);
112
0
    OSSL_CALLBACK *stcb = NULL;
113
0
    void *stcbarg = NULL;
114
0
    OSSL_SELF_TEST *st = NULL;
115
116
0
    if (crngt_glob == NULL)
117
0
        return 0;
118
119
0
    if (!CRYPTO_THREAD_write_lock(crngt_glob->lock))
120
0
        return 0;
121
122
0
    if (!crngt_glob->preloaded) {
123
0
        if (!crngt_get_entropy(drbg->provctx, crngt_glob->md, buf,
124
0
                               crngt_glob->crngt_prev, NULL)) {
125
0
            OPENSSL_cleanse(buf, sizeof(buf));
126
0
            goto unlock_return;
127
0
        }
128
0
        crngt_glob->preloaded = 1;
129
0
    }
130
131
    /*
132
     * Calculate how many bytes of seed material we require, rounded up
133
     * to the nearest byte.  If the entropy is of less than full quality,
134
     * the amount required should be scaled up appropriately here.
135
     */
136
0
    bytes_needed = (entropy + 7) / 8;
137
0
    if (bytes_needed < min_len)
138
0
        bytes_needed = min_len;
139
0
    if (bytes_needed > max_len)
140
0
        goto unlock_return;
141
0
    entp = ent = OPENSSL_secure_malloc(bytes_needed);
142
0
    if (ent == NULL)
143
0
        goto unlock_return;
144
145
0
    OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg);
146
0
    if (stcb != NULL) {
147
0
        st = OSSL_SELF_TEST_new(stcb, stcbarg);
148
0
        if (st == NULL)
149
0
            goto err;
150
0
        OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_CRNG,
151
0
                               OSSL_SELF_TEST_DESC_RNG);
152
0
    }
153
154
0
    for (t = bytes_needed; t > 0;) {
155
        /* Care needs to be taken to avoid overrunning the buffer */
156
0
        s = t >= CRNGT_BUFSIZ ? CRNGT_BUFSIZ : t;
157
0
        entbuf = t >= CRNGT_BUFSIZ ? entp : buf;
158
0
        if (!crngt_get_entropy(drbg->provctx, crngt_glob->md, entbuf, md, &sz))
159
0
            goto err;
160
0
        if (t < CRNGT_BUFSIZ)
161
0
            memcpy(entp, buf, t);
162
        /* Force a failure here if the callback returns 1 */
163
0
        if (OSSL_SELF_TEST_oncorrupt_byte(st, md))
164
0
            memcpy(md, crngt_glob->crngt_prev, sz);
165
0
        if (!prov_crngt_compare_previous(crngt_glob->crngt_prev, md, sz)) {
166
0
            crng_test_pass = 0;
167
0
            goto err;
168
0
        }
169
        /* Update for next block */
170
0
        memcpy(crngt_glob->crngt_prev, md, sz);
171
0
        entp += s;
172
0
        t -= s;
173
0
    }
174
0
    r = bytes_needed;
175
0
    *pout = ent;
176
0
    ent = NULL;
177
178
0
 err:
179
0
    OSSL_SELF_TEST_onend(st, crng_test_pass);
180
0
    OSSL_SELF_TEST_free(st);
181
0
    OPENSSL_secure_clear_free(ent, bytes_needed);
182
183
0
 unlock_return:
184
0
    CRYPTO_THREAD_unlock(crngt_glob->lock);
185
0
    return r;
186
0
}
187
188
void ossl_crngt_cleanup_entropy(ossl_unused PROV_DRBG *drbg,
189
                                unsigned char *out, size_t outlen)
190
0
{
191
0
    OPENSSL_secure_clear_free(out, outlen);
192
0
}