Skip to content

chore(sdk): drop the internal DER round-trip on ECDSA signatures (DSPX-3634) - #996

Draft
dmihalcik-virtru wants to merge 1 commit into
dspx-3397-7-web-app-noncefrom
dspx-3397-8-drop-der-roundtrip
Draft

chore(sdk): drop the internal DER round-trip on ECDSA signatures (DSPX-3634)#996
dmihalcik-virtru wants to merge 1 commit into
dspx-3397-7-web-app-noncefrom
dspx-3397-8-drop-der-roundtrip

Conversation

@dmihalcik-virtru

Copy link
Copy Markdown
Member

Stack level 8 of the DSPX-3397 split — the optional tail. Base: #994.

This one is droppable. It is not needed for DPoP nonce support; it's the cleanup DSPX-3634 tracks, made obvious by the audit that produced this stack.

What

sign() converted WebCrypto's raw IEEE P1363 output to DER, and every consumer immediately converted it straight back:

site conversion
src/auth/dpop.ts (DPoP proofs) DER → P1363
tdf3/src/crypto/jwt.ts (KAS rewrap request token) DER → P1363
verify() DER → P1363, with jwt.ts doing P1363 → DER first

The DER form never reached the wire, a file, or a public API return value — it was a detour between two functions in the same module. JWS requires raw R‖S anyway (RFC 7518 §3.4), which is exactly what WebCrypto already produces.

So sign()/verify() now speak raw P1363, and ieeeP1363ToDer / derToIeeeP1363 are deleted along with their unit tests: ~150 lines of hand-rolled ASN.1 parsing gone.

Interaction with #988 — please read before merging

This makes #988 moot. #988 hardens the DER parser's bounds checking; this PR deletes that parser and der-signature.spec.ts with it.

#988 is still correct to land first — it protects that code path for as long as the path exists, and it's the right fix if you'd rather not take this refactor. But you should pick one end state:

  • Merge both → the hardening ships, then is removed. Clean final state, slightly odd history.
  • Drop this PR → keep the DER detour, hardened. Also fine.

Behavioral changes

Two, both surfaced by existing tests rather than hidden:

  1. crypto-service.spec.ts asserted DER well-formedness for ES512. It now asserts what actually matters for interop: fixed-width 132-byte output for P-521.
  2. A wrong-width signature used to hit the DER parser and throw Invalid IEEE P1363 signature: expected 64 bytes for ES256, got 63. WebCrypto simply returns false, so it now surfaces as the ordinary Invalid JWT: signature verification failed. Marginally better — no leak of internal encoding detail.

No change to CryptoService's documented contract: the sign/verify docs never specified an encoding.

How to test

cd lib && npm test

394 mocha passing, 394 karma SUCCESS, lint clean. CLI builds and passes its 32 tests against a freshly packed SDK.

Risk

Touches crypto. Mitigated by the fact that the removed encoding was purely internal — verified by auditing every cryptoService.sign/verify caller in the repo (there are three). The JWS conformance suite from #987, which verifies real tokens against jose.jwtVerify, covers the output format end to end.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fbfda982-1540-450f-9d42-9f1cedf042b6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dmihalcik-virtru dmihalcik-virtru changed the title refactor(sdk): drop the internal DER round-trip on ECDSA signatures (DSPX-3634) chore(sdk): drop the internal DER round-trip on ECDSA signatures (DSPX-3634) Aug 10, 2026
…DSPX-3634)

`sign()` converted WebCrypto's raw IEEE P1363 output to DER, and every
consumer immediately converted it straight back:

  - `src/auth/dpop.ts` (DPoP proofs) — DER -> P1363
  - `tdf3/src/crypto/jwt.ts` (KAS rewrap request token) — DER -> P1363
  - `verify()` — DER -> P1363, with `jwt.ts` doing P1363 -> DER first

The DER form never reached the wire, a file, or a public API return
value; it was a detour between two functions in the same module. JWS
requires raw R||S anyway (RFC 7518 §3.4), which is exactly what WebCrypto
already produces.

So `sign()`/`verify()` now speak raw P1363 and the two converters —
`ieeeP1363ToDer` and `derToIeeeP1363` — are deleted along with their unit
tests, removing ~150 lines of hand-rolled ASN.1 parsing.

Two behavioral notes:

  - `crypto-service.spec.ts` asserted DER well-formedness for ES512. It
    now asserts what actually matters for interop: fixed-width 132-byte
    output for P-521.
  - A wrong-width signature used to hit the DER parser and throw
    `Invalid IEEE P1363 signature: expected 64 bytes...`. WebCrypto just
    returns false, so it now surfaces as the ordinary
    `Invalid JWT: signature verification failed` — no detail about the
    internal encoding.

How to test: `cd lib && npm test`.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@dmihalcik-virtru
dmihalcik-virtru force-pushed the dspx-3397-8-drop-der-roundtrip branch from dd18da5 to 7afd5fe Compare August 10, 2026 17:47
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

X-Test Failure Report

opentdf-ctl
opentdf-sdk-lib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant