Skip to content

Commit 1168621

Browse files
committed
crypto: support SLH-DSA KeyObject, sign, and verify
1 parent 7c9fbc1 commit 1168621

33 files changed

+542
-37
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ constexpr static PQCMapping pqc_mappings[] = {
2525
{"ML-KEM-512", EVP_PKEY_ML_KEM_512},
2626
{"ML-KEM-768", EVP_PKEY_ML_KEM_768},
2727
{"ML-KEM-1024", EVP_PKEY_ML_KEM_1024},
28+
{"SLH-DSA-SHA2-128f", EVP_PKEY_SLH_DSA_SHA2_128F},
29+
{"SLH-DSA-SHA2-128s", EVP_PKEY_SLH_DSA_SHA2_128S},
30+
{"SLH-DSA-SHA2-192f", EVP_PKEY_SLH_DSA_SHA2_192F},
31+
{"SLH-DSA-SHA2-192s", EVP_PKEY_SLH_DSA_SHA2_192S},
32+
{"SLH-DSA-SHA2-256f", EVP_PKEY_SLH_DSA_SHA2_256F},
33+
{"SLH-DSA-SHA2-256s", EVP_PKEY_SLH_DSA_SHA2_256S},
34+
{"SLH-DSA-SHAKE-128f", EVP_PKEY_SLH_DSA_SHAKE_128F},
35+
{"SLH-DSA-SHAKE-128s", EVP_PKEY_SLH_DSA_SHAKE_128S},
36+
{"SLH-DSA-SHAKE-192f", EVP_PKEY_SLH_DSA_SHAKE_192F},
37+
{"SLH-DSA-SHAKE-192s", EVP_PKEY_SLH_DSA_SHAKE_192S},
38+
{"SLH-DSA-SHAKE-256f", EVP_PKEY_SLH_DSA_SHAKE_256F},
39+
{"SLH-DSA-SHAKE-256s", EVP_PKEY_SLH_DSA_SHAKE_256S},
2840
};
2941

