Coverage Report

Created: 2026-03-09 06:55

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
0
{
101
    /*
102
     * A list of valid function names to encoded string mappings
103
     * See NIST SP800-185 Section 3.4
104
     */
105
0
    static NAME_ENCODE_MAP functionNameMap[] = {
106
0
        { "", empty_encoded_string, sizeof(empty_encoded_string) },
107
0
        { "KMAC", kmac_encoded_string, sizeof(kmac_encoded_string) },
108
0
        { "TupleHash", tuplehash_encoded_string, sizeof(tuplehash_encoded_string) },
109
0
        { "ParallelHash", parallelhash_encoded_string, sizeof(parallelhash_encoded_string) },
110
0
        { NULL, NULL, 0 }
111
0
    };
112
113
0
    *out = NULL;
114
0
    *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
0
    if (in == NULL || in[0] == 0)
121
0
        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
0
{
138
0
    size_t inlen;
139
140
0
    if (*outlen != 0)
141
0
        OPENSSL_cleanse(out, outmax);
142
0
    *outlen = 0;
143
0
    if (in == NULL)
144
0
        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
0
{
183
0
    OSSL_PARAM params[2];
184
0
    const char *name;
185
186
0
    if (shake)
187
0
        name = (ctx->bitlen == 128 ? "SHAKE128" : "SHAKE256");
188
0
    else
189
0
        name = (ctx->bitlen == 128 ? "CSHAKE-KECCAK-128" : "CSHAKE-KECCAK-256");
190
191
0
    if (ctx->md == NULL || !EVP_MD_is_a(ctx->md, name)) {
192
0
        ctx->md = EVP_MD_fetch(ctx->libctx, name, ctx->propq);
193
0
        if (ctx->md == NULL)
194
0
            return 0;
195
0
    }
196
0
    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN,
197
0
        &ctx->xoflen);
198
0
    params[1] = OSSL_PARAM_construct_end();
199
0
    return EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params);
200
0
}
201
202
static void *cshake_newctx(void *provctx, size_t bitlen)
203
0
{
204
0
    CSHAKE_CTX *ctx;
205
206
0
    if (ossl_unlikely(!ossl_prov_is_running()))
207
0
        return NULL;
208
0
    ctx = OPENSSL_zalloc(sizeof(*ctx));
209
0
    if (ctx != NULL) {
210
0
        ctx->mdctx = EVP_MD_CTX_create();
211
0
        if (ctx->mdctx == NULL) {
212
0
            OPENSSL_free(ctx);
213
0
            return NULL;
214
0
        }
215
0
        ctx->bitlen = bitlen;
216
0
        ctx->libctx = PROV_LIBCTX_OF(provctx);
217
0
    }
218
0
    return ctx;
219
0
}
220
221
static void cshake_freectx(void *vctx)
222
0
{
223
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
224
225
0
    OPENSSL_free(ctx->propq);
226
0
    EVP_MD_free(ctx->md);
227
0
    EVP_MD_CTX_destroy(ctx->mdctx);
228
0
    OPENSSL_clear_free(ctx, sizeof(*ctx));
229
0
}
230
231
static void *cshake_dupctx(void *ctx)
232
0
{
233
0
    CSHAKE_CTX *src = (CSHAKE_CTX *)ctx;
234
0
    CSHAKE_CTX *ret = ossl_prov_is_running() ? OPENSSL_malloc(sizeof(*ret))
235
0
                                             : NULL;
236
237
0
    if (ret != NULL) {
238
0
        *ret = *src;
239
0
        ret->md = NULL;
240
0
        ret->mdctx = NULL;
241
0
        ret->propq = NULL;
242
243
0
        if (src->md != NULL && !EVP_MD_up_ref(src->md))
244
0
            goto err;
245
0
        ret->md = src->md;
246
247
0
        if (src->mdctx != NULL) {
248
0
            ret->mdctx = EVP_MD_CTX_new();
249
0
            if (ret->mdctx == NULL
250
0
                || !EVP_MD_CTX_copy_ex(ret->mdctx, src->mdctx))
251
0
                goto err;
252
0
        }
253
0
        if (src->propq != NULL) {
254
0
            ret->propq = OPENSSL_strdup(src->propq);
255
0
            if (ret->propq == NULL)
256
0
                goto err;
257
0
        }
258
0
    }
259
0
    return ret;
260
0
err:
261
0
    cshake_freectx(ret);
262
0
    return NULL;
263
0
}
264
265
static int cshake_init(void *vctx, const OSSL_PARAM params[])
266
0
{
267
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
268
269
0
    if (ossl_unlikely(!ossl_prov_is_running()))
270
0
        return 0;
271
0
    ctx->inited = 0;
272
0
    ctx->xoflen = (ctx->bitlen == 128) ? 32 : 64; /* Set default values here */
273
0
    cshake_set_func_encode_string(NULL, &ctx->func, &ctx->funclen);
274
0
    cshake_set_encode_string(NULL, ctx->custom, sizeof(ctx->custom), &ctx->customlen);
275
0
    return cshake_set_ctx_params(vctx, params);
276
0
}
277
278
static const OSSL_PARAM *cshake_settable_ctx_params(ossl_unused void *ctx,
279
    ossl_unused void *provctx)
