Coverage Report

Created: 2026-03-19 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/slhdsa/slhdsa.cc.inc
Line
Count
Source
1
// Copyright 2014 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/base.h>
16
17
#include <string.h>
18
19
#include <openssl/bytestring.h>
20
#include <openssl/obj.h>
21
#include <openssl/rand.h>
22
23
#include "../../internal.h"
24
#include "../bcm_interface.h"
25
#include "address.h"
26
#include "fors.h"
27
#include "merkle.h"
28
#include "params.h"
29
#include "thash.h"
30
31
32
using namespace bssl;
33
34
#if defined(BORINGSSL_FIPS)
35
36
DEFINE_STATIC_ONCE(g_slhdsa_keygen_self_test_once)
37
DEFINE_STATIC_ONCE(g_slhdsa_sign_self_test_once)
38
DEFINE_STATIC_ONCE(g_slhdsa_verify_self_test_once)
39
40
#endif
41
42
namespace {
43
44
namespace fips {
45
void ensure_keygen_self_test();
46
void ensure_sign_self_test();
47
void ensure_verify_self_test();
48
}  // namespace fips
49
50
// The OBJECT IDENTIFIER header is also included in these values, per the spec.
51
const uint8_t kSHA256OID[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
52
                              0x65, 0x03, 0x04, 0x02, 0x01};
53
const uint8_t kSHA384OID[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
54
                              0x65, 0x03, 0x04, 0x02, 0x02};
55
#define MAX_OID_LENGTH 11
56
0
#define MAX_CONTEXT_LENGTH 255
57
58
bcm_infallible generate_key_from_seed_no_self_test(const slh_dsa_config *config,
59
                                                   uint8_t *out_public_key,
60
                                                   uint8_t *out_secret_key,
61
0
                                                   const uint8_t *seed) {
62
  // Initialize SK.seed || SK.prf || PK.seed from seed.
63
0
  OPENSSL_memcpy(out_secret_key, seed, 3 * config->n);
64
65
  // Initialize PK.seed from seed.
66
0
  OPENSSL_memcpy(out_public_key, seed + 2 * config->n, config->n);
67
68
0
  uint8_t addr[32] = {0};
69
0
  slhdsa_set_layer_addr(config, addr, config->d - 1);
70
71
  // Set PK.root
72
0
  slhdsa_treehash(config, out_public_key + config->n, out_secret_key, 0,
73
0
                  config->tree_height, out_public_key, addr);
74
0
  OPENSSL_memcpy(out_secret_key + 3 * config->n, out_public_key + config->n,
75
0
                 config->n);
76
77
  // FIPS 140-3 IG 10.3.A comment 1 says of the pair-wise consistency test for
78
  // SLH-DSA:
79
  //
80
  // "For key pairs generated for use with approved algorithms in SP 800-208 and
81
  // FIPS 205, the PCT (described by the tester in TE10.35.02) may be limited to
82
  // confirming the same key identifier (I in the case of LMS, SEED in the case
83
  // of XMSS and PK.SEED for SLH-DSA) is shared by the resulting public and
84
  // private key following generation."
85
  //
86
  // Since this is cheap, we always do this.
87
88
0
  if (boringssl_fips_break_test("SLHDSA_PWCT")) {
89
0
    out_public_key[0] ^= 1;
90
0
  }
91
0
  if (OPENSSL_memcmp(out_public_key, out_secret_key + 2 * config->n,
92
0
                     config->n) != 0) {
93
0
    abort();
94
0
  }
95
96
0
  return bcm_infallible::not_approved;
97
0
}
98
99
0
uint64_t load_tree_index(const slh_dsa_config *config, const uint8_t *in) {
100
0
  const size_t tree_bits = slhdsa_tree_bits(config);
101
0
  const size_t tree_bytes = slhdsa_tree_bytes(config);
102
0
  BSSL_CHECK(tree_bits <= 64);
103
0
  BSSL_CHECK(tree_bytes <= 8);
104
105
0
  uint8_t buf[8] = {0};
106
0
  OPENSSL_memcpy(buf + (sizeof(buf) - tree_bytes), in, tree_bytes);
107
0
  uint64_t index = CRYPTO_load_u64_be(buf);
108
0
  if (tree_bits < 64) {
109
0
    index &= (~(uint64_t)0) >> (64 - tree_bits);
110
0
  }
111
0
  return index;
112
0
}
113
114
// Implements Algorithm 22: slh_sign function (Section 10.2.1, page 39)
115
bcm_infallible sign_internal_no_self_test(
116
    const slh_dsa_config *config, uint8_t *out_signature,
117
    const uint8_t *secret_key,
118
    const uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN], const uint8_t *context,
119
    size_t context_len, const uint8_t *msg, size_t msg_len,
120
0
    const uint8_t *entropy) {
121
0
  const size_t n = config->n;
122
0
  const uint8_t *sk_seed = secret_key;
123
0
  const uint8_t *sk_prf = secret_key + n;
124
0
  const uint8_t *pk_seed = secret_key + 2 * n;
125
0
  const uint8_t *pk_root = secret_key + 3 * n;
126
127
  // Derive randomizer R and copy it to signature
128
0
  uint8_t R[SLHDSA_MAX_N];
129
0
  slhdsa_thash_prfmsg(config, R, sk_prf, entropy, header, context, context_len,
130
0
                      msg, msg_len);
131
0
  OPENSSL_memcpy(out_signature, R, n);
132
133
  // Compute message digest
134
0
  uint8_t digest[SLHDSA_MAX_DIGEST_SIZE];
135
0
  slhdsa_thash_hmsg(config, digest, R, pk_seed, pk_root, header, context,
136
0
                    context_len, msg, msg_len);
137
138
0
  uint8_t fors_digest[SLHDSA_MAX_FORS_MSG_BYTES];
139
0
  const size_t fors_msg_bytes = slhdsa_fors_msg_bytes(config);
140
0
  OPENSSL_memcpy(fors_digest, digest, fors_msg_bytes);
141
142
0
  size_t digest_offset = fors_msg_bytes;
143
0
  const uint64_t idx_tree = load_tree_index(config, digest + digest_offset);
144
0
  digest_offset += slhdsa_tree_bytes(config);
145
0
  uint32_t idx_leaf = 0;
146
0
  const size_t leaf_bytes = slhdsa_leaf_bytes(config);
147
0
  for (size_t i = 0; i < leaf_bytes; ++i) {
148
0
    idx_leaf = (idx_leaf << 8) | digest[digest_offset + i];
149
0
  }
150
0
  const size_t leaf_bits = slhdsa_leaf_bits(config);
151
0
  if (leaf_bits < 32) {
152
0
    idx_leaf &= (~(uint32_t)0) >> (32 - leaf_bits);
153
0
  }
154
155
0
  uint8_t addr[32] = {0};
156
0
  slhdsa_set_tree_addr(config, addr, idx_tree);
157
0
  slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_FORSTREE);
