createTcpTransport and createTlsTransport's frame readers slice the raw accumulator Buffer and hand that slice straight to cbor2's decode(). cbor2 mirrors the input's own class for nested byte-string values, so a Buffer input produces Buffer-typed byte strings in the decoded frame rather than plain Uint8Array. cbor2's encode() doesn't recognise a Buffer as a byte string at all and falls through to serialising it as a generic object, so any later re-encode of a decoded byte string silently produces the wrong bytes.
A capability token's own signature verification does exactly that re-encode -- COSE's Sig_structure is built by re-encoding the token's protected-header and payload byte strings. Any capability token received over a real TCP or TLS connection fails signature verification with bad_signature, even though the token's own bytes cross the wire perfectly intact.
Found while building agent-comms' directed room.send (the first thing in either codebase to send a real, cryptographically-signed CapabilityToken over an actual wire connection and verify it on the receiving end -- everything before this either verified tokens purely locally or used fakes that never serialize over real TLS).
Fixed in #88: wrap the socket's extracted body in a plain Uint8Array view before decode(), matching frame-codec.ts's own existing normalisation for its message-based transports.
createTcpTransport and createTlsTransport's frame readers slice the raw accumulator Buffer and hand that slice straight to cbor2's decode(). cbor2 mirrors the input's own class for nested byte-string values, so a Buffer input produces Buffer-typed byte strings in the decoded frame rather than plain Uint8Array. cbor2's encode() doesn't recognise a Buffer as a byte string at all and falls through to serialising it as a generic object, so any later re-encode of a decoded byte string silently produces the wrong bytes.
A capability token's own signature verification does exactly that re-encode -- COSE's Sig_structure is built by re-encoding the token's protected-header and payload byte strings. Any capability token received over a real TCP or TLS connection fails signature verification with
bad_signature, even though the token's own bytes cross the wire perfectly intact.Found while building agent-comms' directed room.send (the first thing in either codebase to send a real, cryptographically-signed CapabilityToken over an actual wire connection and verify it on the receiving end -- everything before this either verified tokens purely locally or used fakes that never serialize over real TLS).
Fixed in #88: wrap the socket's extracted body in a plain Uint8Array view before decode(), matching frame-codec.ts's own existing normalisation for its message-based transports.