Coverage Report

Created: 2025-08-28 07:07

/src/openssl35/crypto/slh_dsa/slh_hash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2024-2025 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
#include "internal/deprecated.h" /* PKCS1_MGF1() */
11
12
#include <string.h>
13
#include <openssl/evp.h>
14
#include <openssl/core_names.h>
15
#include <openssl/rsa.h> /* PKCS1_MGF1() */
16
#include "slh_dsa_local.h"
17
#include "slh_dsa_key.h"
18
19
#define MAX_DIGEST_SIZE 64 /* SHA-512 is used for security category 3 & 5 */
20
21
static OSSL_SLH_HASHFUNC_H_MSG slh_hmsg_sha2;
22
static OSSL_SLH_HASHFUNC_PRF slh_prf_sha2;
23
static OSSL_SLH_HASHFUNC_PRF_MSG slh_prf_msg_sha2;
24
static OSSL_SLH_HASHFUNC_F slh_f_sha2;
25
static OSSL_SLH_HASHFUNC_H slh_h_sha2;
26
static OSSL_SLH_HASHFUNC_T slh_t_sha2;
27
28
static OSSL_SLH_HASHFUNC_H_MSG slh_hmsg_shake;
29
static OSSL_SLH_HASHFUNC_PRF slh_prf_shake;
30
static OSSL_SLH_HASHFUNC_PRF_MSG slh_prf_msg_shake;
31
static OSSL_SLH_HASHFUNC_F slh_f_shake;
32
static OSSL_SLH_HASHFUNC_H slh_h_shake;
33
static OSSL_SLH_HASHFUNC_T slh_t_shake;
34
35
static ossl_inline int xof_digest_3(EVP_MD_CTX *ctx,
36
                                    const uint8_t *in1, size_t in1_len,
37
                                    const uint8_t *in2, size_t in2_len,
38
                                    const uint8_t *in3, size_t in3_len,
39
                                    uint8_t *out, size_t out_len)
40
243M
{
41
243M
    return (EVP_DigestInit_ex2(ctx, NULL, NULL) == 1
42
243M
            && EVP_DigestUpdate(ctx, in1, in1_len) == 1
43
243M
            && EVP_DigestUpdate(ctx, in2, in2_len) == 1
44
243M
            && EVP_DigestUpdate(ctx, in3, in3_len) == 1
45
243M
            && EVP_DigestFinalXOF(ctx, out, out_len) == 1);
46
243M
}
47
48
static ossl_inline int xof_digest_4(EVP_MD_CTX *ctx,
49
                                    const uint8_t *in1, size_t in1_len,
50
                                    const uint8_t *in2, size_t in2_len,
51
                                    const uint8_t *in3, size_t in3_len,
52
                                    const uint8_t *in4, size_t in4_len,
53
                                    uint8_t *out, size_t out_len)
54
17.7M
{
55
17.7M
    return (EVP_DigestInit_ex2(ctx, NULL, NULL) == 1
56
17.7M
            && EVP_DigestUpdate(ctx, in1, in1_len) == 1
57
17.7M
            && EVP_DigestUpdate(ctx, in2, in2_len) == 1
58
17.7M
            && EVP_DigestUpdate(ctx, in3, in3_len) == 1
59
17.7M
            && EVP_DigestUpdate(ctx, in4, in4_len) == 1
60
17.7M
            && EVP_DigestFinalXOF(ctx, out, out_len) == 1);
61
17.7M
}
62
63
/* See FIPS 205 Section 11.1 */
64
static int
65
slh_hmsg_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *r,
66
               const uint8_t *pk_seed, const uint8_t *pk_root,
67
               const uint8_t *msg, size_t msg_len,
68
               uint8_t *out, size_t out_len)
69
374
{
70
374
    const SLH_DSA_PARAMS *params = ctx->key->params;
71
374
    size_t m = params->m;
72
374
    size_t n = params->n;
73
74
374
    return xof_digest_4(ctx->md_ctx, r, n, pk_seed, n, pk_root, n,
75
374
                        msg, msg_len, out, m);
76
374
}
77
78
static int
79
slh_prf_shake(SLH_DSA_HASH_CTX *ctx,
80
              const uint8_t *pk_seed, const uint8_t *sk_seed,
81
              const uint8_t *adrs, uint8_t *out, size_t out_len)
82
30.4M
{
83
30.4M
    const SLH_DSA_PARAMS *params = ctx->key->params;
84
30.4M
    size_t n = params->n;
85
86
30.4M
    return xof_digest_3(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE,
87
30.4M
                        sk_seed, n, out, n);
88
30.4M
}
89
90
static int
91
slh_prf_msg_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_prf,
92
                  const uint8_t *opt_rand, const uint8_t *msg, size_t msg_len,
93
                  WPACKET *pkt)
