Repository navigation
fix: keep RSA-OAEP-256 digest correct in runtimes that ignore oaepHash - #106
Conversation
f19a834 to
ccb1501
Compare
talha-API
left a comment
There was a problem hiding this comment.
Thanks for raising this PR and issue @mmorales-post and apologies for the delay in the response.
The changes are sound, just a few points to address. Please also update the PR with latest changes from main (if not done already) and add any relevant tests for the comments provided.
talha-API
left a comment
There was a problem hiding this comment.
Thanks for addressing the comments @mmorales-post , please see additional minor comments and I request you to provide some further context on the points below:
- Which runtime did you run into this issue in? Since the issue specified
crypto-browserifyandpublic-encrypt, I assume a browser bundle. If not, please share the runtime and the bundler/versions. - As you noted in the scope section, this change targets only the digest issue. A client must still polyfill
process.version(≥ 13),fs,Buffer,cryptoetc. How does your setup provide them? - I have tested the changes and they do not introduce any regressions, but please share evidence from the setup where you found this (browser/postman/insomnia, error logs etc) It will help us review and assess the need for JWE support outside native Node.
|
Thanks @talha-API. Comment fixes are pushed. On your three questions: 1. Runtime. The Postman script runtime, which runs the same way in the Postman app, the Postman CLI and Postman monitors. It isn't a browser, but it has the same constraints: no The bundle I validated with: webpack 5.112.2, 2. The other polyfills.
None of that needs a change to this library. The digest is the only part a polyfill can't fix: the polyfill accepts 3. Evidence. a) The same bundle built from On b) I also confirmed it end to end against Mastercard's sandbox environment: the SHA-1-wrapped token from c) In the same bundle, in the same Postman script runtime, the field-level path is already correct, because On the need for JWE outside native node: |
|
Thanks for the detailed reply on my queries, it is consistent with what I saw during review and is correct for client built bundles. On your last point on the Have you tried using these updates through the |
|
Thanks @talha-API. No, I haven't run these changes through I did check its current release for the same problem, and it's fine. Its Moving it onto I can look into it and open a PR there once this one is merged, if your team wants it. I'd rather keep it out of this PR's scope. Is anything still open here? If not, could you approve? |
|
Thanks for clarifying on your point! The change is valid for the specific OAEP issue for custom bundles so we can take up the postman library changes separately. If you intend on raising the PR for it, do let us know. Otherwise we will plan and update ourselves. |
|



PR checklist
masterbranchLink to issue/feature request: #105
Description
The JWE key wrap asked node's
crypto.publicEncryptforoaepHash: "sha256". nodehonours that; the
crypto-browserifypolyfill silently ignores it and wraps with SHA-1,producing a token whose header claims
RSA-OAEP-256. It fails only at the recipient.node callers are unaffected. The native path is retained and selected by a one-time
probe. Measured 0.055 ms against 0.050 ms on
mainforencryptData, within noise.The probe. node validates the digest name and throws on an unrecognised one; a
polyfill that ignores
oaepHashaccepts anything. Attempting a wrap under a deliberatelybogus digest therefore distinguishes them, costs one call, and is memoised. It also treats
an absent or stubbed
cryptomodule as unsupported, which is whatresolve.fallback.crypto = falsein this repo'swebpack.config.jsproduces.The fallback goes through node-forge with SHA-256 set for the OAEP digest, which
forge otherwise defaults to SHA-1. MGF1 follows that digest when unset; it is set
explicitly anyway to make the intent clear. The helper mirrors
createOAEPOptionsin
field-level-crypto.js. Forge keys are parsed lazily, so node callers never parse them.decryptDatagets the same treatment, so a browser build can read responses as well assend requests.
Scope. This fixes the digest, which is the failure that is silent. It does not make
the library work under
resolve.fallback.crypto = false, becauserandomBytes,createCipherivandcreateDecipherivstill require the module. Under a bundler thatpolyfills
cryptothe full JWE path now works. Happy to raise the remaining pieceseparately if that is useful.
Validation
Three tests added to
test/jwe-crypto.test.js:still wraps with SHA-256 when the runtime ignores oaepHashstubspublicEncrypttobehave like the polyfill, then asserts the emitted key unwraps with SHA-256 and not
SHA-1. Fails on
main.detects whether the runtime honours oaepHashcovers the probe against real node, apolyfill, and an empty module. Fails on
main.wraps the content encryption key with RSA-OAEP-256, not SHA-1locks the digest for thenative path. This one passes on
mainas well, by design: under node the old code wasalready correct, which is why the bug survived. It is there to stop a regression.
Cross-checked that forge and native interoperate in both directions on the same key, and
that a SHA-1 unwrap of the forge output is rejected.
Full suite: 200 passing. eslint: 0 errors, 5 warnings, unchanged from
main.Validated on Node 17, 22 and 24. Probe error code verified on node 13 through 24 and 26.