Add unstable JOSE modules (Jwa, Jwk, Jws, Jwt, Jwe)#6566
Add unstable JOSE modules (Jwa, Jwk, Jws, Jwt, Jwe)#6566leonitousconforti wants to merge 7 commits into
Conversation
Effect Schema definitions and WebCrypto-backed operations for the JOSE family: RFC 7518 algorithm identifiers with separate import/signature parameter sets, RFC 7517 JWK/JWK Set schemas, RFC 7515 JWS in all three serializations with multi-signature sign/verify and extensible critical headers validated at the type level, and a high-level RFC 7519 JWT layer with JWK Set verification and registered-claim validation. Keys embedded in tokens (jwk/jku header parameters) are ignored during verification unless explicitly opted into.
🦋 Changeset detectedLatest commit: 35830ea The changes in this PR will be included in the next version bump. This PR includes changesets to release 28 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds an unstable JOSE API with JWA/JWK schemas, JWS signing and verification, JWE encryption and decryption, JWT signing and claims validation, namespace exports, interoperability tests, security tests, and patch-release metadata. ChangesJOSE API
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)JWT verification flowsequenceDiagram
participant Jwt
participant Jws
participant JwkSet
participant WebCrypto
Jwt->>Jws: Decode and verify compact JWT
Jws->>JwkSet: Select compatible trusted keys
Jws->>WebCrypto: Verify signature
WebCrypto-->>Jws: Verification result
Jws-->>Jwt: Verified claims payload
Jwt-->>Jwt: Validate registered claims
JWE encryption flowsequenceDiagram
participant Jwe
participant KeyManagement
participant WebCrypto
Jwe->>KeyManagement: Derive or wrap CEK
KeyManagement->>WebCrypto: Execute key-management operation
WebCrypto-->>KeyManagement: CEK or encrypted key
Jwe->>WebCrypto: Encrypt plaintext with AAD
WebCrypto-->>Jwe: Ciphertext and authentication tag
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
Comment |
JWE Compact Serialization with WebCrypto-backed authenticated encryption and decryption. Content encryption covers the AES-GCM and AES-CBC-HMAC-SHA2 families; key management covers dir, RSA-OAEP, AES key wrap, AES-GCM key wrap, ECDH-ES (direct and key-wrap), and PBES2. RSA1_5 is omitted as WebCrypto does not implement it and RFC 8725 discourages it. Also expands the test suite: an exhaustive JWE encrypt/decrypt matrix over every key-management x content-encryption pairing, tamper and wrong-key negative tests, and the RFC 7516 Appendix A.3 decryption vector; plus JWS multi-signature, critical-header, and RFC 7515 Appendix A.1 tests. Fixes JWS signing to populate the crit header from the configured critical header names.
Addresses the findings from the adversarial audit. No behaviour change for
correctly-configured callers; adds fail-closed guards and opt-in hardening.
Jwe:
- Bound the attacker-controlled PBES2 iteration count on decrypt
(maxPBES2Count, default 10000) to prevent a CPU-exhaustion DoS.
- Decode all attacker-supplied base64url segments through a typed decoder so
malformed input yields JweError("Malformed") instead of an unhandled defect.
- Reject an unrecognized 'crit' header (RFC 7516 4.1.13).
- Add keyManagementAlgorithms / contentEncryptionAlgorithms allowlists.
- Convert key-management crypto rejections to typed errors (tryPromise).
- Validate a 'dir' key length equals the content-encryption CEK size.
- Bind apu/apv into the ECDH-ES Concat KDF (RFC 7518 4.6.2) and document the
AES-GCM random-IV reuse bound.
Jws:
- Convert importKey/verify rejections to typed failures so an alg/key
mismatch or malformed key material is skipped rather than crashing the
verifying fiber.
- On the jku/embedded-jwk paths, use a key only if it is an asymmetric public
key compatible with the header algorithm (never symmetric or private).
- Add an 'algorithms' allowlist and a 'maxSignatures' bound.
Jwt / Jwk:
- Add 'algorithms' and 'types' (typ) allowlists to Jwt.verify.
- Extract the alg<->key-type compatibility gate to Jwk.isCompatibleWith and
add Jwk.isSymmetric / Jwk.isPrivate guards, shared by Jws and Jwt.
Adds test/unstable/jose/Security.test.ts with regression tests for each fix.
Follow-up to the security hardening: Jwt.verify imported every compatible candidate key and failed the whole verification if any single one rejected, so one malformed key in an otherwise-valid JWK Set could deny service to tokens signed by the good keys. Import each candidate independently and skip the unusable ones, mirroring Jws.verify; still fail closed when none import.
b61a098 to
7a82a65
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/effect/src/unstable/jose/Jwt.ts (1)
25-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAll registered claims are OPTIONAL per RFC 7519 §4.1.
sub,aud, andiatare declared required here, but RFC 7519 defines every registered claim as optional. Tokens that legitimately omitsuboraud(common for access tokens) will failClaimsFromJsondecoding and surface to callers asMalformedrather than a specific reason. If requiring them is a deliberate policy this is fine; otherwise consider making them optional and enforcing presence only where mandated.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/effect/src/unstable/jose/Jwt.ts` around lines 25 - 46, Update the RegisteredClaims schema so every RFC 7519 registered claim, including sub, aud, and iat, is optional; preserve the existing optional handling for nbf and jti. Ensure ClaimsFromJson accepts tokens that omit any registered claim, leaving presence enforcement to policy-specific validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/effect/src/unstable/jose/Jwe.ts`:
- Around line 673-677: Validate the CEK returned by keyManagementDecrypt against
params.cekBytes before proceeding to content decryption, and convert any
mismatch into the existing DecryptionFailed error path. Preserve the current
key-management flow and ensure invalid lengths for all supported algorithms
cannot reach crypto.subtle.importKey as an unhandled error.
In `@packages/effect/src/unstable/jose/Jwk.ts`:
- Around line 237-275: The RsaPrivateKey union currently matches the d-only
branch before the full RSA CRT branch, causing CRT fields to be discarded during
decoding. Reorder the Schema.Union branches so the Schema.Struct containing p,
q, dp, dq, and qi appears before the d-only variant, preserving all CRT
parameters for full private JWKs.
---
Nitpick comments:
In `@packages/effect/src/unstable/jose/Jwt.ts`:
- Around line 25-46: Update the RegisteredClaims schema so every RFC 7519
registered claim, including sub, aud, and iat, is optional; preserve the
existing optional handling for nbf and jti. Ensure ClaimsFromJson accepts tokens
that omit any registered claim, leaving presence enforcement to policy-specific
validation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3894e119-2173-4e02-a9b8-b9edbad095b0
📒 Files selected for processing (10)
packages/effect/src/unstable/jose/Jwa.tspackages/effect/src/unstable/jose/Jwe.tspackages/effect/src/unstable/jose/Jwk.tspackages/effect/src/unstable/jose/Jws.tspackages/effect/src/unstable/jose/Jwt.tspackages/effect/src/unstable/jose/index.tspackages/effect/test/unstable/jose/Jwe.test.tspackages/effect/test/unstable/jose/Jws.test.tspackages/effect/test/unstable/jose/Jwt.test.tspackages/effect/test/unstable/jose/Security.test.ts
- Jwe.decrypt: reject a CEK whose length does not match the content algorithm before it reaches AES importKey. A key-management algorithm can yield a wrong-length CEK (e.g. an attacker RSA-OAEP-encrypts an arbitrary-length key to the recipient's public key), which otherwise rejected inside contentDecrypt as an unhandled defect rather than a typed DecryptionFailed. - Jwk.RsaPrivateKey: order the union so the full CRT struct precedes the d-only struct. A CRT key also satisfies the d-only member and Struct decoding drops unlisted fields, so the previous order silently discarded p/q/dp/dq/qi from complete private keys.
…pto calls The `dir` key-management decrypt exported the recipient's key with a bare Effect.promise, so a token selecting alg:"dir" against a non-extractable or non-raw-exportable key (e.g. an RSA private key) surfaced the WebCrypto rejection as an unhandled defect instead of a typed JweError. Wrap it in Effect.tryPromise -> KeyManagementFailed, and do the same for every other bare crypto.subtle call on the decrypt path (aesKwUnwrap exportKey, the ECDH-ES+AKW and PBES2 KEK imports, and the AES-GCM/HMAC/AES-CBC operations in contentDecrypt) so no attacker input can defect the verifying fiber. Adds a regression test asserting a dir token against an RSA private key fails closed as a typed KeyManagementFailed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Does this have a place in effect? Or should it belong in it's own package? |
Effect Schema definitions and WebCrypto-backed operations for the JOSE family: RFC 7518 algorithm identifiers with separate import/signature parameter sets, RFC 7517 JWK/JWK Set schemas, RFC 7515 JWS in all three serializations with multi-signature sign/verify and extensible critical headers validated at the type level, and a high-level RFC 7519 JWT layer with JWK Set verification and registered-claim validation.
Keys embedded in tokens (jwk/jku header parameters) are ignored during verification unless explicitly opted into.
Type
Description
Related
Summary by CodeRabbit
alg/enccombinations with hardened handling of malformed inputs and unsupported header parameters.