94
187
{
95
187
    unsigned char out[SLH_MAX_N];
96
187
    const SLH_DSA_PARAMS *params = ctx->key->params;
97
187
    size_t n = params->n;
98
99
187
    return xof_digest_3(ctx->md_ctx, sk_prf, n, opt_rand, n, msg, msg_len, out, n)
100
187
        && WPACKET_memcpy(pkt, out, n);
101
187
}
102
103
static int
104
slh_f_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, const uint8_t *adrs,
105
            const uint8_t *m1, size_t m1_len, uint8_t *out, size_t out_len)
106
212M
{
107
212M
    const SLH_DSA_PARAMS *params = ctx->key->params;
108
212M
    size_t n = params->n;
109
110
212M
    return xof_digest_3(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE, m1, m1_len, out, n);
111
212M
}
112
113
static int
114
slh_h_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, const uint8_t *adrs,
115
            const uint8_t *m1, const uint8_t *m2, uint8_t *out, size_t out_len)
116
17.7M
{
117
17.7M
    const SLH_DSA_PARAMS *params = ctx->key->params;
118
17.7M
    size_t n = params->n;
119
120
17.7M
    return xof_digest_4(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE, m1, n, m2, n, out, n);
121
17.7M
}
122
123
static int
124
slh_t_shake(SLH_DSA_HASH_CTX *ctx, const uint8_t *pk_seed, const uint8_t *adrs,
125
            const uint8_t *ml, size_t ml_len, uint8_t *out, size_t out_len)
126
256k
{
127
256k
    const SLH_DSA_PARAMS *params = ctx->key->params;
128
256k
    size_t n = params->n;
129
130
256k
    return xof_digest_3(ctx->md_ctx, pk_seed, n, adrs, SLH_ADRS_SIZE, ml, ml_len, out, n);
131
256k
}
132
133
static ossl_inline int
134
digest_4(EVP_MD_CTX *ctx,
135
         const uint8_t *in1, size_t in1_len, const uint8_t *in2, size_t in2_len,
136
         const uint8_t *in3, size_t in3_len, const uint8_t *in4, size_t in4_len,
137
         uint8_t *out)
138
546M
{
139
546M
    return (EVP_DigestInit_ex2(ctx, NULL, NULL) == 1
140
546M
            && EVP_DigestUpdate(ctx, in1, in1_len) == 1
141
546M
            && EVP_DigestUpdate(ctx, in2, in2_len) == 1
142
546M
            && EVP_DigestUpdate(ctx, in3, in3_len) == 1
143
546M
            && EVP_DigestUpdate(ctx, in4, in4_len) == 1
144
546M
            && EVP_DigestFinal_ex(ctx, out, NULL) == 1);
145
546M
}
146
147
/* FIPS 205 Section 11.2.1 and 11.2.2 */
148
149
static int
150
slh_hmsg_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *r, const uint8_t *pk_seed,
151
              const uint8_t *pk_root, const uint8_t *msg, size_t msg_len,
152
              uint8_t *out, size_t out_len)
153
764
{
154
764
    const SLH_DSA_PARAMS *params = hctx->key->params;
155
764
    size_t m = params->m;
156
764
    size_t n = params->n;
157
764
    uint8_t seed[2 * SLH_MAX_N + MAX_DIGEST_SIZE];
158
764
    int sz = EVP_MD_get_size(hctx->key->md_big);
159
764
    size_t seed_len = (size_t)sz + 2 * n;
160
161
764
    if (sz <= 0)
162
0
        return 0;
163
164
764
    memcpy(seed, r, n);
165
764
    memcpy(seed + n, pk_seed, n);
166
764
    return digest_4(hctx->md_big_ctx, r, n, pk_seed, n, pk_root, n, msg, msg_len,
167
764
                    seed + 2 * n)
168
764
        && (PKCS1_MGF1(out, m, seed, seed_len, hctx->key->md_big) == 0);
169
764
}
170
171
static int
172
slh_prf_msg_sha2(SLH_DSA_HASH_CTX *hctx,
173
                 const uint8_t *sk_prf, const uint8_t *opt_rand,
174
                 const uint8_t *msg, size_t msg_len, WPACKET *pkt)
175
382
{
176
382
    int ret;
177
382
    const SLH_DSA_KEY *key = hctx->key;
178
382
    EVP_MAC_CTX *mctx = hctx->hmac_ctx;
179
382
    const SLH_DSA_PARAMS *prms = key->params;
180
382
    size_t n = prms->n;
181
382
    uint8_t mac[MAX_DIGEST_SIZE] = {0};
182
382
    OSSL_PARAM *p = NULL;
183
382
    OSSL_PARAM params[3];
184
185
    /*
186
     * Due to the way HMAC works, it is not possible to do this code early
187
     * in hmac_ctx_new() since it requires a key in order to set the digest.
188
     * So we do a lazy update here on the first call.
189
     */
190
382
    if (hctx->hmac_digest_used == 0) {
191
382
        p = params;
192
        /* The underlying digest to be used */
193
382
        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
194
382
                                                (char *)EVP_MD_get0_name(key->md_big), 0);
195
382
        if (key->propq != NULL)
196
0
            *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_PROPERTIES,
197
0
                                                    (char *)key->propq, 0);
