Commit 618f7934644 for nodejs

commit 618f7934644cb96d0419af4cb61d3505febb3554
Author: Filip Skokan <panva.ip@gmail.com>
Date:   Tue Sep 22 22:29:27 2026 +0200

    crypto: report actual RSA modulus lengths

    Use the generated key's modulus size for both CryptoKey algorithm
    objects. Preserve successful backend generation when it rounds the
    requested size, keeping metadata consistent across export and cloning.

    Signed-off-by: Filip Skokan <panva.ip@gmail.com>
    Assisted-by: Codex
    PR-URL: https://github.com/nodejs/node/pull/66237
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Aviv Keller <me@aviv.sh>

diff --git a/lib/internal/crypto/rsa.js b/lib/internal/crypto/rsa.js
index 767c5e14507..8fa3ecdff1b 100644
--- a/lib/internal/crypto/rsa.js
+++ b/lib/internal/crypto/rsa.js
@@ -32,6 +32,7 @@ const {
   bigIntArrayToUnsignedInt,
   getUsagesMask,
   jobPromise,
+  jobPromiseThen,
   normalizeHashName,
   validateAlgorithm,
   validateMaxBufferLength,
@@ -132,7 +133,7 @@ function rsaKeyGenerate(
   const keyUsages = getKeyPairUsages(usagesSet, allowedUsages);
   validateUsagesNotEmpty(keyUsages.private);

-  return jobPromise(() => new RsaKeyPairGenJob(
+  return jobPromiseThen(jobPromise(() => new RsaKeyPairGenJob(
     kCryptoJobWebCrypto,
     kKeyVariantRSA_SSA_PKCS1_v1_5,
     modulusLength,
@@ -140,7 +141,13 @@ function rsaKeyGenerate(
     keyAlgorithm,
     getUsagesMask(keyUsages.public),
     getUsagesMask(keyUsages.private),
-    extractable));
+    extractable)), (result) => {
+    const { modulusLength: actualModulusLength } =
+      getCryptoKeyHandle(result.publicKey).keyDetail({ __proto__: null });
+    getCryptoKeyAlgorithm(result.publicKey).modulusLength = actualModulusLength;
+    getCryptoKeyAlgorithm(result.privateKey).modulusLength = actualModulusLength;
+    return result;
+  });
 }

 function rsaExportKey(key, format) {
diff --git a/test/parallel/test-webcrypto-rsa-modulus-length.js b/test/parallel/test-webcrypto-rsa-modulus-length.js
new file mode 100644
index 00000000000..72032ed1a44
--- /dev/null
+++ b/test/parallel/test-webcrypto-rsa-modulus-length.js
@@ -0,0 +1,47 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const assert = require('assert');
+const { generateKeyPairSync, KeyObject } = require('crypto');
+const { subtle } = globalThis.crypto;
+
+(async () => {
+  for (const name of ['RSA-PSS', 'RSASSA-PKCS1-v1_5', 'RSA-OAEP']) {
+    const usages = name === 'RSA-OAEP' ? ['encrypt', 'decrypt'] : ['sign', 'verify'];
+    for (const modulusLength of [1025, 2048, 2049]) {
+      let pair;
+      try {
+        pair = await subtle.generateKey({
+          name, modulusLength, hash: 'SHA-256', publicExponent: new Uint8Array([1, 0, 1]),
+        }, true, usages);
+      } catch (err) {
+        if (modulusLength === 2048 || err.name !== 'OperationError')
+          throw err;
+        // Only reject sizes the backend also rejects. Some backends round
+        // the requested size, which must still produce a usable CryptoKey.
+        assert.throws(() => generateKeyPairSync('rsa', { modulusLength }),
+                      { name: 'Error' });
+        continue;
+      }
+      const actualModulusLength =
+        KeyObject.from(pair.publicKey).asymmetricKeyDetails.modulusLength;
+      for (const key of [pair.publicKey, pair.privateKey]) {
+        assert.strictEqual(key.algorithm.modulusLength, actualModulusLength);
+        assert.strictEqual(
+          KeyObject.from(key).asymmetricKeyDetails.modulusLength, actualModulusLength);
+        assert.deepStrictEqual(structuredClone(key).algorithm, key.algorithm);
+
+        const format = key.type === 'public' ? 'spki' : 'pkcs8';
+        const imported = await subtle.importKey(
+          format, await subtle.exportKey(format, key),
+          { name, hash: 'SHA-256' }, true, key.usages);
+        assert.deepStrictEqual(imported.algorithm, key.algorithm);
+      }
+      const publicKey = await subtle.getPublicKey(pair.privateKey, pair.publicKey.usages);
+      assert.deepStrictEqual(publicKey.algorithm, pair.publicKey.algorithm);
+    }
+  }
+})().then(common.mustCall());