158
0
  slhdsa_set_keypair_addr(config, addr, idx_leaf);
159
160
0
  slhdsa_fors_sign(config, out_signature + n, fors_digest, sk_seed, pk_seed,
161
0
                   addr);
162
163
0
  uint8_t pk_fors[SLHDSA_MAX_N];
164
0
  slhdsa_fors_pk_from_sig(config, pk_fors, out_signature + n, fors_digest,
165
0
                          pk_seed, addr);
166
167
0
  slhdsa_ht_sign(config, out_signature + n + slhdsa_fors_bytes(config), pk_fors,
168
0
                 idx_tree, idx_leaf, sk_seed, pk_seed);
169
0
  return bcm_infallible::approved;
170
0
}
171
172
bcm_status verify_internal(const slh_dsa_config *config,
173
                           const uint8_t *signature, size_t signature_len,
174
                           const uint8_t *public_key,
175
                           const uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN],
176
                           const uint8_t *context, size_t context_len,
177
0
                           const uint8_t *msg, size_t msg_len) {
178
0
  const size_t n = config->n;
179
0
  if (signature_len != config->signature_bytes) {
180
0
    return bcm_status::failure;
181
0
  }
182
0
  const uint8_t *pk_seed = public_key;
183
0
  const uint8_t *pk_root = public_key + n;
184
185
0
  const uint8_t *r = signature;
186
0
  const uint8_t *sig_fors = signature + n;
187
0
  const uint8_t *sig_ht = sig_fors + slhdsa_fors_bytes(config);
188
189
0
  uint8_t digest[SLHDSA_MAX_DIGEST_SIZE];
190
0
  slhdsa_thash_hmsg(config, digest, r, pk_seed, pk_root, header, context,
191
0
                    context_len, msg, msg_len);
192
193
0
  uint8_t fors_digest[SLHDSA_MAX_FORS_MSG_BYTES];
194
0
  const size_t fors_msg_bytes = slhdsa_fors_msg_bytes(config);
195
0
  OPENSSL_memcpy(fors_digest, digest, fors_msg_bytes);
196
197
0
  size_t digest_offset = fors_msg_bytes;
198
0
  const uint64_t idx_tree = load_tree_index(config, digest + digest_offset);
199
0
  digest_offset += slhdsa_tree_bytes(config);
200
0
  uint32_t idx_leaf = 0;
201
0
  const size_t leaf_bytes = slhdsa_leaf_bytes(config);
202
0
  for (size_t i = 0; i < leaf_bytes; ++i) {
203
0
    idx_leaf = (idx_leaf << 8) | digest[digest_offset + i];
204
0
  }
205
0
  const size_t leaf_bits = slhdsa_leaf_bits(config);
206
0
  if (leaf_bits < 32) {
207
0
    idx_leaf &= (~(uint32_t)0) >> (32 - leaf_bits);
208
0
  }
209
210
0
  uint8_t addr[32] = {0};
211
0
  slhdsa_set_tree_addr(config, addr, idx_tree);
212
0
  slhdsa_set_type(config, addr, SLHDSA_ADDR_TYPE_FORSTREE);
213
0
  slhdsa_set_keypair_addr(config, addr, idx_leaf);
214
215
0
  uint8_t pk_fors[SLHDSA_MAX_N];
216
0
  slhdsa_fors_pk_from_sig(config, pk_fors, sig_fors, fors_digest, pk_seed,
217
0
                          addr);
218
219
0
  if (!slhdsa_ht_verify(config, sig_ht, pk_fors, idx_tree, idx_leaf, pk_root,
220
0
                        pk_seed)) {
221
0
    return bcm_status::failure;
222
0
  }
223
224
0
  return bcm_status::approved;
225
0
}
226
227
namespace fips {
228
229
#include "fips_known_values.inc"
230
231
0
static int keygen_self_test() {
232
0
  uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N] = {0};
233
0
  uint8_t pub[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES];
234
0
  uint8_t priv[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES];
235
0
  generate_key_from_seed_no_self_test(&kSLHDSAConfigSHA2_128s, pub, priv, seed);
236
237
0
  if (!BORINGSSL_check_test(kExpectedPublicKey, pub, "SLH-DSA public key") ||
238
0
      !BORINGSSL_check_test(kExpectedPrivateKey, priv, "SLH-DSA private key")) {
239
0
    return 0;
240
0
  }
241
242
0
  return 1;
243
0
}
244
245
0
static int sign_self_test() {
246
0
  uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN] = {0};
247
0
  uint8_t entropy[BCM_SLHDSA_SHA2_128S_N] = {0};
248
0
  uint8_t sig[BCM_SLHDSA_SHA2_128S_SIGNATURE_BYTES];
249
0
  sign_internal_no_self_test(&kSLHDSAConfigSHA2_128s, sig, kExpectedPrivateKey,
250
0
                             header, nullptr, 0, nullptr, 0, entropy);
251
0
  uint8_t digest[32];
252
0
  SHA256(sig, sizeof(sig), digest);
253
254
0
  if (!BORINGSSL_check_test(kExpectedSignatureSHA256, digest,
255
0
                            "SLH-DSA signature")) {
256
0
    return 0;
257
0
  }
258
259
0
  return 1;
260
0
}
261
262
0
static int verify_self_test() {
263
0
  uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN] = {0};
264
0
  return verify_internal(&kSLHDSAConfigSHA2_128s, kExpectedSignature,
265
0
                         sizeof(kExpectedSignature), kExpectedPublicKey, header,
266
0
                         nullptr, 0, nullptr, 0) == bcm_status::approved;
267
0
}
268
269
#if defined(BORINGSSL_FIPS)
270
271
void ensure_keygen_self_test() {
272
  CRYPTO_once(g_slhdsa_keygen_self_test_once_bss_get(), []() {
273
    if (!keygen_self_test()) {
274
      BORINGSSL_FIPS_abort();
275
    }
276
  });
277
}
278
279
void ensure_sign_self_test() {
280
  CRYPTO_once(g_slhdsa_sign_self_test_once_bss_get(), []() {
281
    if (!sign_self_test()) {
282
      BORINGSSL_FIPS_abort();
283
    }
284
  });
285
}
286
287
void ensure_verify_self_test() {
288
  CRYPTO_once(g_slhdsa_verify_self_test_once_bss_get(), []() {
289
    if (!verify_self_test()) {
290
      BORINGSSL_FIPS_abort();
291
    }
292
  });
293
}
294
295
#else
296
297
0
void ensure_keygen_self_test() {}
298
0
void ensure_sign_self_test() {}
299
0
void ensure_verify_self_test() {}
300
301
#endif
302
303
}  // namespace fips
304
305
}  // namespace
306
307
bcm_infallible bssl::BCM_slhdsa_sha2_128s_generate_key_from_seed(
308
    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
309
    uint8_t out_secret_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
310
0
    const uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N]) {
311
0
  fips::ensure_keygen_self_test();
312
0
  return generate_key_from_seed_no_self_test(
313
0
      &kSLHDSAConfigSHA2_128s, out_public_key, out_secret_key, seed);
314
0
}
315
316
bcm_infallible bssl::BCM_slhdsa_shake_256f_generate_key_from_seed(
317
    uint8_t out_public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
318
    uint8_t out_secret_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES],
