Coverage Report

Created: 2026-02-22 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/providers/implementations/digests/cshake_prov.c
Line
Count
Source
1
/*
2
 * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
/* including crypto/sha.h requires this for SHA256_CTX */
11
#include "internal/deprecated.h"
12
/*
13
 * NOTE: By default CSHAKE sets secure xof lengths (OSSL_DIGEST_PARAM_XOFLEN)
14
 * that are used by EVP_DigestFinal_ex(). This differs from SHAKE where the
15
 * xof length MUST be set (since the initial implementation shipped with BAD
16
 * defaults - and the only safe way to fix it was to make the user set the value)
17
 */
18
#include <string.h>
19
#include <openssl/evp.h>
20
#include <openssl/err.h>
21
#include <openssl/proverr.h>
22
#include <openssl/core_names.h>
23
#include "crypto/sha.h"
24
#include "prov/provider_ctx.h"
25
#include "prov/digestcommon.h"
26
#include "prov/implementations.h"
27
#include "internal/common.h"
28
#include "internal/sha3.h"
29
#include "providers/implementations/digests/cshake_prov.inc"
30
31
/*
32
 * Length encoding will be a 1 byte size + length in bits (3 bytes max)
33
 * This gives a range of 0..0XFFFFFF bits = 2097151 bytes).
34
 */
35
#define CSHAKE_MAX_ENCODED_HEADER_LEN (1 + 3)
36
37
/*
38
 * Restrict the maximum length of the custom strings N & S.
39
 * This must not exceed 64 bits = 8k bytes.
40
 */
41
0
#define CSHAKE_MAX_STRING 512
42
43
/* Maximum size of both the encoded strings (N and S) */
44
#define CSHAKE_MAX_ENCODED_STRING (CSHAKE_MAX_STRING + CSHAKE_MAX_ENCODED_HEADER_LEN)
45
#define CSHAKE_FLAGS (PROV_DIGEST_FLAG_XOF | PROV_DIGEST_FLAG_ALGID_ABSENT)
46
47
typedef struct cshake_ctx_st {
48
    OSSL_LIB_CTX *libctx;
49
    char *propq;
50
    EVP_MD_CTX *mdctx;
51
    EVP_MD *md;
52
    const uint8_t *func; /* encoded N */
53
    uint8_t custom[CSHAKE_MAX_ENCODED_STRING]; /* encoded S */
54
    size_t funclen;
55
    size_t customlen;
56
    size_t bitlen;
57
    size_t xoflen;
58
    int inited;
59
} CSHAKE_CTX;
60
61
static OSSL_FUNC_digest_freectx_fn cshake_freectx;
62
static OSSL_FUNC_digest_dupctx_fn cshake_dupctx;
63
static OSSL_FUNC_digest_init_fn cshake_init;
64
static OSSL_FUNC_digest_update_fn cshake_update;
65
static OSSL_FUNC_digest_final_fn cshake_final;
66
static OSSL_FUNC_digest_squeeze_fn cshake_squeeze;
67
static OSSL_FUNC_digest_set_ctx_params_fn cshake_set_ctx_params;
68
static OSSL_FUNC_digest_settable_ctx_params_fn cshake_settable_ctx_params;
69
static OSSL_FUNC_digest_get_ctx_params_fn cshake_get_ctx_params;
70
static OSSL_FUNC_digest_gettable_ctx_params_fn cshake_gettable_ctx_params;
71
72
typedef struct name_encode_map_st {
73
    const char *name;
74
    const uint8_t *encoding;
75
    size_t encodinglen;
76
} NAME_ENCODE_MAP;
77
78
/* Fixed value of encode_string("") */
79
static const unsigned char empty_encoded_string[] = {
80
    0x01, 0x00
81
};
82
83
/* Fixed value of encode_string("KMAC") */
84
static const unsigned char kmac_encoded_string[] = {
85
    0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43
86
};
87
88
/* Fixed value of encode_string("TupleHash") */
89
static const unsigned char tuplehash_encoded_string[] = {
90
    0x01, 0x48, 0x54, 0x75, 0x70, 0x6C, 0x65, 0x48, 0x61, 0x73, 0x68
91
};
92
93
/* Fixed value of encode_string("ParallelHash") */
94
static const unsigned char parallelhash_encoded_string[] = {
95
    0x01, 0x60, 0x50, 0x61, 0x72, 0x61, 0x6C, 0x6C, 0x65, 0x6C, 0x48, 0x61, 0x73, 0x68
96
};
97
98
static int cshake_set_func_encode_string(const char *in,
99
    const uint8_t **out, size_t *outlen)
100
8
{
101
    /*
102
     * A list of valid function names to encoded string mappings
103
     * See NIST SP800-185 Section 3.4
104
     */
105
8
    static NAME_ENCODE_MAP functionNameMap[] = {
106
8
        { "", empty_encoded_string, sizeof(empty_encoded_string) },
107
8
        { "KMAC", kmac_encoded_string, sizeof(kmac_encoded_string) },
108
8
        { "TupleHash", tuplehash_encoded_string, sizeof(tuplehash_encoded_string) },
109
8
        { "ParallelHash", parallelhash_encoded_string, sizeof(parallelhash_encoded_string) },
110
8
        { NULL, NULL, 0 }
111
8
    };
112
113
8
    *out = NULL;
114
8
    *outlen = 0;
115
    /*
116
     * Don't encode an empty string here - this is done manually later only when
117
     * one of the strings is not empty. If both are empty then we don't want it
118
     * to encode at all.
119
     */
120
8
    if (in == NULL || in[0] == 0)
121
8
        return 1;
122
0
    for (int i = 1; functionNameMap[i].name != NULL; ++i) {
123
0
        if (functionNameMap[i].name[0] == in[0]) {
124
0
            if (OPENSSL_strcasecmp(functionNameMap[i].name, in) == 0) {
125
0
                *out = functionNameMap[i].encoding;
126
0
                *outlen = functionNameMap[i].encodinglen;
127
0
                return 1;
128
0
            }
129
0
            return 0; /* Name does not match a known name */
130
0
        }
131
0
    }
132
0
    return 0; /* Name not found */
133
0
}
134
135
static int cshake_set_encode_string(const char *in,
136
    uint8_t *out, size_t outmax, size_t *outlen)
137
8
{
138
8
    size_t inlen;
139
140
8
    if (*outlen != 0)
141
0
        OPENSSL_cleanse(out, outmax);
142
8
    *outlen = 0;
143
8
    if (in == NULL)
144
8
        return 1;
145
146
0
    inlen = strlen(in);
147
    /*
148
     * Don't encode an empty string here - this is done manually later only when
149
     * one of the strings is not empty. If both are empty then we don't want it
150
     * to encode at all.
151
     */
152
0
    if (inlen == 0)
153
0
        return 1;
154
0
    if (inlen >= CSHAKE_MAX_STRING)
155
0
        return 0;
156
0
    return ossl_sp800_185_encode_string(out, outmax, outlen,
157
0
        (const unsigned char *)in, inlen);
158
0
}
159
160
/*
161
 * Set the xof length, note that if the digest has not been fetched yet then
162
 * it is just set into a variable and deferred to later.
163
 */
164
static int cshake_set_xoflen(CSHAKE_CTX *ctx, size_t xoflen)
165
0
{
166
0
    OSSL_PARAM params[2];
167
168
0
    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &xoflen);
169
0
    params[1] = OSSL_PARAM_construct_end();
170
171
0
    ctx->xoflen = xoflen;
172
0
    if (ctx->md != NULL)
173
0
        return EVP_MD_CTX_set_params(ctx->mdctx, params);
174
0
    return 1;
175
0
}
176
177
/*
178
 * Fetch a digest for SHAKE or KECCAK, set its xof len and init it
179
 * into an mdctx.
180
 */
181
static int cshake_set_shake_mode(CSHAKE_CTX *ctx, int shake)
182
4
{
183
4
    OSSL_PARAM params[2];
184
4
    const char *name;
185
186
4
    if (shake)
187
4
        name = (ctx->bitlen == 128 ? "SHAKE128" : "SHAKE256");
188
0
    else
189
0
        name = (ctx->bitlen == 128 ? "CSHAKE-KECCAK-128" : "CSHAKE-KECCAK-256");
190
191
4
    if (ctx->md == NULL || !EVP_MD_is_a(ctx->md, name)) {
192
4
        ctx->md = EVP_MD_fetch(ctx->libctx, name, ctx->propq);
193
4
        if (ctx->md == NULL)
194
0
            return 0;
195
4
    }
196
4
    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN,
197
4
        &ctx->xoflen);
198
4
    params[1] = OSSL_PARAM_construct_end();
199
4
    return EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params);
200
4
}
201
202
static void *cshake_newctx(void *provctx, size_t bitlen)
203
4
{
204
4
    CSHAKE_CTX *ctx;
205
206
4
    if (ossl_unlikely(!ossl_prov_is_running()))
207
0
        return NULL;
208
4
    ctx = OPENSSL_zalloc(sizeof(*ctx));
209
4
    if (ctx != NULL) {
210
4
        ctx->mdctx = EVP_MD_CTX_create();
211
4
        if (ctx->mdctx == NULL) {
212
0
            OPENSSL_free(ctx);
213
0
            return NULL;
214
0
        }
215
4
        ctx->bitlen = bitlen;
216
4
        ctx->libctx = PROV_LIBCTX_OF(provctx);
217
4
    }
218
4
    return ctx;
219
4
}
220
221
static void cshake_freectx(void *vctx)
222
4
{
223
4
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
224
225
4
    EVP_MD_free(ctx->md);
226
4
    EVP_MD_CTX_destroy(ctx->mdctx);
227
4
    OPENSSL_clear_free(ctx, sizeof(*ctx));
228
4
}
229
230
static void *cshake_dupctx(void *ctx)
231
0
{
232
0
    CSHAKE_CTX *src = (CSHAKE_CTX *)ctx;
233
0
    CSHAKE_CTX *ret = ossl_prov_is_running() ? OPENSSL_malloc(sizeof(*ret))
234
0
                                             : NULL;
235
236
0
    if (ret != NULL) {
237
0
        *ret = *src;
238
0
        ret->md = NULL;
239
0
        ret->mdctx = NULL;
240
0
        ret->propq = NULL;
241
242
0
        if (src->md != NULL && !EVP_MD_up_ref(src->md))
243
0
            goto err;
244
0
        ret->md = src->md;
245
246
0
        if (src->mdctx != NULL) {
247
0
            ret->mdctx = EVP_MD_CTX_new();
248
0
            if (ret->mdctx == NULL
249
0
                || !EVP_MD_CTX_copy_ex(ret->mdctx, src->mdctx))
250
0
                goto err;
251
0
        }
252
0
        if (src->propq != NULL) {
253
0
            ret->propq = OPENSSL_strdup(src->propq);
254
0
            if (ret->propq == NULL)
255
0
                goto err;
256
0
        }
257
0
    }
258
0
    return ret;
259
0
err:
260
0
    cshake_freectx(ret);
261
0
    return NULL;
262
0
}
263
264
static int cshake_init(void *vctx, const OSSL_PARAM params[])
265
8
{
266
8
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
267
268
8
    if (ossl_unlikely(!ossl_prov_is_running()))
269
0
        return 0;
270
8
    ctx->inited = 0;
271
8
    ctx->xoflen = (ctx->bitlen == 128) ? 32 : 64; /* Set default values here */
272
8
    cshake_set_func_encode_string(NULL, &ctx->func, &ctx->funclen);
273
8
    cshake_set_encode_string(NULL, ctx->custom, sizeof(ctx->custom), &ctx->customlen);
274
8
    return cshake_set_ctx_params(vctx, params);
275
8
}
276
277
static const OSSL_PARAM *cshake_settable_ctx_params(ossl_unused void *ctx,
278
    ossl_unused void *provctx)
279
0
{
280
0
    return cshake_set_ctx_params_list;
281
0
}
282
283
static int set_property_query(CSHAKE_CTX *ctx, const char *propq)
284
0
{
285
0
    OPENSSL_free(ctx->propq);
286
0
    ctx->propq = NULL;
287
0
    if (propq != NULL) {
288
0
        ctx->propq = OPENSSL_strdup(propq);
289
0
        if (ctx->propq == NULL)
290
0
            return 0;
291
0
    }
292
0
    return 1;
293
0
}
294
295
static int cshake_set_ctx_params(void *vctx, const OSSL_PARAM params[])
296
8
{
297
8
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
298
8
    struct cshake_set_ctx_params_st p;
299
300
8
    if (ctx == NULL || !cshake_set_ctx_params_decoder(params, &p))
301
0
        return 0;
302
303
8
    if (p.xoflen != NULL) {
304
0
        size_t xoflen;
305
306
0
        if (!OSSL_PARAM_get_size_t(p.xoflen, &xoflen)
307
0
            || !cshake_set_xoflen(ctx, xoflen)) {
308
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
309
0
            return 0;
310
0
        }
311
0
    }
312
8
    if (p.func != NULL) {
313
0
        if (p.func->data_type != OSSL_PARAM_UTF8_STRING)
314
0
            return 0;
315
0
        if (!cshake_set_func_encode_string(p.func->data, &ctx->func, &ctx->funclen)) {
316
0
            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_FUNCTION_NAME);
317
0
            return 0;
318
0
        }
319
0
    }
