Skip to content

COSE HeaderMap: header() and equality use Map reference equality; build() creates duplicate label entries #482

Description

@solidsnakedev

Summary

HeaderMap stores headers in a JS Map keyed by Label objects, but Label uses structural equality while Map.get/Map.set use reference equality. As a result:

  • (a) the public header() accessor calls this.headers.get(label) with a freshly built Label, so it always returns undefined;
  • (b) HeaderMap [Equal.symbol] looks up keys from this in that's map by reference, so two structurally-equal HeaderMaps never compare equal;
  • (c) setAlgorithmId followed by setHeader(labelFromInt(1n), ...) inserts two distinct Label objects for logical key 1, leaving two entries in the map.

No functional or security impact today: the security paths (verifyData, algorithmId, keyId) iterate the map manually with Equal.equals and are unaffected, header() is unused, and the duplicate label-1 entries collapse to a single correct entry on CBOR encode (encode re-keys by primitive value). Latent correctness / cleanup.

Affected

packages/evolution/src/cose/Header.ts

  • header() (L260-262): this.headers.get(label) uses reference equality -> always undefined
  • [Equal.symbol] (L43-51): that.headers.get(key) uses reference equality -> HeaderMaps never equal

packages/evolution/src/cose/Key.ts

  • EdDSA25519Key.build() (L248-252): setAlgorithmId(1n) then setHeader(labelFromInt(1n), ...) create two entries at logical key 1

Fix

Stop keying a JS Map by objects with custom equality. Either intern Label instances so structurally-equal labels share a reference, or replace the map lookups (header(), equality, setHeader overwrite) with Equal.equals-based iteration (as the working accessors already do). Making setHeader overwrite an existing logical key also removes the duplicate label-1 entries in build().

Regression test

  • given: a HeaderMap built with setHeader(labelFromText("address"), bytes)
  • before fix: hm.header(labelFromText("address")) returns undefined
  • after fix: returns the bytes
    Must FAIL on main today and PASS after the fix.

Reference

Reported informally (HeaderMap reference-equality). No live security impact; cleanup for a broken public accessor and a fragile build path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions