Repository navigation
Conversation
…erywhere JsonWebKey.key_ops is sequence<DOMString> in the WebCrypto IDL. RFC 7517 section 4.3 allows key_ops values that are not WebCrypto usages, and the jwk import steps only require key_ops to contain the requested usages. The dictionary converted the member as sequence<KeyUsage>, so a JWK with a foreign or non-string key_ops entry failed with a TypeError before the import algorithm ran. Node and Chromium import such keys. key_ops is now a Vector<String>. normalizeJsonWebKey builds the usages bitmap from the entries that name a KeyUsage and skips the rest. hasDuplicateJwkKeyOps compares the strings, so it also catches repeated unknown values, and the AES, RSA, EC and OKP importers now call it too. Before, only HMAC, ChaCha20-Poly1305 and AKP rejected duplicates.
Add CryptoAlgorithm::validateJwkKeyOps, which rejects duplicate key_ops entries and key_ops that do not cover the requested usages with Node's "Duplicate key operation" and "Key operations and usage mismatch" DataError messages. Every jwk import branch calls it after the use check. HMAC, ChaCha20-Poly1305 and AKP already reported these messages inline; AES, RSA, EC and OKP reported the generic DataError. Upstream Node tests assert the messages for EC, RSA and CFRG keys.
|
Reproduction (main 3f3a9ff, compare with const S = crypto.subtle;
const jwk = { kty: "oct", k: "AAECAwQFBgcICQoLDA0ODw" };
const run = members =>
S.importKey("jwk", { ...jwk, ...members }, "AES-GCM", true, ["encrypt"]).then(
k => "imported " + JSON.stringify(k.usages),
e => e.name + ": " + e.message,
);
for (const key_ops of [["encrypt","fly"], ["encrypt","deriveBits","x-custom"], [1,"encrypt"], ["encrypt",null], ["fly"], ["encrypt","fly","fly"], ["encrypt","encrypt"]]) {
console.log(JSON.stringify(key_ops).padEnd(36), await run({ key_ops }));
}
console.log("oth: [{}]".padEnd(36), await run({ oth: [{}] }));
The CI. The red tests on this PR are in the AOT suite: 40 files under |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
JWK representation and normalization src/jsc/bindings/webcrypto/JsonWebKey.idl, src/jsc/bindings/webcrypto/JSJsonWebKey.cpp, src/jsc/bindings/webcrypto/JsonWebKey.h, src/jsc/bindings/webcrypto/JSCryptoKeyUsage.*, src/jsc/bindings/webcrypto/SubtleCrypto.cpp |
key_ops uses strings instead of enum values. Normalization retains the entries and sets usage bits for recognized values. Duplicate detection checks repeated strings. |
Algorithm import checks and export serialization src/jsc/bindings/webcrypto/CryptoAlgorithmAKPShared.h, src/jsc/bindings/webcrypto/CryptoAlgorithmChaCha20Poly1305.cpp, src/jsc/bindings/webcrypto/CryptoAlgorithmHMAC.cpp, src/jsc/bindings/webcrypto/CryptoKey*.cpp, src/jsc/bindings/webcrypto/SubtleCrypto.cpp |
Algorithm imports pass the full JWK to duplicate detection. Key exports convert usage bitmaps to JWK operation strings. Import and unwrap paths move converted JWK data. |
JWK behavior tests and benchmarks test/js/web/crypto/web-crypto.test.ts, test/js/node/test/parallel/test-webcrypto-key-ops-duplicates.js, bench/snippets/webcrypto-keys.mjs |
Tests cover unknown and duplicate operations, conversion, import, unwrap, and export behavior across key types. The benchmark snippet covers key import, unwrap, export, and generation. |
RSA other-prime dictionary conversion
| Layer / File(s) | Summary |
|---|---|
Optional RSA other-prime fields src/jsc/bindings/webcrypto/RsaOtherPrimesInfo.idl, src/jsc/bindings/webcrypto/JSRsaOtherPrimesInfo.cpp, test/js/web/crypto/web-crypto.test.ts |
The r, d, and t fields are no longer required. Tests cover missing fields during AES and RSA imports. |
Suggested reviewers: cirospaciari, dylan-conway
Merge Risk: 
Minimal · up to fd64a
-
No concrete merge-blocking issue is established for the JWK conversion changes. Merge readiness remains subject to normal build and test checks.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description is thorough and follows the repository template. It has a 'What does this PR do?' equivalent (Problem, Fix, Background, Downsides sections) and a 'How did you verify your code works?' equivalent (the Verified bullets, test results, the fail-on-main and pass-on-PR gate evidence, and the Node test file). It states the behavior change clearly: key_ops entries that are not KeyUsage values are now accepted when requested usages are present, and oth entries convert without r, d, or t. It also covers the trade-offs, including the export cost, the intentional divergence from WebKit, and the remaining unwrapKey differences. The main weakness is length and density. Much of the detail sits in a collapsed Notes section, so a reviewer must read a lot to find the core rationale. This does not make the description incomplete.
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
|
Status: the automated review reported no actionable findings, so there is nothing to change from it. The |
|
Status: the edited automated review still has no actionable findings. The fail-before/pass-after gate passed on ASAN and release builds. Buildkite #113400 is at 170 of 181 jobs passed with none failed so far. |
There was a problem hiding this comment.
I reviewed this PR and didn't find any bugs. Because it retypes a WebCrypto IDL member and touches key-import validation across every algorithm — deliberately diverging from upstream WebKit — a human look would still be worthwhile.
What was reviewed:
- Grepped
case CryptoKeyFormat::Jwk— all 15 JWK import branches now callvalidateJwkKeyOps; all 7exportJwk()sites usetoJwkKeyOps(), none missed. HashSet<String>inhasDuplicateJwkKeyOps:IDLDOMStringconversion never yields a nullWTF::String, and empty""is a valid entry (WTF uses null/HashTableDeletedValueas the sentinel slots), sokey_ops: ["", ""]is handled without tripping a hash-table assertion.- The two updated leak-regression tests:
key_ops: "sign"still throws insideconvert<IDLSequence<...>>inconvertDictionary<JsonWebKey>, so the same DeferredPromise conversion-exception branch is exercised. parseEnumerationFromString<CryptoKeyUsage>follows the existingBufferEncodingTypespecialization pattern; the base template is already declared inJSDOMConvertEnumeration.h.
Extended reasoning...
Overview
This PR retypes JsonWebKey.key_ops from sequence<CryptoKeyUsage> to sequence<DOMString> so JWKs carrying JOSE-defined or vendor key_ops values (permitted by RFC 7517 §4.3 and by the actual W3C WebCrypto IDL) no longer TypeError during dictionary conversion. It extracts a shared static CryptoAlgorithm::validateJwkKeyOps() (duplicate check via HashSet<String>, then usages-cover check, with Node's exact DataError messages and order) and wires it into every algorithm's JWK import branch — the AES family, ChaCha20-Poly1305, HMAC, ECDH/ECDSA, Ed25519/X25519, RSA-OAEP/PSS/RSASSA, and AKP. normalizeJsonWebKey() now builds the usages bitmap by parsing each string entry and dropping unrecognized ones. All exportJwk() sites convert back through a new toJwkKeyOps() helper. Three new tests cover the full behavior matrix; two existing DeferredPromise-leak regression tests swap their trigger from ["bogus"] to a non-sequence value since the old input no longer throws at the conversion layer.
Security risks
WebCrypto key import is security-relevant surface. The change relaxes validation in one direction (foreign key_ops entries are now tolerated) and tightens it in another (duplicate entries now reject for every algorithm, not just HMAC/ChaCha/AKP). The relaxation is safe: key_ops is advisory metadata about intended operations, and the actual capability restriction on the imported CryptoKey comes from the caller's usages argument, which the new helper still enforces ((jwk.usages & usages) != usages → DataError). No cryptographic primitive, key material handling, or capability grant changed. The HashSet<String> duplicate scan is not exposed to hash-table sentinel hazards because IDLDOMString conversion always produces a non-null WTF::String and empty strings are valid entries.
Level of scrutiny
Medium-high. The mechanical fan-out (15 import branches, 7 export sites) is verified complete by grep, and the shared helper is placed at the right layer (CryptoAlgorithm, the base every importer already inherits from). The tests are thorough — one combined .toEqual per case, exact error class + message asserted, both known and unknown duplicate values covered per algorithm, and the unwrapKey path exercised. However, the change deliberately diverges from upstream WebKit's IDL, picks Chromium's reading over Node's on one edge (duplicate unknown values reject), and for the AES family places the key_ops check ahead of the kty/use/alg checks that live inside CryptoKeyAES::importJwk — a documented but real error-precedence difference from Node. Those are design calls a maintainer should sign off on rather than an automated review.
Other factors
No CODEOWNERS entry covers src/jsc/bindings/webcrypto/. The PR description notes the vendored Node parallel tests don't yet carry upstream's new EC/RSA/CFRG key_ops assertions, and that a wider refactor folding use/ext into the shared helper was considered and deferred — both reasonable scoping decisions worth a human acknowledging. The two edited pre-existing tests still exercise the same convertDictionary<JsonWebKey> throw path (sequence conversion of a non-iterable), so the leak guard they protect is intact.
|
The review found no bugs and leaves three design calls for a maintainer. For whoever picks this up, here is where each one stands:
Buildkite #113400 is at 180 of 181 jobs passed. |
main (bc55d56) rejects a repeated key_ops entry for AES, RSA, EC and OKP keys in CryptoKey*::importJwk, through jwkKeyOpsAllow. This branch did the same in the algorithm branches, with validateJwkKeyOps. The merge takes main's tree as it is. The next commit adds the part that main does not have: key_ops entries that are not a KeyUsage.
JsonWebKey.key_ops is sequence<DOMString> in the WebCrypto IDL, and RFC 7517 section 4.3 lets a JWK name operations that WebCrypto does not define. The dictionary conversion read it as sequence<KeyUsage>, so importKey and unwrapKey threw a TypeError for such a key. key_ops is now a Vector<String> through JsonWebKey. normalizeJsonWebKey builds the usages bitmap from the entries that name a KeyUsage. The checks that main has (jwkKeyOpsAllow and the three inline ones) see the strings, so a repeated entry is a DataError whether it names a KeyUsage or not, as in Node v26.12.1. A key_ops without a foreign entry costs one popcount compare in the duplicate check. exportKey builds its key_ops from the usages bitmap. The three copies of the JsonWebKey on import are now moves.
…key-ops-domstring
parseEnumerationFromString<CryptoKeyUsage> has two callers. Inlined into both, the scan of the 12-entry table became an out-of-line std::__find_if in release builds, and every conversion of a KeyUsage paid a call for it. NEVER_INLINE keeps the scan folded into the one function, as it is on main.
RsaOtherPrimesInfo has no required member in the Web Crypto IDL. The converter threw a TypeError for an entry without r, d or t, for every key type. Now the entry converts. An RSA import rejects every oth with a DataError, and the other key types do not read it.
The row for each key type now exports its key, so each of the seven places that build key_ops from the usages has a row. The ChaCha20-Poly1305 row asks for its four usages. bench: add rows for importKey, unwrapKey, exportKey and generateKey. bench/ had none for a key operation.
|
This branch now has main (3f3a9ff) merged, and the PR is smaller: 17 source files, +73/-48. It was 31 files. What main covers. #47559 rejects a repeated What main still lacks. A What this push has.
Against Node v26.12.1. 11 algorithms and 22 shapes of Two questions for a maintainer. @dylan-conway, this is next to your #47559 and #47591.
Not in this PR. Verified on a debug build of d350e24:
|
There was a problem hiding this comment.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
Beyond the inline finding, I also checked a few things in the C++ side and found nothing wrong: toJwkKeyOps iterates 1 << bit in CryptoKeyUsage declaration order, which matches both the CryptoKeyUsage* bit constants in CryptoKeyUsage.h and the order the old CryptoKey::usages() produced, so exported key_ops are unchanged; the size() == popcount(usages) fast path in hasDuplicateJwkKeyOps is sound because normalizeJsonWebKey only sets a bit for entries that parse as a KeyUsage, so equality implies no repeats and no foreign entries; the three new WTF::moves are on an rvalue variant and locals that are not read afterwards; and dropping required from RsaOtherPrimesInfo cannot change RSA import behavior since CryptoKeyRSA::importJwk rejects any oth before looking at its members.
Extended reasoning...
The change rewires JsonWebKey.key_ops from an enum sequence to DOMString in the WebCrypto bindings, adds string-based duplicate detection, and makes every exporter derive key_ops from the usages bitmap; it touches crypto import/export paths but no auth or data-exposure surface. One inline finding (a Bun-authored test placed under the vendored Node test directory) is already posted; the ruled-out items above are the enum/bitmap ordering, the popcount fast path, the move sites, and the RsaOtherPrimesInfo IDL relaxation.
hasDuplicateJwkKeyOps had a comment that explained why equal counts mean no repeated entry. The two values now have names that say it, and the comment is gone. key_ops and usages each have a one-line comment in place of the shared paragraph. No behavior change.
|
Review follow-up, in fd64a85:
On a debug build of this commit, |
|
The automated review of fd64a85 has no actionable finding, so there is nothing to change. All three review threads have a reply and are resolved. |
|
The second automated review of fd64a85 also found no issue. No review thread is open, and no change is pending from a review. |
|
The edited automated summary for fd64a85 still has no actionable finding. The CI build for that commit is almost complete (183 of 188 jobs), and its red tests are only AOT-suite files. There are 41 of them (an earlier version of this comment said 29, from a truncated list). The first comment has the details. 40 of them are also red on merged PRs, the other one fails in some runs of other branches, and this PR touches none of them. |
|
The edited automated summary still has no actionable finding. Its one remark is about the length of the description: the four visible sections hold what decides the merge, and the collapsed Notes hold the measurements and the test lists, so the Notes are optional reading. |
Problem
crypto.subtle.importKey("jwk", { kty: "oct", k, key_ops: ["encrypt", "fly"] }, "AES-GCM", true, ["encrypt"])rejects withTypeError: value must be enumeration (string). Node v26.12.1 imports the key. A comparison with Node found this, not a user report.convertDictionary<JsonWebKey>(src/jsc/bindings/webcrypto/JSJsonWebKey.cpp:150). It convertskey_opsassequence<KeyUsage>. The Web Crypto IDL hassequence<DOMString>, and RFC 7517 section 4.3 lets a JWK name other operations.oth: [{}]is aTypeErrortoo: the converter requiresr,dandt. The IDL does not.Fix
JsonWebKey.key_opsis aVector<String>.normalizeJsonWebKeybuilds theusagesbitmap from the entries that name aKeyUsage. Main's duplicate check (node:crypto, webcrypto: assorted Node compatibility fixes #47559) now sees every string.othentry converts withoutr,dort. RSA import rejects everyoth(node:crypto, webcrypto: a third batch of Node compatibility fixes #47591), and no other key type reads it.test/js/web/crypto/web-crypto.test.ts(four new tests fail on main) and Node'stest-webcrypto-key-ops-duplicates.js, added as it is.Background
importKey("jwk")andunwrapKey("jwk")share this converter. A caller that owns itsimportKeycall can filterkey_opsfirst. A call inside a library cannot: hono'sjwk({ jwks_uri })answers 401.["encrypt", "fly", "fly"]imports where Node's test wants aDataError.Downsides
TypeErrornow imports, or fails with aDataError.exportKey("jwk")runs 50 to 70 more instructions for each usage after the first (7,148 to 7,209 with two): it writes strings.importKey("jwk")runs 36 to 199 fewer..text: 512 bytes smaller.Notes
What this PR is now. The PR of 2026-09-09 had two parts. Main covers one of them since #47559.
key_opsentry imports for AES, RSA, EC and OKP keysjwkKeyOpsAllowinCryptoKey{AES,RSA,EC,OKP}::importJwkCryptoAlgorithm::validateJwkKeyOps, its 15 call sites, and Node's message textkey_opsentry that is not aKeyUsageis aTypeErrorThe branch has main merged. The merge of bc55d56 takes main's tree as it is, and the commits after it hold the whole change. #33902 was an earlier PR of mine for the duplicate part alone. I closed it in favour of this one.
Where this comes from. No issue and no user report exists for it.
gh search issues --repo oven-sh/bunfinds no issue forkey_opsand none for"value must be enumeration". The difference showed in a comparison ofimportKey("jwk")with Node v26.12.1. The grounds are:sequence<DOMString> key_ops, andRsaOtherPrimesInfowith no required member,test/parallel/test-webcrypto-key-ops-duplicates.js, which imports["sign", "future"].WebKit has
sequence<CryptoKeyUsage> key_opsandrequiredonr,dandt(Source/WebCore/crypto/JsonWebKey.idl,RsaOtherPrimesInfo.idl). ItsLayoutTests/crypto/subtle/import-key-malformed-parameters.htmlexpects a rejection forkey_ops: ["foo"]. So Safari rejects these keys on purpose, and Bun differs from WebKit on purpose after this PR.JsonWebKey.hsays so at the member.Who this can change, and who it cannot.
jwk({ jwks_uri })and a JWKS key that haskey_ops: ["verify", "urn:example:attest"]: HTTP 401 on main (the cause is theTypeError), HTTP 200 on Node v26.12.1 and with this PR. Azure Key Vault is one source of such values (import,export).jose.importJWKpasseskey_opson as thekeyUsagesargument, and a name that is not aKeyUsageis aTypeErrorthere in Node too.importKeyis where such a JWK is known to arrive.unwrapKey("jwk")changes because it sharesconvertDictionary<JsonWebKey>. I know of no program that wraps a JWK with such an entry.A caller that owns its
importKeycall gets Node's results on a released Bun with this wrapper. With it, the installed Bun 1.4.3 canary agrees with Node v26.12.1 on all 242importKeycells of the census below.The wrapper cannot reach a call inside a library (the hono row). It also does not fit
unwrapKey("jwk")when the wrapping key hasunwrapKeyand notdecrypt. The one detour there unwraps the bytes as an extractable raw HMAC key, exports it, filters the JSON and imports it. That puts the key material into script, which an unwrap into a key that is not extractable must not do. Those two cases are why the converter changes.Results. 11 algorithms (AES-GCM, AES-KW, AES-CBC, HMAC, ChaCha20-Poly1305, RSA-OAEP, RSASSA-PKCS1-v1_5, ECDSA, ECDH, Ed25519, X25519), 22 shapes of
key_ops, throughimportKey("jwk")andunwrapKey("jwk"): 484 cells. Each cell is the usages of the key or the name of the error. "main" is a debug build with thesrc/of 3f3a9ff, "this PR" a debug build of this branch.importKey, mainimportKey, this PRunwrapKey, mainunwrapKey, this PR264 cells change between main and this PR. Each of them is the
TypeErroron main. 224 of them import now, and 40 are aDataError. The rows for AES-GCM with the usages["encrypt", "decrypt"], throughimportKey:key_ops["encrypt","decrypt","x-op"],["x-op","encrypt","decrypt"]["encrypt","decrypt","x-op","y-op"]["encrypt","decrypt",7],[..., null],[..., true],[..., {}],[..., ""],[..., "ENCRYPT"]["x-op"]["encrypt","decrypt","x-op","x-op"]["encrypt","decrypt","encrypt"],[]"encrypt",5,{},null(not a sequence)oth, 6 keys and 10 shapes, 60 cells: 41 agree with Node on main and 59 with this PR.oth: [{}],[{ r }]and[null]import for a key that is not RSA, and are aDataErrorfor an RSA key. The one cell that still differs is a private RSA JWK with a full entry (r,d,t). Node imports it as a multi-prime key. BoringSSL has no multi-prime RSA, and #47591 rejects everyoth.A repeated entry that is not a
KeyUsage.["encrypt","fly","fly"]is aDataErrorhere. Node v26.12.1 rejects it, and Node v26.3.0 imported it:validateKeyOpsnow keeps a set of every entry. Node's test asserts all three cases (["sign","future"]imports,["sign","sign"]and["sign","future","future"]are aDataError). The file is in this PR as Node has it at v26.12.1. It exits 1 on main, at line 13.Not changed here.
DataErrormessage. node:crypto, webcrypto: assorted Node compatibility fixes #47559 lists Node's text (Duplicate key operation,Key operations and usage mismatch) as a difference it did not change.keyUsagesargument.importKey("raw", bytes, "AES-GCM", true, [{ toString() { return "encrypt" } }])isTypeError: value must be a string. Node v26.12.1 and Bun 1.2.23 convert the entry with ToString and import the key. Bun 1.3.0 does not. The cause is in the shared sequence conversion since Add new bindings generator; portSSLConfig#23169 (Bun::DefaultConversionContext,src/jsc/bindings/webcore/JSDOMConvertSequences.h), at 8 call sites (JSSubtleCrypto.cpp:407,:440,:522,:638,:662,:719,:782andnode/crypto/KeyObject.cpp:965). It is a different defect with a different cause, so it is not in this PR. After this PR oneimportKey("jwk")call converts akey_opsentry with ToString and akeyUsagesentry without. I handed it on as separate work.unwrapKeycells that differ from Node. They are in the parse step ofunwrapKey, which this PR does not touch. In 44,key_opsis not a sequence:TypeErrorhere,DataErrorin Node, the same as on main. In 11, an entry ofkey_opsin the wrapped JSON is an object:TypeErroron main, an import here,DataErrorin Node. Node parses a wrapped JWK into objects with no prototype, so ToString throws for that entry.How a usual key pays nothing for the duplicate check.
hasDuplicateJwkKeyOpstakes theJsonWebKey.usageshas one bit for each distinct entry that names aKeyUsage. Ifkey_opshas as many entries asusageshas bits, no entry is repeated and none is foreign, and the check returns. Only akey_opswith a foreign or a repeated entry reaches theHashSet<String>scan inSubtleCrypto.cpp.Cost, measured on release builds. Release builds (ThinLTO, linux-x64) of 3f3a9ff and of this branch (d350e24). The commit after d350e24 (fd64a85) names the two values of the duplicate check and shortens two comments in
JsonWebKey.h. In a reduction of the check, clang 23 at-O2emits the same 10 instructions for the old form and the new form (-march=nehalemand-march=haswell). Only the order of the popcount and the size load differs. The numbers are instructions in user mode on the main thread for one call: the slope between a loop of 100,000 calls and a loop of 300,000 (perf_event_open), with the smallest of 5 runs for each loop, and the two builds in turn. Single runs of one cell spread by 7 to 200 instructions, and a few runs are off by about 600. The smallest count of each loop removes that. The Node column is one run, for scale.importKey("raw")AES-GCM, 1 usageimportKey("raw")AES-GCM, 2 usagesgenerateKeyAES-GCM, 2 usagesimportKey("jwk")AES-GCM, nokey_opskey_opskey_opskey_opskey_opsand 1 entry that is not aKeyUsageimportKey("jwk")HMAC, 2key_opsimportKey("jwk")ECDSA public, 1key_opsimportKey("jwk")RSA-OAEP public, 1key_opsunwrapKey("jwk")AES-GCM, 2key_opsexportKey("jwk")AES-GCM, 1 usageexportKey("jwk")AES-GCM, 2 usagesexportKey("jwk")AES-GCM, 4 usagesimportKey("raw")and the first read ofkey.usages, 4 usagesThe installed Bun 1.4.3 canary (367d939) is an official build with another build configuration. For the six rows that it can run and that have a Node number it gives 5,620, 15,277, 16,335, 19,056, 19,068 and 6,915.
toKeyDataandSubtleCrypto::importKeyeach copied theJsonWebKey, andunwrapKeycopied it once. These are moves now.JsonWebKey::JsonWebKey(const JsonWebKey&)(905 bytes) is not in the binary any more.exportKeyandwrapKeywritekey_opsas a vector of strings (toJwkKeyOps), where main has a vector of enum values. A single-step trace of oneexportKey("jwk")call with 4 usages has 6,297 instructions on main and 6,495 here. The difference is intoJwkKeyOps,convertEnumerationToStringand the destructor of the vector. The number of allocations is the same. An export that pays nothing needs a second member inJsonWebKey: strings for the import, enum values for the export. I did not build that.KeyUsagelookup.parseEnumerationFromString<CryptoKeyUsage>has two callers. In the first version of this change the optimizer inlined it into both, and the scan of the 12 names became an out-of-linestd::__find_if. Every conversion of aKeyUsagepaid for it: on the earlier base, +245 instructions for an AES JWK with 2key_ops, +1,136 with 12, and +300 forgenerateKey.NEVER_INLINEkeeps the scan in one function, as on main.nm bun-profile | grep '__find_if.*CryptoKeyUsage'prints nothing for main and for this branch..textis 110,632,729 bytes on main and 110,632,217 here (-512)..rodatais 26,768,364 bytes in both. The strippedbunis 140,474,656 bytes in both.sizeof(JsonWebKey)is 200 bytes before and after. CI's size check of fd64a85 (build 136478) against main's canary build 136408 shows +0.0 KB on 7 of the 12 targets and 1.5 KB to 5.5 KB less on the other 5 (Android x64, FreeBSD x64 and aarch64, Windows x64 and aarch64).exportKey("jwk")of 9 fixed keys (AES-GCM, AES-KW, HMAC, ChaCha20-Poly1305, RSA-OAEP, ECDSA, ECDH with no usages, Ed25519, X25519) and onewrapKey("jwk")give the same bytes on both builds.bench/snippets/webcrypto-keys.mjsis new. It has rows forimportKey,unwrapKey,exportKeyandgenerateKey.bench/had no row for a key operation.Tests.
test/js/web/crypto/on a debug build of this branch: 134 pass. With thesrc/of 3f3a9ff the four new tests fail and the other 113 ofweb-crypto.test.tspass.key_ops(CryptoKey{AES,RSA,EC}::importJwk, the two branches ofCryptoKeyOKP::importJwk, and the HMAC, ChaCha20-Poly1305 and ML-DSA importers). Each row also exports its key, so each of the seven places that writekey_opshas a row.test/js/node/test/parallel/test-webcrypto-*(40 files, the new one included) andtest-crypto-key-objects-to-crypto-key.js: all exit 0.test/js/deno/crypto/webcrypto.test.ts,test/js/node/crypto/crypto.key-objects.test.ts,crypto-pqc.test.ts,sign-jwk-ieee-p1363.test.ts,test/js/bun/jsc/common-strings.test.ts: 166 pass, 27 skip, 1 todo.TypeErrorfrom the dictionary conversion withkey_ops: ["bogus"]. That value converts now, so they usekey_ops: "sign", which is not a sequence and still throws there.oth. One asked to leave it out until RSA import rejects a presentoth. node:crypto, webcrypto: a third batch of Node compatibility fixes #47591 does that now, soothis in.The account of 2026-09-09 (against the main of that day). Its
validateJwkKeyOpspart is not in the PR any more. Its sentence that such a JWK "fails only in bun" is wrong: Safari rejects it too.[human-review] gate passed · iteration 1 · 20 files touched
fails on main (without fix)
passes on PR (with fix)
diff hotspot
gate history · 2 passed · 0 rejected · iteration 1
evidence per changed file