319
0
    const uint8_t seed[3 * BCM_SLHDSA_SHAKE_256F_N]) {
320
0
  fips::ensure_keygen_self_test();
321
0
  return generate_key_from_seed_no_self_test(
322
0
      &kSLHDSAConfigSHAKE_256f, out_public_key, out_secret_key, seed);
323
0
}
324
325
bcm_status bssl::BCM_slhdsa_sha2_128s_generate_key_from_seed_fips(
326
    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
327
    uint8_t out_secret_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
328
0
    const uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N]) {
329
0
  if (out_public_key == nullptr || out_secret_key == nullptr) {
330
0
    return bcm_status::failure;
331
0
  }
332
0
  BCM_slhdsa_sha2_128s_generate_key_from_seed(out_public_key, out_secret_key,
333
0
                                              seed);
334
0
  return bcm_status::approved;
335
0
}
336
337
bcm_status bssl::BCM_slhdsa_shake_256f_generate_key_from_seed_fips(
338
    uint8_t out_public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
339
    uint8_t out_secret_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES],
340
0
    const uint8_t seed[3 * BCM_SLHDSA_SHAKE_256F_N]) {
341
0
  if (out_public_key == nullptr || out_secret_key == nullptr) {
342
0
    return bcm_status::failure;
343
0
  }
344
0
  BCM_slhdsa_shake_256f_generate_key_from_seed(out_public_key, out_secret_key,
345
0
                                               seed);
346
0
  return bcm_status::approved;
347
0
}
348
349
bcm_infallible bssl::BCM_slhdsa_sha2_128s_generate_key(
350
    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
351
0
    uint8_t out_private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]) {
352
0
  uint8_t seed[3 * BCM_SLHDSA_SHA2_128S_N];
353
0
  RAND_bytes(seed, 3 * BCM_SLHDSA_SHA2_128S_N);
354
0
  return BCM_slhdsa_sha2_128s_generate_key_from_seed(out_public_key,
355
0
                                                     out_private_key, seed);
356
0
}
357
358
bcm_infallible bssl::BCM_slhdsa_shake_256f_generate_key(
359
    uint8_t out_public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
360
0
    uint8_t out_private_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES]) {
361
0
  uint8_t seed[3 * BCM_SLHDSA_SHAKE_256F_N];
362
0
  RAND_bytes(seed, 3 * BCM_SLHDSA_SHAKE_256F_N);
363
0
  return BCM_slhdsa_shake_256f_generate_key_from_seed(out_public_key,
364
0
                                                      out_private_key, seed);
365
0
}
366
367
bcm_status bssl::BCM_slhdsa_sha2_128s_generate_key_fips(
368
    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
369
0
    uint8_t out_private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]) {
370
0
  if (out_public_key == nullptr || out_private_key == nullptr) {
371
0
    return bcm_status::failure;
372
0
  }
373
0
  BCM_slhdsa_sha2_128s_generate_key(out_public_key, out_private_key);
374
0
  return bcm_status::approved;
375
0
}
376
377
bcm_status bssl::BCM_slhdsa_shake_256f_generate_key_fips(
378
    uint8_t out_public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
379
0
    uint8_t out_private_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES]) {
380
0
  if (out_public_key == nullptr || out_private_key == nullptr) {
381
0
    return bcm_status::failure;
382
0
  }
383
0
  BCM_slhdsa_shake_256f_generate_key(out_public_key, out_private_key);
384
0
  return bcm_status::approved;
385
0
}
386
387
bcm_infallible bssl::BCM_slhdsa_sha2_128s_public_from_private(
388
    uint8_t out_public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
389
0
    const uint8_t private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES]) {
390
0
  OPENSSL_memcpy(out_public_key, private_key + 2 * BCM_SLHDSA_SHA2_128S_N,
391
0
                 BCM_SLHDSA_SHA2_128S_N * 2);
392
0
  return bcm_infallible::approved;
393
0
}
394
395
bcm_infallible bssl::BCM_slhdsa_shake_256f_public_from_private(
396
    uint8_t out_public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
397
0
    const uint8_t private_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES]) {
398
0
  OPENSSL_memcpy(out_public_key, private_key + 2 * BCM_SLHDSA_SHAKE_256F_N,
399
0
                 BCM_SLHDSA_SHAKE_256F_N * 2);
400
0
  return bcm_infallible::approved;
401
0
}
402
403
bcm_status bssl::BCM_slhdsa_sha2_128s_sign(
404
    uint8_t out_signature[BCM_SLHDSA_SHA2_128S_SIGNATURE_BYTES],
405
    const uint8_t private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
406
    const uint8_t *msg, size_t msg_len, const uint8_t *context,
407
0
    size_t context_len) {
408
0
  if (context_len > MAX_CONTEXT_LENGTH) {
409
0
    return bcm_status::failure;
410
0
  }
411
412
  // Construct header for M' as specified in Algorithm 22
413
0
  uint8_t M_prime_header[2];
414
0
  M_prime_header[0] = 0;  // domain separator for pure signing
415
0
  M_prime_header[1] = (uint8_t)context_len;
416
417
0
  uint8_t entropy[BCM_SLHDSA_SHA2_128S_N];
418
0
  RAND_bytes(entropy, sizeof(entropy));
419
0
  BCM_slhdsa_sha2_128s_sign_internal(out_signature, private_key, M_prime_header,
420
0
                                     context, context_len, msg, msg_len,
421
0
                                     entropy);
422
0
  return bcm_status::approved;
423
0
}
424
425
bcm_status bssl::BCM_slhdsa_shake_256f_sign(
426
    uint8_t out_signature[BCM_SLHDSA_SHAKE_256F_SIGNATURE_BYTES],
427
    const uint8_t private_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES],
