Skip to content

feat: add self-describing key container codecs (pkix,pkcs8,cose-key)#400

Open
lidel wants to merge 2 commits intomasterfrom
add-pkix-pkcs8-keys
Open

feat: add self-describing key container codecs (pkix,pkcs8,cose-key)#400
lidel wants to merge 2 commits intomasterfrom
add-pkix-pkcs8-keys

Conversation

@lidel
Copy link
Copy Markdown
Member

@lidel lidel commented Apr 14, 2026

Summary

Adds a family of self-describing key container codecs in one motion. Each wraps an IETF-standard container whose payload carries its own algorithm identifier, so one codec covers every algorithm the container
can carry.

name code format spec
pkix-pub 0x40 DER-encoded ASN.1 SubjectPublicKeyInfo (SPKI) RFC 5280 §4.1.2.7
pkcs8-priv 0x41 DER-encoded ASN.1 OneAsymmetricKey (PKCS#8) RFC 5958 §2
cose-key 0x42 CBOR-encoded COSE_Key map (application/cose-key) RFC 9052 §7
cose-key-set 0x43 CBOR-encoded COSE_KeySet array (application/cose-key-set) RFC 9052 §7

The algorithm is self-identified by the payload: AlgorithmIdentifier OID for the DER containers, kty/alg/crv for COSE.

Motivation

The main goal is to make these codecs usable for libp2p peer IDs and IPNS records, so the set of supported key types in those systems stops being gated by multicodec assignments.

Today, adopting a new key type in libp2p or IPNS requires minting a per-algorithm multicodec entry first. That turns the multicodec table into a bottleneck: every new algorithm (ML-DSA, SLH-DSA, any future PQ
scheme, niche curves) has to land a bespoke entry before applications can use it, and everyone has to agree on that entry before implementations can ship.

These four containers break that coupling. Because the algorithm identifier lives inside the payload, a single codec covers every algorithm the container can carry. The moment an IETF/RFC encoding exists for a
new key type (for example RFC 9881 for ML-DSA in SPKI/PKCS#8, or a COSE_Key kty/alg registration), it is immediately usable as a libp2p or IPNS key without
waiting on a multicodec update.

Concretely:

  • Less vendor lock-in for libp2p and IPNS. Peer IDs and IPNS names are no longer limited to the algorithms that happen to have per-algorithm multicodec entries. Any SPKI-encodable public key can be supported by willing implementations through
    pkix-pub; any PKCS#8-encodable private key may be supported through pkcs8-priv; CBOR-native stacks get the same path via cose-key/cose-key-set.
  • Faster new-algorithm rollout. The ecosystem can adopt new key types as soon as an RFC/IETF standard exists for them, no new multicodec entry required.
  • Library reuse. SPKI and PKCS#8 are parsed natively by OpenSSL, BoringSSL, Go crypto/x509, rustls, Java JCE, WebCrypto, and every other mainstream crypto stack. COSE_Key is already the key format
    used by WebAuthn/passkeys, CWT, EAT, and constrained-device stacks.

Related:

Code placement

All four codes are single-byte varints (< 0x80). Existing users of libp2p-key (at 0x72, one byte on the wire) encode the codec prefix into every peer ID and IPNS name. Placing the replacements at two-byte codes would mean every migrated identifier pays an extra byte forever.

Specifically, 0x40-0x43 sit in the unclustered 0x39-0x4f free block, avoiding the ipld/CID-codec neighborhood at 0x70-0x7f where a key-tagged entry would not fit the surrounding tags.

Why cose-key and cose-key-set are separate codecs

COSE_Key is a CBOR map; COSE_KeySet is a CBOR array. IETF registers them as separate IANA media types (application/cose-key vs application/cose-key-set) and separate CoAP Content-Format IDs (101 vs 102) in RFC 9052 §11.3.

lidel added 2 commits April 14, 2026 17:23
Introduce container codecs for IETF-standard asymmetric key formats that carry the algorithm identifier alongside the key material, so implementers can reuse existing crypto libraries and specs rather than mint a per-algorithm codec for every new scheme.

- pkix-pub (0x40): SubjectPublicKeyInfo (SPKI) per IETF RFC 5280 section 4.1.2.7
- pkcs8-priv (0x41): OneAsymmetricKey (PKCS #8) per IETF RFC 5958 section 2
- both formats self-identify the key algorithm via the embedded AlgorithmIdentifier OID
- codes placed in the single-byte varint range (< 0x80) so existing users of libp2p-key (0x72) in peer IDs and IPNS names can migrate without paying an extra prefix byte per identifier
- 0x40 and 0x41 sit in the unclustered 0x39-0x4f free block, avoiding the ipld/CID-codec neighborhood at 0x70-0x7f

Refs:
- https://www.rfc-editor.org/rfc/rfc5280
- https://www.rfc-editor.org/rfc/rfc5958
- libp2p/specs#711
Register the CBOR-native counterparts to pkix-pub/pkcs8-priv so the table has one-codec-per-role containers for both the DER (ASN.1) and CBOR (COSE) ecosystems, covering the same "algorithm identifier travels in the payload" model on both sides.

- cose-key (0x42): COSE_Key map per IETF RFC 9052 section 7; media type application/cose-key
- cose-key-set (0x43): COSE_KeySet array per IETF RFC 9052 section 7; media type application/cose-key-set
- split mirrors IETF's own registration of two media types and two CoAP Content-Format IDs (101 and 102), and keeps the "prefix tells you the shape" invariant
- both remain in the single-byte varint range (0x42 and 0x43 in the unclustered 0x39-0x4f block) for identifier cost parity with libp2p-key

Refs:
- https://www.rfc-editor.org/rfc/rfc9052
- https://www.iana.org/assignments/media-types/application/cose-key
- https://www.iana.org/assignments/media-types/application/cose-key-set
@vmx
Copy link
Copy Markdown
Member

vmx commented Apr 14, 2026

Before having a closer look: do they need to be in the 1 byte range, or can then be > 0x80? Getting them into the 2 bytes range is much easier as it needs a less thorough review.

@MarcoPolo
Copy link
Copy Markdown
Contributor

1 byte range would be ideal, as that lowers the overhead to bridging to other standards. 2 bytes wouldn't be a blocker of course, but if this isn't worth a 1 byte codepoint, I'm not sure what would is.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants