Skip to content

Commit 4b631be

Browse files
panvatargos
authored andcommitted
crypto: support Ed448 and ML-DSA context parameter in Web Cryptography
PR-URL: #59570 Reviewed-By: James M Snell <[email protected]>
1 parent 6f79450 commit 4b631be

File tree

21 files changed

+363
-207
lines changed

21 files changed

+363
-207
lines changed

‎deps/ncrypto/ncrypto.cc‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4288,6 +4288,54 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInit(
42884288
return ctx;
42894289
}
42904290

4291+
std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInitWithContext(
4292+
const EVPKeyPointer& key,
4293+
const Digest& digest,
4294+
const Buffer<constunsignedchar>& context_string){
4295+
#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING
4296+
EVP_PKEY_CTX* ctx = nullptr;
4297+
4298+
const OSSL_PARAM params[] ={
4299+
OSSL_PARAM_construct_octet_string(
4300+
OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
4301+
const_cast<unsignedchar*>(context_string.data),
4302+
context_string.len),
4303+
OSSL_PARAM_END};
4304+
4305+
if (!EVP_DigestSignInit_ex(
4306+
ctx_.get(), &ctx, nullptr, nullptr, nullptr, key.get(), params)){
4307+
return std::nullopt;
4308+
}
4309+
return ctx;
4310+
#else
4311+
return std::nullopt;
4312+
#endif
4313+
}
4314+
4315+
std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInitWithContext(
4316+
const EVPKeyPointer& key,
4317+
const Digest& digest,
4318+
const Buffer<constunsignedchar>& context_string){
4319+
#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING
4320+
EVP_PKEY_CTX* ctx = nullptr;
4321+
4322+
const OSSL_PARAM params[] ={
4323+
OSSL_PARAM_construct_octet_string(
4324+
OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
4325+
const_cast<unsignedchar*>(context_string.data),
4326+
context_string.len),
4327+
OSSL_PARAM_END};
4328+
4329+
if (!EVP_DigestVerifyInit_ex(
4330+
ctx_.get(), &ctx, nullptr, nullptr, nullptr, key.get(), params)){
4331+
return std::nullopt;
4332+
}
4333+
return ctx;
4334+
#else
4335+
return std::nullopt;
4336+
#endif
4337+
}
4338+
42914339
DataPointer EVPMDCtxPointer::signOneShot(
42924340
const Buffer<constunsignedchar>& buf) const{
42934341
if (!ctx_) return{};

‎deps/ncrypto/ncrypto.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,15 @@ class EVPMDCtxPointer final{
14091409
std::optional<EVP_PKEY_CTX*> verifyInit(const EVPKeyPointer& key,
14101410
const Digest& digest);
14111411

1412+
std::optional<EVP_PKEY_CTX*> signInitWithContext(
1413+
const EVPKeyPointer& key,
1414+
const Digest& digest,
1415+
const Buffer<constunsignedchar>& context_string);
1416+
std::optional<EVP_PKEY_CTX*> verifyInitWithContext(
1417+
const EVPKeyPointer& key,
1418+
const Digest& digest,
1419+
const Buffer<constunsignedchar>& context_string);
1420+
14121421
DataPointer signOneShot(const Buffer<constunsignedchar>& buf) const;
14131422
DataPointer sign(const Buffer<constunsignedchar>& buf) const;
14141423
boolverify(const Buffer<constunsignedchar>& buf,

‎doc/api/webcrypto.md‎

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,7 @@ changes:
13411341
13421342
<!--lint disable maximum-line-length remark-lint-->
13431343
1344-
* `algorithm`{string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params|ContextParams|KmacParams}
1344+
* `algorithm`{string|Algorithm|RsaPssParams|EcdsaParams|ContextParams|KmacParams}
13451345
* `key`{CryptoKey}
13461346
* `data`{ArrayBuffer|TypedArray|DataView|Buffer}
13471347
* Returns:{Promise} Fulfills with an{ArrayBuffer} upon success.
@@ -1462,7 +1462,7 @@ changes:
14621462
14631463
<!--lint disable maximum-line-length remark-lint-->
14641464
1465-
* `algorithm`{string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params|ContextParams}
1465+
* `algorithm`{string|Algorithm|RsaPssParams|EcdsaParams|ContextParams|KmacParams}
14661466
* `key`{CryptoKey}
14671467
* `signature`{ArrayBuffer|TypedArray|DataView|Buffer}
14681468
* `data`{ArrayBuffer|TypedArray|DataView|Buffer}
@@ -1829,20 +1829,23 @@ added: v24.7.0
18291829
added: v24.7.0
18301830
-->
18311831
1832-
* Type:{string} Must be `'ML-DSA-44'`[^modern-algos], `'ML-DSA-65'`[^modern-algos], or `'ML-DSA-87'`[^modern-algos].
1832+
* Type:{string} Must be `Ed448`[^secure-curves], `'ML-DSA-44'`[^modern-algos],
1833+
`'ML-DSA-65'`[^modern-algos], or `'ML-DSA-87'`[^modern-algos].
18331834
18341835
#### `contextParams.context`
18351836
18361837
<!-- YAML
18371838
added: v24.7.0
1839+
changes:
1840+
- version: REPLACEME
1841+
pr-url: https://github.com/nodejs/node/pull/59570
1842+
description: Non-empty context is now supported.
18381843
-->
18391844
18401845
* Type:{ArrayBuffer|TypedArray|DataView|Buffer|undefined}
18411846
18421847
The `context` member represents the optional context data to associate with
18431848
the message.
1844-
The Node.js Web Crypto API implementation only supports zero-length context
1845-
which is equivalent to not providing context at all.
18461849
18471850
### Class: `CShakeParams`
18481851
@@ -2023,37 +2026,6 @@ added: v15.0.0
20232026
20242027
* Type:{string} Must be one of `'P-256'`, `'P-384'`, `'P-521'`.
20252028
2026-
### Class: `Ed448Params`
2027-
2028-
<!-- YAML
2029-
added: v15.0.0
2030-
-->
2031-
2032-
#### `ed448Params.name`
2033-
2034-
<!-- YAML
2035-
added:
2036-
- v18.4.0
2037-
- v16.17.0
2038-
-->
2039-
2040-
* Type:{string} Must be `'Ed448'`[^secure-curves].
2041-
2042-
#### `ed448Params.context`
2043-
2044-
<!-- YAML
2045-
added:
2046-
- v18.4.0
2047-
- v16.17.0
2048-
-->
2049-
2050-
* Type:{ArrayBuffer|TypedArray|DataView|Buffer|undefined}
2051-
2052-
The `context` member represents the optional context data to associate with
2053-
the message.
2054-
The Node.js Web Crypto API implementation only supports zero-length context
2055-
which is equivalent to not providing context at all.
2056-
20572029
### Class: `EncapsulatedBits`
20582030
20592031
<!-- YAML

‎lib/internal/crypto/cfrg.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ function eddsaSignVerify(key, data, algorithm, signature){
359359
undefined,
360360
undefined,
361361
undefined,
362+
algorithm.name==='Ed448' ? algorithm.context : undefined,
362363
signature));
363364
}
364365

‎lib/internal/crypto/ec.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ function ecdsaSignVerify(key, data,{name, hash }, signature){
302302
undefined,// Salt length, not used with ECDSA
303303
undefined,// PSS Padding, not used with ECDSA
304304
kSigEncP1363,
305+
undefined,
305306
signature));
306307
}
307308

