Commit 5af55e612c1 for nodejs

commit 5af55e612c1c0fb21def18aa5114c7d554668443
Author: Filip Skokan <panva.ip@gmail.com>
Date:   Tue Sep 22 22:27:08 2026 +0200

    crypto: minimize RSA public exponent metadata

    Omit leading zero octets from generated CryptoKey publicExponent
    values, matching the BigInteger representation.

    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 56c58bf1262..767c5e14507 100644
--- a/lib/internal/crypto/rsa.js
+++ b/lib/internal/crypto/rsa.js
@@ -2,6 +2,8 @@

 const {
   TypedArrayPrototypeGetBuffer,
+  TypedArrayPrototypeGetByteOffset,
+  TypedArrayPrototypeGetLength,
   Uint8Array,
 } = primordials;

@@ -113,11 +115,17 @@ function rsaKeyGenerate(
   const usagesSet = validateKeyUsages(usages, allowedUsages.keygen, name);
   validateAlgorithm(algorithm, 'generateKey');
   const publicExponentConverted = bigIntArrayToUnsignedInt(publicExponent);
+  let firstNonzeroByte = 0;
+  while (publicExponent[firstNonzeroByte] === 0)
+    firstNonzeroByte++;

   const keyAlgorithm = {
     name,
     modulusLength,
-    publicExponent,
+    publicExponent: new Uint8Array(
+      TypedArrayPrototypeGetBuffer(publicExponent),
+      TypedArrayPrototypeGetByteOffset(publicExponent) + firstNonzeroByte,
+      TypedArrayPrototypeGetLength(publicExponent) - firstNonzeroByte),
     hash,
   };

diff --git a/test/parallel/test-webcrypto-rsa-exponent-length.js b/test/parallel/test-webcrypto-rsa-exponent-length.js
new file mode 100644
index 00000000000..c227154c7a1
--- /dev/null
+++ b/test/parallel/test-webcrypto-rsa-exponent-length.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+  common.skip('missing crypto');
+
+const assert = require('assert');
+const { getFips } = require('crypto');
+const { subtle } = globalThis.crypto;
+
+(async () => {
+  const exponents = getFips() ? [[1, 0, 1]] : [[3], [1, 0, 1]];
+  for (const name of ['RSA-PSS', 'RSASSA-PKCS1-v1_5', 'RSA-OAEP']) {
+    const usages = name === 'RSA-OAEP' ? ['encrypt', 'decrypt'] : ['sign', 'verify'];
+    for (const exponent of exponents) {
+      const publicExponent = new Uint8Array([0, 0, 0, 0, ...exponent]);
+      const pair = await subtle.generateKey({
+        name, modulusLength: 2048, publicExponent, hash: 'SHA-256',
+      }, true, usages);
+      for (const key of [pair.publicKey, pair.privateKey]) {
+        assert.deepStrictEqual(key.algorithm.publicExponent, new Uint8Array(exponent));
+      }
+      assert.deepStrictEqual(publicExponent, new Uint8Array([0, 0, 0, 0, ...exponent]));
+    }
+  }
+})().then(common.mustCall());