320
8
    if (p.custom != NULL) {
321
0
        if (p.custom->data_type != OSSL_PARAM_UTF8_STRING)
322
0
            return 0;
323
0
        if (!cshake_set_encode_string(p.custom->data, ctx->custom, sizeof(ctx->custom), &ctx->customlen))
324
0
            return 0;
325
0
    }
326
8
    if (p.propq != NULL) {
327
0
        if (p.propq->data_type != OSSL_PARAM_UTF8_STRING
328
0
            || !set_property_query(ctx, p.propq->data))
329
0
            return 0;
330
0
    }
331
8
    return 1;
332
8
}
333
334
/*
335
 * bytepad(encode_string(N) || encode_string(S), w)
336
 * See SP800-185 Section 2.3.3 Padding.
337
 *
338
 * Rather than build an array and do a single keccak operation, we use the
339
 * internal keccak buffer to simplify the process.
340
 * Note that if the strings are large enough to fill the buffer, it will handle
341
 * this internally by absorbing full blocks. The zero padding is also simple
342
 * as we just fill the buffer with zeros to make it a multiple of the blocksize.
343
 */
344
static int cshake_absorb_bytepad_strings(CSHAKE_CTX *ctx)
345
0
{
346
0
    const uint8_t zeros[SHA3_BLOCKSIZE(128)] = { 0 };
347
0
    uint8_t bytepad_header[2] = { 0x01, 0x00 };
348
0
    const uint8_t *n = ctx->func, *s = ctx->custom;
349
0
    size_t nlen = ctx->funclen, slen = ctx->customlen;
350
0
    size_t zlen;
351
0
    size_t w = SHA3_BLOCKSIZE(ctx->bitlen); /* w = 168 or 136 */
352
353
0
    bytepad_header[1] = (uint8_t)w;
354
355
    /* Empty strings are still encoded */
356
0
    if (nlen == 0) {
357
0
        n = empty_encoded_string;
358
0
        nlen = sizeof(empty_encoded_string);
359
0
    }
360
0
    if (slen == 0) {
361
0
        s = empty_encoded_string;
362
0
        slen = sizeof(empty_encoded_string);
363
0
    }
364
    /* Calculate the number of padding zeros to fill up the block */
365
0
    zlen = ((sizeof(bytepad_header) + nlen + slen) % w);
366
0
    if (zlen != 0)
367
0
        zlen = w - zlen;
368
369
    /* left encoded(w) || encodestring(n) || encodestring(s) || zero_padding */
370
0
    return EVP_DigestUpdate(ctx->mdctx, bytepad_header, sizeof(bytepad_header))
371
0
        && EVP_DigestUpdate(ctx->mdctx, n, nlen)
372
0
        && EVP_DigestUpdate(ctx->mdctx, s, slen)
373
0
        && EVP_DigestUpdate(ctx->mdctx, zeros, zlen);
374
0
}
375
376
/*
377
 * The setup of the EVP_MD gets deferred until after the set_ctx_params
378
 * which means that we need to defer to the functions that may be called
379
 * afterwards (i.e. The update(), final() or squeeze()).
380
 *
381
 */
382
static int check_init(CSHAKE_CTX *ctx)
383
12
{
384
    /*
385
     * We have to defer choosing the mode EVP_MD object (SHAKE or KECCAK)
386
     * until the first call to either update(), final() or squeeze()
387
     * since the strings can be set at any time before this point.
388
     */
389
12
    if (ctx->inited == 0) {
390
4
        if (ctx->funclen != 0 || ctx->customlen != 0) {
391
0
            if (!cshake_set_shake_mode(ctx, 0)
392
0
                || !cshake_absorb_bytepad_strings(ctx))
393
0
                return 0;
394
4
        } else {
395
            /* Use SHAKE if N and S are both empty strings */
396
4
            if (!cshake_set_shake_mode(ctx, 1))
397
0
                return 0;
398
4
        }
399
4
        ctx->inited = 1;
400
4
    }
401
12
    return 1;
402
12
}
403
404
static int cshake_update(void *vctx, const unsigned char *in, size_t inlen)
405
8
{
406
8
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
407
408
8
    return check_init(ctx)
409
8
        && EVP_DigestUpdate(ctx->mdctx, in, inlen);
410
8
}
411
412
static int cshake_final(void *vctx, uint8_t *out, size_t *outl, size_t outsz)
413
4
{
414
4
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
415
4
    unsigned int der = (unsigned int)(*outl);
416
4
    int ret = 1;
417
418
4
    if (ossl_unlikely(!ossl_prov_is_running()))
419
0
        return 0;
420
421
4
    if (outsz > 0)
422
4
        ret = check_init(ctx) && EVP_DigestFinal_ex(ctx->mdctx, out, &der);
423
4
    *outl = der;
424
4
    return ret;
425
4
}
426
427
static int cshake_squeeze(void *vctx, uint8_t *out, size_t *outl, size_t outsz)
428
0
{
429
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
430
0
    int ret = 1;
431
432
0
    if (ossl_unlikely(!ossl_prov_is_running()))
433
0
        return 0;
434
435
0
    if (outsz > 0)
436
0
        ret = check_init(ctx) && EVP_DigestSqueeze(ctx->mdctx, out, outsz);
437
0
    if (ret && outl != NULL)
438
0
        *outl = outsz;
439
0
    return ret;
440
0
}
441
442
static const OSSL_PARAM *cshake_gettable_ctx_params(ossl_unused void *ctx,
443
    ossl_unused void *provctx)