198
382
        *p = OSSL_PARAM_construct_end();
199
382
        p = params;
200
382
        hctx->hmac_digest_used = 1;
201
382
    }
202
203
382
    ret = EVP_MAC_init(mctx, sk_prf, n, p) == 1
204
382
        && EVP_MAC_update(mctx, opt_rand, n) == 1
205
382
        && EVP_MAC_update(mctx, msg, msg_len) == 1
206
382
        && EVP_MAC_final(mctx, mac, NULL, sizeof(mac)) == 1
207
382
        && WPACKET_memcpy(pkt, mac, n); /* Truncate output to n bytes */
208
382
    return ret;
209
382
}
210
211
static ossl_inline int
212
do_hash(EVP_MD_CTX *ctx, size_t n, const uint8_t *pk_seed, const uint8_t *adrs,
213
        const uint8_t *m, size_t m_len, size_t b, uint8_t *out, size_t out_len)
214
546M
{
215
546M
    int ret;
216
546M
    uint8_t zeros[128] = { 0 };
217
546M
    uint8_t digest[MAX_DIGEST_SIZE];
218
219
546M
    ret = digest_4(ctx, pk_seed, n, zeros, b - n, adrs, SLH_ADRSC_SIZE,
220
546M
                   m, m_len, digest);
221
    /* Truncated returned value is n = 16 bytes */
222
546M
    memcpy(out, digest, n);
223
546M
    return ret;
224
546M
}
225
226
static int
227
slh_prf_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed,
228
             const uint8_t *sk_seed, const uint8_t *adrs,
229
             uint8_t *out, size_t out_len)
230
60.9M
{
231
60.9M
    size_t n = hctx->key->params->n;
232
233
60.9M
    return do_hash(hctx->md_ctx, n, pk_seed, adrs, sk_seed, n,
234
60.9M
                   OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len);
235
60.9M
}
236
237
static int
238
slh_f_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs,
239
           const uint8_t *m1, size_t m1_len, uint8_t *out, size_t out_len)
240
450M
{
241
450M
    return do_hash(hctx->md_ctx, hctx->key->params->n, pk_seed, adrs, m1, m1_len,
242
450M
                   OSSL_SLH_DSA_SHA2_NUM_ZEROS_H_AND_T_BOUND1, out, out_len);
243
450M
}
244
245
static int
246
slh_h_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs,
247
           const uint8_t *m1, const uint8_t *m2, uint8_t *out, size_t out_len)
248
33.9M
{
249
33.9M
    uint8_t m[SLH_MAX_N * 2];
250
33.9M
    const SLH_DSA_PARAMS *prms = hctx->key->params;
251
33.9M
    size_t n = prms->n;
252
253
33.9M
    memcpy(m, m1, n);
254
33.9M
    memcpy(m + n, m2, n);
255
33.9M
    return do_hash(hctx->md_big_ctx, n, pk_seed, adrs, m, 2 * n,
256
33.9M
                   prms->sha2_h_and_t_bound, out, out_len);
257
33.9M
}
258
259
static int
260
slh_t_sha2(SLH_DSA_HASH_CTX *hctx, const uint8_t *pk_seed, const uint8_t *adrs,
261
           const uint8_t *ml, size_t ml_len, uint8_t *out, size_t out_len)
262
606k
{
263
606k
    const SLH_DSA_PARAMS *prms = hctx->key->params;
264
265
606k
    return do_hash(hctx->md_big_ctx, prms->n, pk_seed, adrs, ml, ml_len,
266
606k
                   prms->sha2_h_and_t_bound, out, out_len);
267
606k
}
268
269
const SLH_HASH_FUNC *ossl_slh_get_hash_fn(int is_shake)
270
146k
{
271
146k
    static const SLH_HASH_FUNC methods[] = {
272
146k
        {
273
146k
            slh_hmsg_shake,
274
146k
            slh_prf_shake,
275
146k
            slh_prf_msg_shake,
276
146k
            slh_f_shake,
277
146k
            slh_h_shake,
278
146k
            slh_t_shake
279
146k
        },
280
146k
        {
281
146k
            slh_hmsg_sha2,
282
146k
            slh_prf_sha2,
283
146k
            slh_prf_msg_sha2,
284
146k
            slh_f_sha2,
285
146k
            slh_h_sha2,
286
146k
            slh_t_sha2
287
146k
        }
288
146k
    };
289
146k
    return &methods[is_shake ? 0 : 1];
290
146k
}