‎lib/internal/crypto/ml_dsa.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ function mlDsaSignVerify(key, data, algorithm, signature){
303303
undefined,
304304
undefined,
305305
undefined,
306+
algorithm.context,
306307
signature));
307308
}
308309

‎lib/internal/crypto/rsa.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ function rsaSignVerify(key, data,{saltLength }, signature){
355355
saltLength,
356356
key[kAlgorithm].name==='RSA-PSS' ? RSA_PKCS1_PSS_PADDING : undefined,
357357
undefined,
358+
undefined,
358359
signature);
359360
});
360361
}

‎lib/internal/crypto/sig.js‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ function signOneShot(algorithm, data, key, callback){
171171
algorithm,
172172
pssSaltLength,
173173
rsaPadding,
174-
dsaSigEnc);
174+
dsaSigEnc,
175+
undefined,
176+
undefined);
175177

176178
if(!callback){
177179
const{0: err,1: signature}=job.run();
@@ -276,6 +278,7 @@ function verifyOneShot(algorithm, data, key, signature, callback){
276278
pssSaltLength,
277279
rsaPadding,
278280
dsaSigEnc,
281+
undefined,
279282
signature);
280283

281284
if(!callback){

‎lib/internal/crypto/util.js‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ const kAlgorithmDefinitions ={
268268
'generateKey': null,
269269
'exportKey': null,
270270
'importKey': null,
271-
'sign': 'Ed448Params',
272-
'verify': 'Ed448Params',
271+
'sign': 'ContextParams',
272+
'verify': 'ContextParams',
273273
},
274274
'HKDF': {
275275
'importKey': null,
@@ -494,7 +494,6 @@ const simpleAlgorithmDictionaries ={
494494
salt: 'BufferSource',
495495
info: 'BufferSource',
496496
},
497-
Ed448Params: {context: 'BufferSource'},
498497
ContextParams: {context: 'BufferSource'},
499498
Pbkdf2Params: {hash: 'HashAlgorithmIdentifier',salt: 'BufferSource'},
500499
RsaOaepParams: {label: 'BufferSource'},

‎lib/internal/crypto/webidl.js‎

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const{
1919
MathTrunc,
2020
Number,
2121
NumberIsFinite,
22+
NumberParseInt,
2223
ObjectPrototypeHasOwnProperty,
2324
ObjectPrototypeIsPrototypeOf,
2425
SafeArrayIterator,
@@ -304,13 +305,12 @@ function createDictionaryConverter(name, dictionaries){
304305
constcontext=`'${key}' of '${name}'${
305306
opts.context ? ` (${opts.context})` : ''
306307
}`;
307-
const{ converter, validator }=member;
308-
constidlMemberValue=converter(esMemberValue,{
308+
constidlMemberValue=member.converter(esMemberValue,{
309309
__proto__: null,
310310
...opts,
311311
context,
312312
});
313-
validator?.(idlMemberValue,esDict);
313+
member.validator?.(idlMemberValue,esDict);
314314
setOwnProperty(idlDict,key,idlMemberValue);
315315
}elseif(member.required){
316316
throwmakeException(
@@ -769,17 +769,25 @@ converters.EcdhKeyDeriveParams = createDictionaryConverter(
769769
},
770770
]);
771771

772-
for(constnameof['Ed448Params','ContextParams']){
773-
converters[name]=createDictionaryConverter(
774-
name,[
775-
...newSafeArrayIterator(dictAlgorithm),
776-
{
777-
key: 'context',
778-
converter: converters.BufferSource,
779-
validator: validateZeroLength(`${name}.context`),
772+
converters.ContextParams=createDictionaryConverter(
773+
'ContextParams',[
774+
...newSafeArrayIterator(dictAlgorithm),
775+
{
776+
key: 'context',
777+
converter: converters.BufferSource,
778+
validator(V,dict){
779+
let{0: major,1: minor}=process.versions.openssl.split('.');
780+
major=NumberParseInt(major,10);
781+
minor=NumberParseInt(minor,10);
782+
if(major>3||(major===3&&minor>=2)){
783+
this.validator=undefined;
784+
}else{
785+
this.validator=validateZeroLength('ContextParams.context');
786+
this.validator(V,dict);
787+
}
780788
},
781-
]);
782-
}
789+
},
790+
]);
783791

784792
converters.Argon2Params=createDictionaryConverter(
785793
'Argon2Params',[

0 commit comments

Comments
(0)