3042
#endif
@@ -2545,6 +2557,18 @@ bool EVPKeyPointer::isOneShotVariant() const {
25452557
case EVP_PKEY_ML_DSA_44:
25462558
case EVP_PKEY_ML_DSA_65:
25472559
case EVP_PKEY_ML_DSA_87:
2560+
case EVP_PKEY_SLH_DSA_SHA2_128F:
2561+
case EVP_PKEY_SLH_DSA_SHA2_128S:
2562+
case EVP_PKEY_SLH_DSA_SHA2_192F:
2563+
case EVP_PKEY_SLH_DSA_SHA2_192S:
2564+
case EVP_PKEY_SLH_DSA_SHA2_256F:
2565+
case EVP_PKEY_SLH_DSA_SHA2_256S:
2566+
case EVP_PKEY_SLH_DSA_SHAKE_128F:
2567+
case EVP_PKEY_SLH_DSA_SHAKE_128S:
2568+
case EVP_PKEY_SLH_DSA_SHAKE_192F:
2569+
case EVP_PKEY_SLH_DSA_SHAKE_192S:
2570+
case EVP_PKEY_SLH_DSA_SHAKE_256F:
2571+
case EVP_PKEY_SLH_DSA_SHAKE_256S:
25482572
#endif
25492573
return true;
25502574
default:

doc/api/crypto.md

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,35 @@ try {
7777

7878
The following table lists the asymmetric key types recognized by the [`KeyObject`][] API:
7979

80-
| Key Type | Description | OID |
81-
| --------------------------- | -------------- | ----------------------- |
82-
| `'dh'` | Diffie-Hellman | 1.2.840.113549.1.3.1 |
83-
| `'dsa'` | DSA | 1.2.840.10040.4.1 |
84-
| `'ec'` | Elliptic curve | 1.2.840.10045.2.1 |
85-
| `'ed25519'` | Ed25519 | 1.3.101.112 |
86-
| `'ed448'` | Ed448 | 1.3.101.113 |
87-
| `'ml-dsa-44'`[^openssl35] | ML-DSA-44 | 2.16.840.1.101.3.4.3.17 |
88-
| `'ml-dsa-65'`[^openssl35] | ML-DSA-65 | 2.16.840.1.101.3.4.3.18 |
89-
| `'ml-dsa-87'`[^openssl35] | ML-DSA-87 | 2.16.840.1.101.3.4.3.19 |
90-
| `'ml-kem-1024'`[^openssl35] | ML-KEM-1024 | 2.16.840.1.101.3.4.4.3 |
91-
| `'ml-kem-512'`[^openssl35] | ML-KEM-512 | 2.16.840.1.101.3.4.4.1 |
92-
| `'ml-kem-768'`[^openssl35] | ML-KEM-768 | 2.16.840.1.101.3.4.4.2 |
93-
| `'rsa-pss'` | RSA PSS | 1.2.840.113549.1.1.10 |
94-
| `'rsa'` | RSA | 1.2.840.113549.1.1.1 |
95-
| `'x25519'` | X25519 | 1.3.101.110 |
96-
| `'x448'` | X448 | 1.3.101.111 |
80+
| Key Type | Description | OID |
81+
| ---------------------------------- | ------------------ | --------------------------- |
82+
| `'dh'` | Diffie-Hellman | 1.2.840.113549.1.3.1 |
83+
| `'dsa'` | DSA | 1.2.840.10040.4.1 |
84+
| `'ec'` | Elliptic curve | 1.2.840.10045.2.1 |
85+
| `'ed25519'` | Ed25519 | 1.3.101.112 |
86+
| `'ed448'` | Ed448 | 1.3.101.113 |
87+
| `'ml-dsa-44'`[^openssl35] | ML-DSA-44 | 2.16.840.1.101.3.4.3.17 |
88+
| `'ml-dsa-65'`[^openssl35] | ML-DSA-65 | 2.16.840.1.101.3.4.3.18 |
89+
| `'ml-dsa-87'`[^openssl35] | ML-DSA-87 | 2.16.840.1.101.3.4.3.19 |
90+
| `'ml-kem-1024'`[^openssl35] | ML-KEM-1024 | 2.16.840.1.101.3.4.4.3 |
91+
| `'ml-kem-512'`[^openssl35] | ML-KEM-512 | 2.16.840.1.101.3.4.4.1 |
92+
| `'ml-kem-768'`[^openssl35] | ML-KEM-768 | 2.16.840.1.101.3.4.4.2 |
93+
| `'rsa-pss'` | RSA PSS | 1.2.840.113549.1.1.10 |
94+
| `'rsa'` | RSA | 1.2.840.113549.1.1.1 |
95+
| `'slh-dsa-sha2-128f'`[^openssl35] | SLH-DSA-SHA2-128f | OID 2.16.840.1.101.3.4.3.21 |
96+
| `'slh-dsa-sha2-128s'`[^openssl35] | SLH-DSA-SHA2-128s | OID 2.16.840.1.101.3.4.3.22 |
97+
| `'slh-dsa-sha2-192f'`[^openssl35] | SLH-DSA-SHA2-192f | OID 2.16.840.1.101.3.4.3.23 |
98+
| `'slh-dsa-sha2-192s'`[^openssl35] | SLH-DSA-SHA2-192s | OID 2.16.840.1.101.3.4.3.24 |
99+
| `'slh-dsa-sha2-256f'`[^openssl35] | SLH-DSA-SHA2-256f | OID 2.16.840.1.101.3.4.3.25 |
100+
| `'slh-dsa-sha2-256s'`[^openssl35] | SLH-DSA-SHA2-256s | OID 2.16.840.1.101.3.4.3.26 |
101+
| `'slh-dsa-shake-128f'`[^openssl35] | SLH-DSA-SHAKE-128f | OID 2.16.840.1.101.3.4.3.27 |
102+
| `'slh-dsa-shake-128s'`[^openssl35] | SLH-DSA-SHAKE-128s | OID 2.16.840.1.101.3.4.3.28 |
103+
| `'slh-dsa-shake-192f'`[^openssl35] | SLH-DSA-SHAKE-192f | OID 2.16.840.1.101.3.4.3.29 |
104+
| `'slh-dsa-shake-192s'`[^openssl35] | SLH-DSA-SHAKE-192s | OID 2.16.840.1.101.3.4.3.30 |
105+
| `'slh-dsa-shake-256f'`[^openssl35] | SLH-DSA-SHAKE-256f | OID 2.16.840.1.101.3.4.3.31 |
106+
| `'slh-dsa-shake-256s'`[^openssl35] | SLH-DSA-SHAKE-256s | OID 2.16.840.1.101.3.4.3.32 |
107+
| `'x25519'` | X25519 | 1.3.101.110 |
108+
| `'x448'` | X448 | 1.3.101.111 |
97109

98110
## Class: `Certificate`
99111

@@ -2046,6 +2058,9 @@ Other key details might be exposed via this API using additional attributes.
20462058
<!-- YAML
20472059
added: v11.6.0
20482060
changes:
2061+
- version: REPLACEME
2062+
pr-url: https://github.com/nodejs/node/pull/59461
2063+
description: Add support for SLH-DSA keys.
20492064
- version: REPLACEME
20502065
pr-url: https://github.com/nodejs/node/pull/59461
20512066
description: Add support for ML-KEM keys.
@@ -3675,6 +3690,9 @@ underlying hash function. See [`crypto.createHmac()`][] for more information.
36753690
<!-- YAML
36763691
added: v10.12.0
36773692
changes:
3693+
- version: REPLACEME
3694+
pr-url: https://github.com/nodejs/node/pull/59461
3695+
description: Add support for SLH-DSA key pairs.
36783696
- version: REPLACEME
36793697
pr-url: https://github.com/nodejs/node/pull/59461
36803698
description: Add support for ML-KEM key pairs.
@@ -3800,6 +3818,9 @@ a `Promise` for an `Object` with `publicKey` and `privateKey` properties.
38003818
<!-- YAML
38013819
added: v10.12.0
38023820
changes:
3821+
- version: REPLACEME
3822+
pr-url: https://github.com/nodejs/node/pull/59461
3823+
description: Add support for SLH-DSA key pairs.
38033824
- version: REPLACEME
38043825
pr-url: https://github.com/nodejs/node/pull/59461
38053826
description: Add support for ML-KEM key pairs.
@@ -5455,6 +5476,9 @@ Throws an error if FIPS mode is not available.
54555476
<!-- YAML
54565477
added: v12.0.0
54575478
changes:
5479+
- version: REPLACEME
5480+
pr-url: https://github.com/nodejs/node/pull/59461
5481+
description: Add support for SLH-DSA signing.
54585482
- version: v24.6.0
54595483
pr-url: https://github.com/nodejs/node/pull/59259
54605484
description: Add support for ML-DSA signing.
@@ -5571,6 +5595,9 @@ not introduce timing vulnerabilities.
55715595
<!-- YAML
55725596
added: v12.0.0
55735597
changes:
5598+
- version: REPLACEME
5599+
pr-url: https://github.com/nodejs/node/pull/59461
5600+
description: Add support for SLH-DSA signature verification.
55745601
- version: v24.6.0
55755602
pr-url: https://github.com/nodejs/node/pull/59259
55765603
description: Add support for ML-DSA signature verification.

lib/internal/crypto/keygen.js

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ const {
2525
EVP_PKEY_ML_KEM_1024,
2626
EVP_PKEY_ML_KEM_512,
2727
EVP_PKEY_ML_KEM_768,
28+
EVP_PKEY_SLH_DSA_SHA2_128F,
29+
EVP_PKEY_SLH_DSA_SHA2_128S,
30+
EVP_PKEY_SLH_DSA_SHA2_192F,
31+
EVP_PKEY_SLH_DSA_SHA2_192S,
32+
EVP_PKEY_SLH_DSA_SHA2_256F,
33+
EVP_PKEY_SLH_DSA_SHA2_256S,
34+
EVP_PKEY_SLH_DSA_SHAKE_128F,
35+
EVP_PKEY_SLH_DSA_SHAKE_128S,
36+
EVP_PKEY_SLH_DSA_SHAKE_192F,
37+
EVP_PKEY_SLH_DSA_SHAKE_192S,
38+
EVP_PKEY_SLH_DSA_SHAKE_256F,
39+
EVP_PKEY_SLH_DSA_SHAKE_256S,
2840
EVP_PKEY_X25519,
2941
EVP_PKEY_X448,
3042
OPENSSL_EC_NAMED_CURVE,
@@ -168,7 +180,7 @@ function parseKeyEncoding(keyType, options = kEmptyObject) {
168180
];
169181
}
170182

171-
const ids = {
183+
const nidOnlyKeyPairs = {
172184
'ed25519': EVP_PKEY_ED25519,
173185
'ed448': EVP_PKEY_ED448,
174186
'x25519': EVP_PKEY_X25519,
@@ -179,6 +191,18 @@ const ids = {
179191
'ml-kem-512': EVP_PKEY_ML_KEM_512,
180192
'ml-kem-768': EVP_PKEY_ML_KEM_768,
181193
'ml-kem-1024': EVP_PKEY_ML_KEM_1024,
194+
'slh-dsa-sha2-128f': EVP_PKEY_SLH_DSA_SHA2_128F,
195+
'slh-dsa-sha2-128s': EVP_PKEY_SLH_DSA_SHA2_128S,
196+
'slh-dsa-sha2-192f': EVP_PKEY_SLH_DSA_SHA2_192F,
197+
'slh-dsa-sha2-192s': EVP_PKEY_SLH_DSA_SHA2_192S,
198+
'slh-dsa-sha2-256f': EVP_PKEY_SLH_DSA_SHA2_256F,
199+
'slh-dsa-sha2-256s': EVP_PKEY_SLH_DSA_SHA2_256S,
200+
'slh-dsa-shake-128f': EVP_PKEY_SLH_DSA_SHAKE_128F,
201+
'slh-dsa-shake-128s': EVP_PKEY_SLH_DSA_SHAKE_128S,
202+
'slh-dsa-shake-192f': EVP_PKEY_SLH_DSA_SHAKE_192F,
203+
'slh-dsa-shake-192s': EVP_PKEY_SLH_DSA_SHAKE_192S,
204+
'slh-dsa-shake-256f': EVP_PKEY_SLH_DSA_SHAKE_256F,
205+
'slh-dsa-shake-256s': EVP_PKEY_SLH_DSA_SHAKE_256S,
182206
};
183207

184208
function createJob(mode, type, options) {
@@ -293,22 +317,6 @@ function createJob(mode, type, options) {
293317
paramEncoding,
294318
...encoding);
295319
}
296-
case 'ed25519':
297-
case 'ed448':
298-
case 'x25519':
299-
case 'x448':
300-
case 'ml-dsa-44':
301-
case 'ml-dsa-65':
302-
case 'ml-dsa-87':
303-
case 'ml-kem-512':
304-
case 'ml-kem-768':
305-
case 'ml-kem-1024':
306-
{
307-
if (ids[type] === undefined) {
308-
throw new ERR_INVALID_ARG_VALUE('type', type, 'must be a supported key type');
309-
}
310-
return new NidKeyPairGenJob(mode, ids[type], ...encoding);
311-
}
312320
case 'dh':
313321
{
314322
validateObject(options, 'options');
@@ -347,10 +355,13 @@ function createJob(mode, type, options) {
347355
generator == null ? 2 : generator,
348356
...encoding);
349357
}
350-
default:
351-
// Fall through
358+
default: {
359+
if (nidOnlyKeyPairs[type] === undefined) {
360+
throw new ERR_INVALID_ARG_VALUE('type', type, 'must be a supported key type');
361+
}
362+
return new NidKeyPairGenJob(mode, nidOnlyKeyPairs[type], ...encoding);
363+
}
352364
}
353-
throw new ERR_INVALID_ARG_VALUE('type', type, 'must be a supported key type');
354365
}
355366

356367
// Symmetric Key Generation

src/crypto/crypto_keys.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,30 @@ Local<Value> KeyObjectHandle::GetAsymmetricKeyType() const {
984984
return env()->crypto_ml_kem_768_string();
985985
case EVP_PKEY_ML_KEM_1024:
986986
return env()->crypto_ml_kem_1024_string();
987+
case EVP_PKEY_SLH_DSA_SHA2_128F:
988+
return env()->crypto_slh_dsa_sha2_128f_string();
989+
case EVP_PKEY_SLH_DSA_SHA2_128S:
990+
return env()->crypto_slh_dsa_sha2_128s_string();
991+
case EVP_PKEY_SLH_DSA_SHA2_192F:
992+
return env()->crypto_slh_dsa_sha2_192f_string();
993+
case EVP_PKEY_SLH_DSA_SHA2_192S:
994+
return env()->crypto_slh_dsa_sha2_192s_string();
995+
case EVP_PKEY_SLH_DSA_SHA2_256F:
996+
return env()->crypto_slh_dsa_sha2_256f_string();
997+
case EVP_PKEY_SLH_DSA_SHA2_256S:
998+
return env()->crypto_slh_dsa_sha2_256s_string();
999+
case EVP_PKEY_SLH_DSA_SHAKE_128F:
1000+
return env()->crypto_slh_dsa_shake_128f_string();
1001+
case EVP_PKEY_SLH_DSA_SHAKE_128S:
1002+
return env()->crypto_slh_dsa_shake_128s_string();
1003+
case EVP_PKEY_SLH_DSA_SHAKE_192F:
1004+
return env()->crypto_slh_dsa_shake_192f_string();
1005+
case EVP_PKEY_SLH_DSA_SHAKE_192S:
1006+
return env()->crypto_slh_dsa_shake_192s_string();
1007+
case EVP_PKEY_SLH_DSA_SHAKE_256F:
1008+
return env()->crypto_slh_dsa_shake_256f_string();
1009+
case EVP_PKEY_SLH_DSA_SHAKE_256S:
1010+
return env()->crypto_slh_dsa_shake_256s_string();
9871011
#endif
9881012
default:
9891013
return Undefined(env()->isolate());
@@ -1267,6 +1291,18 @@ void Initialize(Environment* env, Local<Object> target) {
12671291
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_KEM_512);
12681292
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_KEM_768);
12691293
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_KEM_1024);
1294+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHA2_128F);
1295+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHA2_128S);
1296+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHA2_192F);
1297+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHA2_192S);
1298+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHA2_256F);
1299+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHA2_256S);
1300+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHAKE_128F);
1301+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHAKE_128S);
1302+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHAKE_192F);
1303+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHAKE_192S);
1304+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHAKE_256F);
1305+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_SLH_DSA_SHAKE_256S);
12701306
#endif
12711307
NODE_DEFINE_CONSTANT(target, EVP_PKEY_X25519);
12721308
NODE_DEFINE_CONSTANT(target, EVP_PKEY_X448);