280
0
{
281
0
    return cshake_set_ctx_params_list;
282
0
}
283
284
static int set_property_query(CSHAKE_CTX *ctx, const char *propq)
285
0
{
286
0
    OPENSSL_free(ctx->propq);
287
0
    ctx->propq = NULL;
288
0
    if (propq != NULL) {
289
0
        ctx->propq = OPENSSL_strdup(propq);
290
0
        if (ctx->propq == NULL)
291
0
            return 0;
292
0
    }
293
0
    return 1;
294
0
}
295
296
static int cshake_set_ctx_params(void *vctx, const OSSL_PARAM params[])
297
0
{
298
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
299
0
    struct cshake_set_ctx_params_st p;
300
301
0
    if (ctx == NULL || !cshake_set_ctx_params_decoder(params, &p))
302
0
        return 0;
303
304
0
    if (p.xoflen != NULL) {
305
0
        size_t xoflen;
306
307
0
        if (!OSSL_PARAM_get_size_t(p.xoflen, &xoflen)
308
0
            || !cshake_set_xoflen(ctx, xoflen)) {
309
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
310
0
            return 0;
311
0
        }
312
0
    }
313
0
    if (p.func != NULL) {
314
0
        if (p.func->data_type != OSSL_PARAM_UTF8_STRING)
315
0
            return 0;
316
0
        if (!cshake_set_func_encode_string(p.func->data, &ctx->func, &ctx->funclen)) {
317
0
            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_FUNCTION_NAME);
318
0
            return 0;
319
0
        }
320
0
    }
321
0
    if (p.custom != NULL) {
322
0
        if (p.custom->data_type != OSSL_PARAM_UTF8_STRING)
323
0
            return 0;
324
0
        if (!cshake_set_encode_string(p.custom->data, ctx->custom, sizeof(ctx->custom), &ctx->customlen))
325
0
            return 0;
326
0
    }
327
0
    if (p.propq != NULL) {
328
0
        if (p.propq->data_type != OSSL_PARAM_UTF8_STRING
329
0
            || !set_property_query(ctx, p.propq->data))
330
0
            return 0;
331
0
    }
332
0
    return 1;
333
0
}
334
335
/*
336
 * bytepad(encode_string(N) || encode_string(S), w)
337
 * See SP800-185 Section 2.3.3 Padding.
338
 *
339
 * Rather than build an array and do a single keccak operation, we use the
340
 * internal keccak buffer to simplify the process.
341
 * Note that if the strings are large enough to fill the buffer, it will handle
342
 * this internally by absorbing full blocks. The zero padding is also simple
343
 * as we just fill the buffer with zeros to make it a multiple of the blocksize.
344
 */