444
4
{
445
4
    return cshake_get_ctx_params_list;
446
4
}
447
448
static int cshake_get_ctx_params(void *vctx, OSSL_PARAM params[])
449
4
{
450
4
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
451
4
    struct cshake_get_ctx_params_st p;
452
453
4
    if (ctx == NULL || !cshake_get_ctx_params_decoder(params, &p))
454
0
        return 0;
455
456
    /* Size is an alias of xoflen */
457
4
    if (p.xoflen != NULL || p.size != NULL) {
458
4
        size_t xoflen = ctx->xoflen;
459
460
4
        if (ctx->md != NULL)
461
4
            xoflen = EVP_MD_CTX_get_size_ex(ctx->mdctx);
462
463
4
        if (p.size != NULL && !OSSL_PARAM_set_size_t(p.size, xoflen)) {
464
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
465
0
            return 0;
466
0
        }
467
4
        if (p.xoflen != NULL && !OSSL_PARAM_set_size_t(p.xoflen, xoflen)) {
468
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
469
0
            return 0;
470
0
        }
471
4
    }
472
4
    return 1;
473
4
}
474
475
#define IMPLEMENT_CSHAKE_functions(bitlen)                                          \
476
    static OSSL_FUNC_digest_newctx_fn cshake_##bitlen##_newctx;                     \
477
    static void *cshake_##bitlen##_newctx(void *provctx)                            \
478
4
    {                                                                               \
479
4
        return cshake_newctx(provctx, bitlen);                                      \
480
4
    }                                                                               \
cshake_prov.c:cshake_128_newctx
Line
Count
Source
478
1
    {                                                                               \
479
1
        return cshake_newctx(provctx, bitlen);                                      \
480
1
    }                                                                               \
cshake_prov.c:cshake_256_newctx
Line
Count
Source
478
3
    {                                                                               \
479
3
        return cshake_newctx(provctx, bitlen);                                      \
480
3
    }                                                                               \
481
    PROV_FUNC_DIGEST_GET_PARAM(cshake_##bitlen, SHA3_BLOCKSIZE(bitlen),             \
482
        CSHAKE_KECCAK_MDSIZE(bitlen), CSHAKE_FLAGS)                                 \
483
    const OSSL_DISPATCH ossl_cshake_##bitlen##_functions[] = {                      \
484
        { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))cshake_##bitlen##_newctx },      \
485
        { OSSL_FUNC_DIGEST_INIT, (void (*)(void))cshake_init },                     \
486
        { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))cshake_update },                 \
487
        { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))cshake_final },                   \
488
        { OSSL_FUNC_DIGEST_SQUEEZE, (void (*)(void))cshake_squeeze },               \
489
        { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))cshake_freectx },               \
490
        { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))cshake_dupctx },                 \
491
        { OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))cshake_set_ctx_params }, \
492
        { OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS,                                     \
493
            (void (*)(void))cshake_settable_ctx_params },                           \
494
        { OSSL_FUNC_DIGEST_GET_CTX_PARAMS, (void (*)(void))cshake_get_ctx_params }, \
495
        { OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS,                                     \
496
            (void (*)(void))cshake_gettable_ctx_params },                           \
497
        PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(cshake_##bitlen),                      \
498
        PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END
499
500
/* ossl_cshake_128_functions */
501
IMPLEMENT_CSHAKE_functions(128)
502
    /* ossl_cshake_256_functions */
503
    IMPLEMENT_CSHAKE_functions(256)