src/env_properties.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@
121121
V(crypto_ml_kem_512_string, "ml-kem-512") \
122122
V(crypto_ml_kem_768_string, "ml-kem-768") \
123123
V(crypto_ml_kem_1024_string, "ml-kem-1024") \
124+
V(crypto_slh_dsa_sha2_128f_string, "slh-dsa-sha2-128f") \
125+
V(crypto_slh_dsa_sha2_128s_string, "slh-dsa-sha2-128s") \
126+
V(crypto_slh_dsa_sha2_192f_string, "slh-dsa-sha2-192f") \
127+
V(crypto_slh_dsa_sha2_192s_string, "slh-dsa-sha2-192s") \
128+
V(crypto_slh_dsa_sha2_256f_string, "slh-dsa-sha2-256f") \
129+
V(crypto_slh_dsa_sha2_256s_string, "slh-dsa-sha2-256s") \
130+
V(crypto_slh_dsa_shake_128f_string, "slh-dsa-shake-128f") \
131+
V(crypto_slh_dsa_shake_128s_string, "slh-dsa-shake-128s") \
132+
V(crypto_slh_dsa_shake_192f_string, "slh-dsa-shake-192f") \
133+
V(crypto_slh_dsa_shake_192s_string, "slh-dsa-shake-192s") \
134+
V(crypto_slh_dsa_shake_256f_string, "slh-dsa-shake-256f") \
135+
V(crypto_slh_dsa_shake_256s_string, "slh-dsa-shake-256s") \
124136
V(crypto_x25519_string, "x25519") \
125137
V(crypto_x448_string, "x448") \
126138
V(crypto_rsa_string, "rsa") \

0 commit comments

Comments
 (0)