345
static int cshake_absorb_bytepad_strings(CSHAKE_CTX *ctx)
346
0
{
347
0
    const uint8_t zeros[SHA3_BLOCKSIZE(128)] = { 0 };
348
0
    uint8_t bytepad_header[2] = { 0x01, 0x00 };
349
0
    const uint8_t *n = ctx->func, *s = ctx->custom;
350
0
    size_t nlen = ctx->funclen, slen = ctx->customlen;
351
0
    size_t zlen;
352
0
    size_t w = SHA3_BLOCKSIZE(ctx->bitlen); /* w = 168 or 136 */
353
354
0
    bytepad_header[1] = (uint8_t)w;
355
356
    /* Empty strings are still encoded */
357
0
    if (nlen == 0) {
358
0
        n = empty_encoded_string;
359
0
        nlen = sizeof(empty_encoded_string);
360
0
    }
361
0
    if (slen == 0) {
362
0
        s = empty_encoded_string;
363
0
        slen = sizeof(empty_encoded_string);
364
0
    }
365
    /* Calculate the number of padding zeros to fill up the block */
366
0
    zlen = ((sizeof(bytepad_header) + nlen + slen) % w);
367
0
    if (zlen != 0)
368
0
        zlen = w - zlen;
369
370
    /* left encoded(w) || encodestring(n) || encodestring(s) || zero_padding */
371
0
    return EVP_DigestUpdate(ctx->mdctx, bytepad_header, sizeof(bytepad_header))
372
0
        && EVP_DigestUpdate(ctx->mdctx, n, nlen)
373
0
        && EVP_DigestUpdate(ctx->mdctx, s, slen)
374
0
        && EVP_DigestUpdate(ctx->mdctx, zeros, zlen);
375
0
}
376
377
/*
378
 * The setup of the EVP_MD gets deferred until after the set_ctx_params
379
 * which means that we need to defer to the functions that may be called
380
 * afterwards (i.e. The update(), final() or squeeze()).
381
 *
382
 */
383
static int check_init(CSHAKE_CTX *ctx)
384
0
{
385
    /*
386
     * We have to defer choosing the mode EVP_MD object (SHAKE or KECCAK)
387
     * until the first call to either update(), final() or squeeze()
388
     * since the strings can be set at any time before this point.
389
     */
390
0
    if (ctx->inited == 0) {
391
0
        if (ctx->funclen != 0 || ctx->customlen != 0) {
392
0
            if (!cshake_set_shake_mode(ctx, 0)
393
0
                || !cshake_absorb_bytepad_strings(ctx))
394
0
                return 0;
395
0
        } else {
396
            /* Use SHAKE if N and S are both empty strings */
397
0
            if (!cshake_set_shake_mode(ctx, 1))
398
0
                return 0;
399
0
        }
400
0
        ctx->inited = 1;
401
0
    }
402
0
    return 1;
403
0
}
404
405
static int cshake_update(void *vctx, const unsigned char *in, size_t inlen)
406
0
{
407
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
408
409
0
    return check_init(ctx)
410
0
        && EVP_DigestUpdate(ctx->mdctx, in, inlen);
411
0
}
412
413
static int cshake_final(void *vctx, uint8_t *out, size_t *outl, size_t outsz)
414
0
{
415
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
416
0
    unsigned int der = (unsigned int)(*outl);
417
0
    int ret = 1;
418
419
0
    if (ossl_unlikely(!ossl_prov_is_running()))
420
0
        return 0;
421
422
0
    if (outsz > 0)
423
0
        ret = check_init(ctx) && EVP_DigestFinal_ex(ctx->mdctx, out, &der);
424
0
    *outl = der;
425
0
    return ret;
426
0
}
427
428
static int cshake_squeeze(void *vctx, uint8_t *out, size_t *outl, size_t outsz)
429
0
{
430
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
431
0
    int ret = 1;
432
433
0
    if (ossl_unlikely(!ossl_prov_is_running()))
434
0
        return 0;
435
436
0
    if (outsz > 0)
437
0
        ret = check_init(ctx) && EVP_DigestSqueeze(ctx->mdctx, out, outsz);
438
0
    if (ret && outl != NULL)
439
0
        *outl = outsz;
440
0
    return ret;
441
0
}
442
443
static const OSSL_PARAM *cshake_gettable_ctx_params(ossl_unused void *ctx,
444
    ossl_unused void *provctx)
