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.

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