428
    const uint8_t *msg, size_t msg_len, const uint8_t *context,
429
0
    size_t context_len) {
430
0
  if (context_len > MAX_CONTEXT_LENGTH) {
431
0
    return bcm_status::failure;
432
0
  }
433
434
0
  uint8_t M_prime_header[2];
435
0
  M_prime_header[0] = 0;
436
0
  M_prime_header[1] = (uint8_t)context_len;
437
438
0
  uint8_t entropy[BCM_SLHDSA_SHAKE_256F_N];
439
0
  RAND_bytes(entropy, sizeof(entropy));
440
0
  BCM_slhdsa_shake_256f_sign_internal(out_signature, private_key,
441
0
                                      M_prime_header, context, context_len, msg,
442
0
                                      msg_len, entropy);
443
0
  return bcm_status::approved;
444
0
}
445
446
static int slhdsa_get_context_and_oid(uint8_t *out_context_and_oid,
447
                                      size_t *out_context_and_oid_len,
448
                                      size_t max_out_context_and_oid,
449
                                      const uint8_t *context,
450
                                      size_t context_len, int hash_nid,
451
0
                                      size_t hashed_msg_len) {
452
0
  const uint8_t *oid;
453
0
  size_t oid_len;
454
0
  size_t expected_hash_len;
455
0
  switch (hash_nid) {
456
0
    case NID_sha256:
457
0
      oid = kSHA256OID;
458
0
      oid_len = sizeof(kSHA256OID);
459
0
      static_assert(sizeof(kSHA256OID) <= MAX_OID_LENGTH);
460
0
      expected_hash_len = 32;
461
0
      break;
462
463
    // The SLH-DSA spec only lists SHA-256 and SHA-512. This function also
464
    // supports SHA-384, which is non-standard.
465
0
    case NID_sha384:
466
0
      oid = kSHA384OID;
467
0
      oid_len = sizeof(kSHA384OID);
468
0
      static_assert(sizeof(kSHA384OID) <= MAX_OID_LENGTH);
469
0
      expected_hash_len = 48;
470
0
      break;
471
472
    // If adding a hash function with a larger `oid_len`, update the size of
473
    // `context_and_oid` in the callers.
474
0
    default:
475
0
      return 0;
476
0
  }
477
478
0
  if (hashed_msg_len != expected_hash_len) {
479
0
    return 0;
480
0
  }
481
482
0
  *out_context_and_oid_len = context_len + oid_len;
483
0
  if (*out_context_and_oid_len > max_out_context_and_oid) {
484
0
    return 0;
485
0
  }
486
487
0
  OPENSSL_memcpy(out_context_and_oid, context, context_len);
488
0
  OPENSSL_memcpy(out_context_and_oid + context_len, oid, oid_len);
489
490
0
  return 1;
491
0
}
492
493
bcm_infallible bssl::BCM_slhdsa_sha2_128s_sign_internal(
494
    uint8_t out_signature[BCM_SLHDSA_SHA2_128S_SIGNATURE_BYTES],
495
    const uint8_t secret_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
496
    const uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN], const uint8_t *context,