445
0
{
446
0
    return cshake_get_ctx_params_list;
447
0
}
448
449
static int cshake_get_ctx_params(void *vctx, OSSL_PARAM params[])
450
0
{
451
0
    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
452
0
    struct cshake_get_ctx_params_st p;
453
454
0
    if (ctx == NULL || !cshake_get_ctx_params_decoder(params, &p))
455
0
        return 0;
456
457
    /* Size is an alias of xoflen */
458
0
    if (p.xoflen != NULL || p.size != NULL) {
459
0
        size_t xoflen = ctx->xoflen;
460
461
0
        if (ctx->md != NULL)
462
0
            xoflen = EVP_MD_CTX_get_size_ex(ctx->mdctx);
463
464
0
        if (p.size != NULL && !OSSL_PARAM_set_size_t(p.size, xoflen)) {
465
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
466
0
            return 0;
467
0
        }
468
0
        if (p.xoflen != NULL && !OSSL_PARAM_set_size_t(p.xoflen, xoflen)) {
469
0
            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
470
0
            return 0;
471
0
        }
472
0
    }
473
0
    return 1;
474
0
}
475
476
#define IMPLEMENT_CSHAKE_functions(bitlen)                                          \
477
    static OSSL_FUNC_digest_newctx_fn cshake_##bitlen##_newctx;                     \
478
    static void *cshake_##bitlen##_newctx(void *provctx)                            \
479
0
    {                                                                               \
480
0
        return cshake_newctx(provctx, bitlen);                                      \
481
0
    }                                                                               \
Unexecuted instantiation: cshake_prov.c:cshake_128_newctx
Unexecuted instantiation: cshake_prov.c:cshake_256_newctx
482
    PROV_FUNC_DIGEST_GET_PARAM(cshake_##bitlen, SHA3_BLOCKSIZE(bitlen),             \
483
        CSHAKE_KECCAK_MDSIZE(bitlen), CSHAKE_FLAGS)                                 \
484
    const OSSL_DISPATCH ossl_cshake_##bitlen##_functions[] = {                      \
485
        { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))cshake_##bitlen##_newctx },      \
486
        { OSSL_FUNC_DIGEST_INIT, (void (*)(void))cshake_init },                     \
487
        { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))cshake_update },                 \
488
        { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))cshake_final },                   \
489
        { OSSL_FUNC_DIGEST_SQUEEZE, (void (*)(void))cshake_squeeze },               \
490
        { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))cshake_freectx },               \
491
        { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))cshake_dupctx },                 \
492
        { OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))cshake_set_ctx_params }, \
493
        { OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS,                                     \
494
            (void (*)(void))cshake_settable_ctx_params },                           \
495
        { OSSL_FUNC_DIGEST_GET_CTX_PARAMS, (void (*)(void))cshake_get_ctx_params }, \
496
        { OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS,                                     \
497
            (void (*)(void))cshake_gettable_ctx_params },                           \
498
        PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(cshake_##bitlen),                      \
499
        PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END
500
501
/* ossl_cshake_128_functions */
502
IMPLEMENT_CSHAKE_functions(128)
503
    /* ossl_cshake_256_functions */
504
    IMPLEMENT_CSHAKE_functions(256)