From a5d72689a8f9f6dab278025824f6e7950d8c4f46 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 11 Aug 2025 10:12:44 +0200 Subject: [PATCH 1/2] crypto: support Ed448 and ML-DSA context parameter in Web Cryptography --- deps/ncrypto/ncrypto.cc | 48 +++++++ deps/ncrypto/ncrypto.h | 9 ++ doc/api/webcrypto.md | 44 ++----- lib/internal/crypto/cfrg.js | 1 + lib/internal/crypto/ec.js | 1 + lib/internal/crypto/ml_dsa.js | 1 + lib/internal/crypto/rsa.js | 1 + lib/internal/crypto/sig.js | 5 +- lib/internal/crypto/util.js | 5 +- lib/internal/crypto/webidl.js | 34 +++-- src/crypto/crypto_sig.cc | 72 ++++++++++- src/crypto/crypto_sig.h | 7 +- test/fixtures/crypto/eddsa.js | 45 ++++--- test/fixtures/crypto/ml-dsa.js | 44 +++++-- test/fixtures/webcrypto/supports-level-2.mjs | 27 +--- .../webcrypto/supports-modern-algorithms.mjs | 6 + .../webcrypto/supports-secure-curves.mjs | 11 ++ .../test-webcrypto-sign-verify-eddsa.js | 121 +++++++++++------- .../test-webcrypto-sign-verify-ml-dsa.js | 83 ++++++------ test/parallel/test-webcrypto-webidl.js | 4 +- tools/doc/type-parser.mjs | 1 - 21 files changed, 363 insertions(+), 207 deletions(-) diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc index c94f0725bd3d05..6d7bee31c597c5 100644 --- a/deps/ncrypto/ncrypto.cc +++ b/deps/ncrypto/ncrypto.cc @@ -4288,6 +4288,54 @@ std::optional EVPMDCtxPointer::verifyInit( return ctx; } +std::optional EVPMDCtxPointer::signInitWithContext( + const EVPKeyPointer& key, + const Digest& digest, + const Buffer& context_string) { +#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING + EVP_PKEY_CTX* ctx = nullptr; + + const OSSL_PARAM params[] = { + OSSL_PARAM_construct_octet_string( + OSSL_SIGNATURE_PARAM_CONTEXT_STRING, + const_cast(context_string.data), + context_string.len), + OSSL_PARAM_END}; + + if (!EVP_DigestSignInit_ex( + ctx_.get(), &ctx, nullptr, nullptr, nullptr, key.get(), params)) { + return std::nullopt; + } + return ctx; +#else + return std::nullopt; +#endif +} + +std::optional EVPMDCtxPointer::verifyInitWithContext( + const EVPKeyPointer& key, + const Digest& digest, + const Buffer& context_string) { +#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING + EVP_PKEY_CTX* ctx = nullptr; + + const OSSL_PARAM params[] = { + OSSL_PARAM_construct_octet_string( + OSSL_SIGNATURE_PARAM_CONTEXT_STRING, + const_cast(context_string.data), + context_string.len), + OSSL_PARAM_END}; + + if (!EVP_DigestVerifyInit_ex( + ctx_.get(), &ctx, nullptr, nullptr, nullptr, key.get(), params)) { + return std::nullopt; + } + return ctx; +#else + return std::nullopt; +#endif +} + DataPointer EVPMDCtxPointer::signOneShot( const Buffer& buf) const { if (!ctx_) return {}; diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h index 14f5c1170a81e5..bee96ba78347ae 100644 --- a/deps/ncrypto/ncrypto.h +++ b/deps/ncrypto/ncrypto.h @@ -1409,6 +1409,15 @@ class EVPMDCtxPointer final { std::optional verifyInit(const EVPKeyPointer& key, const Digest& digest); + std::optional signInitWithContext( + const EVPKeyPointer& key, + const Digest& digest, + const Buffer& context_string); + std::optional verifyInitWithContext( + const EVPKeyPointer& key, + const Digest& digest, + const Buffer& context_string); + DataPointer signOneShot(const Buffer& buf) const; DataPointer sign(const Buffer& buf) const; bool verify(const Buffer& buf, diff --git a/doc/api/webcrypto.md b/doc/api/webcrypto.md index d65db1e815042c..d8a5ecd3f44a57 100644 --- a/doc/api/webcrypto.md +++ b/doc/api/webcrypto.md @@ -1342,7 +1342,7 @@ changes: -* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params|ContextParams|KmacParams} +* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|ContextParams|KmacParams} * `key` {CryptoKey} * `data` {ArrayBuffer|TypedArray|DataView|Buffer} * Returns: {Promise} Fulfills with an {ArrayBuffer} upon success. @@ -1463,7 +1463,7 @@ changes: -* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|Ed448Params|ContextParams} +* `algorithm` {string|Algorithm|RsaPssParams|EcdsaParams|ContextParams|KmacParams} * `key` {CryptoKey} * `signature` {ArrayBuffer|TypedArray|DataView|Buffer} * `data` {ArrayBuffer|TypedArray|DataView|Buffer} @@ -1830,20 +1830,23 @@ added: v24.7.0 added: v24.7.0 --> -* Type: {string} Must be `'ML-DSA-44'`[^modern-algos], `'ML-DSA-65'`[^modern-algos], or `'ML-DSA-87'`[^modern-algos]. +* Type: {string} Must be `Ed448`[^secure-curves], `'ML-DSA-44'`[^modern-algos], + `'ML-DSA-65'`[^modern-algos], or `'ML-DSA-87'`[^modern-algos]. #### `contextParams.context` * Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined} The `context` member represents the optional context data to associate with the message. -The Node.js Web Crypto API implementation only supports zero-length context -which is equivalent to not providing context at all. ### Class: `CShakeParams` @@ -2024,37 +2027,6 @@ added: v15.0.0 * Type: {string} Must be one of `'P-256'`, `'P-384'`, `'P-521'`. -### Class: `Ed448Params` - - - -#### `ed448Params.name` - - - -* Type: {string} Must be `'Ed448'`[^secure-curves]. - -#### `ed448Params.context` - - - -* Type: {ArrayBuffer|TypedArray|DataView|Buffer|undefined} - -The `context` member represents the optional context data to associate with -the message. -The Node.js Web Crypto API implementation only supports zero-length context -which is equivalent to not providing context at all. - ### Class: `EncapsulatedBits`