IntersectMBO / IntersectMBO/evolution-sdk

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

オープン
#480 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
bug external-review
主要言語
TypeScript
スター
22
フォーク
30
平均マージ
13時間
マージ済み PR(30日)
14

説明

## 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.

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

Start in packages/evolution/src/cose/Sign1.ts, reading signedData() at L70-86 and the decoder at L165, then compare the original-byte preservation pattern in Transaction.ts around the formatCache at L130. Add the described non-minimal protected-header regression case and verify that it fails on main and passes once verification reuses the received bytes.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
typescript
領域
cryptography, security
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
静か
明瞭さ
明確に書かれている
初心者へのやさしさ
72/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。