497
    size_t context_len, const uint8_t *msg, size_t msg_len,
498
0
    const uint8_t entropy[BCM_SLHDSA_SHA2_128S_N]) {
499
0
  fips::ensure_sign_self_test();
500
0
  return sign_internal_no_self_test(&kSLHDSAConfigSHA2_128s, out_signature,
501
0
                                    secret_key, header, context, context_len,
502
0
                                    msg, msg_len, entropy);
503
0
}
504
505
bcm_infallible bssl::BCM_slhdsa_shake_256f_sign_internal(
506
    uint8_t out_signature[BCM_SLHDSA_SHAKE_256F_SIGNATURE_BYTES],
507
    const uint8_t secret_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES],
508
    const uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN], const uint8_t *context,
509
    size_t context_len, const uint8_t *msg, size_t msg_len,
510
0
    const uint8_t entropy[BCM_SLHDSA_SHAKE_256F_N]) {
511
0
  fips::ensure_sign_self_test();
512
0
  return sign_internal_no_self_test(&kSLHDSAConfigSHAKE_256f, out_signature,
513
0
                                    secret_key, header, context, context_len,
514
0
                                    msg, msg_len, entropy);
515
0
}
516
517
bcm_status bssl::BCM_slhdsa_sha2_128s_prehash_sign(
518
    uint8_t out_signature[BCM_SLHDSA_SHA2_128S_SIGNATURE_BYTES],
519
    const uint8_t private_key[BCM_SLHDSA_SHA2_128S_PRIVATE_KEY_BYTES],
520
    const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
521
0
    const uint8_t *context, size_t context_len) {
522
0
  if (context_len > MAX_CONTEXT_LENGTH) {
523
0
    return bcm_status::failure;
524
0
  }
525
526
0
  uint8_t M_prime_header[2];
527
0
  M_prime_header[0] = 1;  // domain separator for prehashed signing
528
0
  M_prime_header[1] = (uint8_t)context_len;
529
530
0
  uint8_t context_and_oid[MAX_CONTEXT_LENGTH + MAX_OID_LENGTH];
531
0
  size_t context_and_oid_len;
532
0
  if (!slhdsa_get_context_and_oid(context_and_oid, &context_and_oid_len,
533
0
                                  sizeof(context_and_oid), context, context_len,
534
0
                                  hash_nid, hashed_msg_len)) {
535
0
    return bcm_status::failure;
536
0
  }
537
538
0
  uint8_t entropy[BCM_SLHDSA_SHA2_128S_N];
539
0
  RAND_bytes(entropy, sizeof(entropy));
540
0
  BCM_slhdsa_sha2_128s_sign_internal(out_signature, private_key, M_prime_header,
541
0
                                     context_and_oid, context_and_oid_len,
542
0
                                     hashed_msg, hashed_msg_len, entropy);
543
0
  return bcm_status::approved;
544
0
}
545
546
bcm_status bssl::BCM_slhdsa_shake_256f_prehash_sign(
547
    uint8_t out_signature[BCM_SLHDSA_SHAKE_256F_SIGNATURE_BYTES],
548
    const uint8_t private_key[BCM_SLHDSA_SHAKE_256F_PRIVATE_KEY_BYTES],
549
    const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
550
0
    const uint8_t *context, size_t context_len) {
551
0
  if (context_len > MAX_CONTEXT_LENGTH) {
552
0
    return bcm_status::failure;
553
0
  }
554
555
0
  uint8_t M_prime_header[2];
556
0
  M_prime_header[0] = 1;
557
0
  M_prime_header[1] = (uint8_t)context_len;
558
559
0
  uint8_t context_and_oid[MAX_CONTEXT_LENGTH + MAX_OID_LENGTH];
560
0
  size_t context_and_oid_len;
561
0
  if (!slhdsa_get_context_and_oid(context_and_oid, &context_and_oid_len,
562
0
                                  sizeof(context_and_oid), context, context_len,
563
0
                                  hash_nid, hashed_msg_len)) {
564
0
    return bcm_status::failure;
565
0
  }
566
567
0
  uint8_t entropy[BCM_SLHDSA_SHAKE_256F_N];
568
0
  RAND_bytes(entropy, sizeof(entropy));
569
0
  BCM_slhdsa_shake_256f_sign_internal(
570
0
      out_signature, private_key, M_prime_header, context_and_oid,
571
0
      context_and_oid_len, hashed_msg, hashed_msg_len, entropy);
572
0
  return bcm_status::approved;
573
0
}
574
575
// Implements Algorithm 24: slh_verify function (Section 10.3, page 41)
576
bcm_status bssl::BCM_slhdsa_sha2_128s_verify(
577
    const uint8_t *signature, size_t signature_len,
578
    const uint8_t public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
579
    const uint8_t *msg, size_t msg_len, const uint8_t *context,
580
0
    size_t context_len) {
581
0
  if (context_len > MAX_CONTEXT_LENGTH) {
582
0
    return bcm_status::failure;
583
0
  }
584
585
  // Construct header for M' as specified in Algorithm 24
586
0
  uint8_t M_prime_header[2];
587
0
  M_prime_header[0] = 0;  // domain separator for pure verification
588
0
  M_prime_header[1] = (uint8_t)context_len;
589
590
0
  return BCM_slhdsa_sha2_128s_verify_internal(
591
0
      signature, signature_len, public_key, M_prime_header, context,
592
0
      context_len, msg, msg_len);
593
0
}
594
595
bcm_status bssl::BCM_slhdsa_shake_256f_verify(
596
    const uint8_t *signature, size_t signature_len,
597
    const uint8_t public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
598
    const uint8_t *msg, size_t msg_len, const uint8_t *context,
599
0
    size_t context_len) {
600
0
  if (context_len > MAX_CONTEXT_LENGTH) {
601
0
    return bcm_status::failure;
602
0
  }
603
604
0
  uint8_t M_prime_header[2];
605
0
  M_prime_header[0] = 0;
606
0
  M_prime_header[1] = (uint8_t)context_len;
607
608
0
  return BCM_slhdsa_shake_256f_verify_internal(
609
0
      signature, signature_len, public_key, M_prime_header, context,
610
0
      context_len, msg, msg_len);
611
0
}
612
613
bcm_status bssl::BCM_slhdsa_sha2_128s_prehash_verify(
614
    const uint8_t *signature, size_t signature_len,
615
    const uint8_t public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
616
    const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
617
0
    const uint8_t *context, size_t context_len) {
618
0
  if (context_len > MAX_CONTEXT_LENGTH) {
619
0
    return bcm_status::failure;
620
0
  }
621
622
0
  uint8_t M_prime_header[2];
623
0
  M_prime_header[0] = 1;  // domain separator for prehashed verification
624
0
  M_prime_header[1] = (uint8_t)context_len;
625
626
0
  uint8_t context_and_oid[MAX_CONTEXT_LENGTH + MAX_OID_LENGTH];
627
0
  size_t context_and_oid_len;
628
0
  if (!slhdsa_get_context_and_oid(context_and_oid, &context_and_oid_len,
629
0
                                  sizeof(context_and_oid), context, context_len,
630
0
                                  hash_nid, hashed_msg_len)) {
631
0
    return bcm_status::failure;
632
0
  }
633
634
0
  return BCM_slhdsa_sha2_128s_verify_internal(
635
0
      signature, signature_len, public_key, M_prime_header, context_and_oid,
636
0
      context_and_oid_len, hashed_msg, hashed_msg_len);
637
0
}
638
639
bcm_status bssl::BCM_slhdsa_shake_256f_prehash_verify(
640
    const uint8_t *signature, size_t signature_len,
641
    const uint8_t public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
642
    const uint8_t *hashed_msg, size_t hashed_msg_len, int hash_nid,
643
0
    const uint8_t *context, size_t context_len) {
644
0
  if (context_len > MAX_CONTEXT_LENGTH) {
645
0
    return bcm_status::failure;
646
0
  }
647
648
0
  uint8_t M_prime_header[2];
649
0
  M_prime_header[0] = 1;
650
0
  M_prime_header[1] = (uint8_t)context_len;
651
652
0
  uint8_t context_and_oid[MAX_CONTEXT_LENGTH + MAX_OID_LENGTH];
653
0
  size_t context_and_oid_len;
654
0
  if (!slhdsa_get_context_and_oid(context_and_oid, &context_and_oid_len,
655
0
                                  sizeof(context_and_oid), context, context_len,
656
0
                                  hash_nid, hashed_msg_len)) {
657
0
    return bcm_status::failure;
658
0
  }
659
660
0
  return BCM_slhdsa_shake_256f_verify_internal(
661
0
      signature, signature_len, public_key, M_prime_header, context_and_oid,
662
0
      context_and_oid_len, hashed_msg, hashed_msg_len);
663
0
}
664
665
bcm_status bssl::BCM_slhdsa_sha2_128s_verify_internal(
666
    const uint8_t *signature, size_t signature_len,
667
    const uint8_t public_key[BCM_SLHDSA_SHA2_128S_PUBLIC_KEY_BYTES],
668
    const uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN], const uint8_t *context,
669
0
    size_t context_len, const uint8_t *msg, size_t msg_len) {
670
0
  fips::ensure_verify_self_test();
671
0
  return verify_internal(&kSLHDSAConfigSHA2_128s, signature, signature_len,
672
0
                         public_key, header, context, context_len, msg,
673
0
                         msg_len);
674
0
}
675
676
bcm_status bssl::BCM_slhdsa_shake_256f_verify_internal(
677
    const uint8_t *signature, size_t signature_len,
678
    const uint8_t public_key[BCM_SLHDSA_SHAKE_256F_PUBLIC_KEY_BYTES],
679
    const uint8_t header[BCM_SLHDSA_M_PRIME_HEADER_LEN], const uint8_t *context,
680
0
    size_t context_len, const uint8_t *msg, size_t msg_len) {
681
0
  fips::ensure_verify_self_test();
682
0
  return verify_internal(&kSLHDSAConfigSHAKE_256f, signature, signature_len,
683
0
                         public_key, header, context, context_len, msg,
684
0
                         msg_len);
685
0
}
686
687
0
int bssl::boringssl_self_test_slhdsa() {
688
0
  return fips::keygen_self_test() && fips::sign_self_test() &&
689
0
         fips::verify_self_test();
690
0
}