From a2550bee45fbc73257e3f4dbbdeb716d852d663d Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Tue, 2 Sep 2025 08:42:16 +0000 Subject: [PATCH] Add detailed comment explaining OpenSSL v3 default digest behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds comprehensive documentation in the code explaining: - How OpenSSL v3 provides SHA256 as the default digest for RSA keys - The exact source code locations in OpenSSL where this happens - Why BoringSSL behaves differently (no automatic default) - Why this fix is necessary for Node.js compatibility The comment includes specific file paths and line numbers from OpenSSL v3 source code for future reference and maintenance. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../bindings/node/crypto/CryptoSignJob.cpp | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/bun.js/bindings/node/crypto/CryptoSignJob.cpp b/src/bun.js/bindings/node/crypto/CryptoSignJob.cpp index 242f987708..9af8d62e45 100644 --- a/src/bun.js/bindings/node/crypto/CryptoSignJob.cpp +++ b/src/bun.js/bindings/node/crypto/CryptoSignJob.cpp @@ -350,11 +350,47 @@ std::optional SignJobCtx::fromJS(JSGlobalObject* globalObject, Throw return {}; } } else { - // When no algorithm is specified, use a default for RSA keys - // Ed25519/Ed448 (one-shot variants) don't need a digest + // OpenSSL v3 Default Digest Behavior for RSA Keys + // ================================================ + // When Node.js calls crypto.sign() or crypto.verify() with a null/undefined algorithm, + // it passes NULL to OpenSSL's EVP_DigestSignInit/EVP_DigestVerifyInit functions. + // + // OpenSSL v3 then automatically provides a default digest for RSA keys through the + // following mechanism: + // + // 1. In crypto/evp/m_sigver.c:215-220 (do_sigver_init function): + // When mdname is NULL and type is NULL, OpenSSL calls: + // evp_keymgmt_util_get_deflt_digest_name(tmp_keymgmt, provkey, locmdname, sizeof(locmdname)) + // + // 2. In crypto/evp/keymgmt_lib.c:533-571 (evp_keymgmt_util_get_deflt_digest_name function): + // This queries the key management provider for OSSL_PKEY_PARAM_DEFAULT_DIGEST + // + // 3. In providers/implementations/keymgmt/rsa_kmgmt.c: + // - Line 54: #define RSA_DEFAULT_MD "SHA256" + // - Lines 351-355: For RSA keys (non-PSS), it returns RSA_DEFAULT_MD ("SHA256") + // if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL + // && (rsa_type != RSA_FLAG_TYPE_RSASSAPSS + // || ossl_rsa_pss_params_30_is_unrestricted(pss_params))) { + // if (!OSSL_PARAM_set_utf8_string(p, RSA_DEFAULT_MD)) + // return 0; + // } + // + // BoringSSL Difference: + // ===================== + // BoringSSL (used by Bun) does not have this automatic default mechanism. + // When NULL is passed as the digest to EVP_DigestVerifyInit for RSA keys, + // BoringSSL returns error 0x06000077 (NO_DEFAULT_DIGEST). + // + // This Fix: + // ========= + // To achieve Node.js/OpenSSL compatibility, we explicitly set SHA256 as the + // default digest for RSA keys when no algorithm is specified, matching the + // OpenSSL behavior documented above. + // + // For Ed25519/Ed448 keys (one-shot variants), we intentionally leave digest + // as null since these algorithms perform their own hashing internally and + // don't require a separate digest algorithm. if (keyObject.asymmetricKey().isRsaVariant()) { - // Use SHA256 as default for RSA keys when no algorithm is specified - // This matches Node.js behavior for crypto.verify with null algorithm digest = Digest::FromName("SHA256"_s); } }