Skip to content

COSE_Sign1 signedData() re-encodes protected headers instead of preserving the original signed bytes #480

Description

@solidsnakedev

Summary

On decode, the original protected-header bytes of a COSE_Sign1 are dropped and only the parsed HeaderMap is kept; signedData() then rebuilds the Sig_structure by re-encoding those headers with canonical CBOR. In COSE (RFC 8152 / RFC 9052) the protected header is a bstr whose exact bytes are what the signature covers, so a conformant verifier must reuse the received bytes rather than re-encode. In practice most signers emit canonical bytes, so this SDK's re-encode usually matches and verification succeeds; but any signer whose protected-header bytes differ from this SDK's canonical re-encode will have a valid signature rejected. Fail closed: only ever rejects a valid signature, never accepts an invalid one.

Affected

packages/evolution/src/cose/Sign1.ts

  • signedData (L70-86): re-encodes protected headers via CBOR.CML_DEFAULT_OPTIONS (L76)
  • decoder (L165): decodes protectedBytes into a HeaderMap and discards the original bytes

Fix

Preserve the original protected-header bytes through decode and replay them in signedData(), decoding to a HeaderMap only as an on-demand view. The repo already has this mechanism: the WeakMap formatCache in Transaction.ts (L130) captures the CBORFormat at decode time so toCBORBytes/toCBORHex reproduce the original encoding byte-for-byte (non-default codec options opt out). Apply the same pattern to the COSE HeaderMap / COSESign1 path.

Regression test

  • given: a COSE_Sign1 whose protected headers use a non-minimal encoding (e.g. label 1 as 2 bytes), with a valid signature over those original bytes
  • before fix: verifyData returns false (valid signature rejected)
  • after fix: verifyData returns true
    Must FAIL on main today and PASS after the fix.

Reference

Reported informally (COSE protected-header re-serialization). Standard basis: RFC 8152 / RFC 9052 — the protected header is a signed bstr, so verification must operate on the received bytes. Same root principle as the CBOR duplicate-key / re-encode fidelity item (separate issue): a decoder must not alter the decoded bytes, and anything signed or hashed must use the original bytes.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingexternal-reviewFrom external review batch

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions