Skip to content

Make XMSS/XMSS^MT generated OIDs and public key format RFC conforming - #5933

Open
falko-strenzke wants to merge 2 commits into
masterfrom
fix-generated-xmss-oids
Open

falko-strenzke wants to merge 2 commits into
masterfrom
fix-generated-xmss-oids

Conversation

@falko-strenzke

Copy link
Copy Markdown
Collaborator

This PR fixes the problem that Botan currently emits the pre-RFC XMSS OID 0.4.0.127.0.15.1.1.13.0 (from
draft-vangeest-x509-hash-sigs-03) in SubjectPublicKeyInfo, PKCS#8 keys and
certificate signature AlgorithmIdentifiers. RFC 9802 (June 2025) assigns
1.3.6.1.5.5.7.6.34 (XMSS) and 1.3.6.1.5.5.7.6.35 (XMSS^MT).

There is a related non-compliance that this PR fixes: RFC 9802
§5.2 says the XMSS public key goes into the SPKI BIT STRING with no ASN.1
wrapping, but XMSS_PublicKey::public_key_bits() wraps the raw key in an
OCTET STRING (the draft-era ISARA and BouncyCastle test certs use that wrapping;
the RFC sample cert does not). The decoder already accepts both forms.

Logical changes

  1. OID table — swap the name XMSS to the RFC OID; keep the ETSI OID under a
    legacy name; add both XMSS^MT OIDs; fix HSS-LMS comment.
  2. Regenerate static_oids.cpp from the table.
  3. Accept legacy OID when loading XMSS public and private keys.
  4. Accept legacy OID when verifying X.509 signatures made with old-OID keys.
  5. Drop the OCTET STRING wrapper in XMSS_PublicKey::public_key_bits() so the
    SPKI matches RFC 9802 §5.2. (Decoding fallback already exists; the PKCS#8
    private key payload stays as is, since no standard defines it.)
  6. Tests: add the RFC 9802 XMSS sample certificate to path validation, keep
    the two legacy certs as regression tests for the old OID + wrapped key, and
    add a unit test asserting the emitted SPKI OID and unwrapped payload.
  7. Release note.

@randombit randombit left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok to me, needs a rebase to address a merge conflict, also the cli tests are failing, will need to update the expected outputs for the XMSS test.

Comment thread src/lib/pubkey/xmss/xmss_publickey.cpp Outdated
// RFC 9802 places the raw XMSS public key directly into the SubjectPublicKeyInfo
// BIT STRING. Earlier Botan versions (following draft-vangeest-x509-hash-sigs)
// wrapped the raw key in an OCTET STRING; such keys are still accepted here.
std::vector<uint8_t> extract_raw_public_key(std::span<const uint8_t> key_bits) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with the historical sequence of changes here (esp wrt the spec itself), but

It seems like historically we've accepted either DER or raw bytes under the old draft OID. We always emitted the DER wrapper. And when I dig into the history further it seems like the raw byte encoding was our encoding approach prior to 2.13, and so we retained it for compatibility with old keys after support for the draft spec, which added the DER wrapper, was included. But we also encoded such pre-2.13 raw keys under a Botan private-arc OID which we no longer support....

Under the new OID, the rule is clear - only the raw encoding is valid.

So it seems like at the very least we should, for the new OID, require that it not be DER wrapped, and skip the decoding attempt. And I think that practically, due to the sequence of incompatible changes made to XMSS over the years due to chasing the specification, no keys exist anywhere which both use the draft OID and the raw encoding.

So extract_raw_public_key should imo skip the sniffing altogether and dispatch based on OID instead.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@randombit
I have implemented that now. It turns out that had to touch the private decoding as well, which previously forwarded an ambigous private key to its public key base. I have generated these figures to illustrate the flows before and after this change.

xmss_unwrap_flow_before xmss_unwrap_flow_after

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.

2 participants