Summary

  • Composite ML-DSA makes two component signatures look like one algorithm, but CMS still names the digest, signature algorithm and signed attributes in separate places. The SignerInfo digest must match the composite algorithm's fixed pre-hash, and the signature OID must carry absent parameters.
  • Verification needs more than a green component result. The recipient must reconstruct the exact signed bytes, recalculate the content digest, compare the algorithm identifiers and apply certificate, status and authorization policy independently.

The verifier reported that both component signatures were valid. The post-quantum half passed. The traditional half passed. Yet the CMS object said it had used a digest that did not belong to the composite algorithm selected by its signature OID.

Which result was authoritative: two successful mathematical checks, or an envelope whose algorithm story contradicted itself?

Revision 05 of Composite Module-Lattice-Based Digital Signature Algorithm (ML-DSA) for use in Cryptographic Message Syntax (CMS) exists to prevent that question from being answered casually. The document is an active LAMPS working-group Internet-Draft in the IETF stream, intended for the Proposed Standard track. Revision 05 is dated 22 May 2026 and expires on 23 November 2026. Datatracker recorded a workflow update on 1 October and now places it in the RFC Editor queue, awaiting a second editor. It is not yet an RFC, and queue progress is not evidence of deployed support, configuration, certificate issuance or successful migration.

The draft is a companion to the Composite ML-DSA primitive specification. That companion combines ML-DSA with RSA, ECDSA, Ed25519 or Ed448 behind one public-key and signature interface. Its verifier returns success only when every component signature succeeds. The CMS document answers the next question: which bytes and which outer algorithm declarations are fed into that primitive?

One OID does not erase the envelope

Composite ML-DSA deliberately presents one algorithm identifier for a paired public key and signature. Revision 05 reproduces 18 OIDs covering different ML-DSA parameter sets and traditional components. The AlgorithmIdentifier parameters field must be absent.

That singular interface is valuable. An application does not have to invent its own two-signature container or decide how to combine independent results. The companion construction binds the components and defines one verification operation. Its security argument aims to retain existential-unforgeability when at least one component remains secure against both classical and quantum-capable adversaries.

But CMS already has an envelope with its own fields. SignedData.digestAlgorithms lists digest algorithms used by signers. Each SignerInfo carries a digestAlgorithm and a signatureAlgorithm. Signed attributes can carry a CMSAlgorithmProtection attribute. The certificate identifies the public-key algorithm. A successful composite primitive cannot decide which of several contradictory outer declarations an application meant to trust.

The system therefore needs an agreement receipt, not a flattened label such as “PQ signature valid.” Record the composite OID, the certificate key algorithm, the SignerInfo signature identifier, its parameter presence, the outer digest identifier, the signed algorithm-protection values and the two component verdicts separately. Only then can a policy distinguish a valid encoding from a confused interpretation.

The pre-hash is fixed by the composite name

Traditional CMS usage developed around algorithms that accepted an externally computed message digest. Pure EdDSA and pure ML-DSA later offered different processing models. Composite ML-DSA, in this profile, exposes only pre-hash mode.

Each composite algorithm name fixes the CMS pre-hash. Some pairings require SHA-256, most require SHA-512, and the Ed448 pairing uses SHAKE256. SignerInfo.digestAlgorithm must name exactly that digest. SHA-256 and SHA-512 parameters must be absent. SHAKE256 parameters must also be absent, and its digest output is 64 bytes.

The traditional component may use another digest internally. An ECDSA P-384 component can use SHA-384 while the composite algorithm's CMS-facing pre-hash is SHA-512. The draft says that internal choice is irrelevant to CMS. This distinction matters for implementation telemetry: logging every digest name without its layer creates an apparent mismatch where none exists, while ignoring the outer mismatch can conceal a real validation error.

Revision 05 also says the SignedData.digestAlgorithms set should include the corresponding digest so that one-pass verifiers can prepare the correct computation. If it is omitted, a one-pass verifier might fail. That set and the mandatory SignerInfo equality are related but not interchangeable receipts. One is a collection-level processing hint; the other identifies what this signer used.

Exact bytes change when signed attributes exist

CMS supports two signing paths. Without signed attributes, the signature covers the value of the encapsulated content OCTET STRING. Its tag and length octets are excluded.

With signed attributes, the content is no longer signed directly. The signature covers the complete DER encoding of the SignedAttrs value. That encoding includes tag and length octets and uses an EXPLICIT SET OF tag for the signature input, not the IMPLICIT [0] tag that appears in the final SignerInfo message.

At minimum, those attributes contain content-type and message-digest. The latter holds a digest of the encapsulated content. The recipient must recalculate that content hash and compare it. Correct component arithmetic over the wrong reconstructed attribute bytes, or over attributes containing an unverified content digest, is not successful CMS verification.

This creates a useful evidence hierarchy. Preserve the raw CMS object hash first. Then preserve the parsed content hash, the exact DER signed-attribute hash, the received message-digest, the recomputed value and the byte range actually submitted to Composite ML-DSA verification. A normalized JSON view or a pretty-printed ASN.1 tree cannot replace the original object.

The composite primitive has a context-string input, but this CMS profile fixes it to the empty string. An application cannot claim that a non-empty primitive context separated invoice signatures from software approvals here. Domain separation must come from the CMS content type, signed attributes, certificate policy or another explicitly verified application rule.

Protect the algorithm story inside the signature

RFC 6211 defined CMSAlgorithmProtection so the digest algorithm and either the signature or MAC algorithm can be placed in signed attributes. RFC 8933 later tightened CMS consistency requirements. Revision 05 says the protection attribute should be included to avoid algorithm-substitution attacks.

That word “included” matters. An unsigned outer field can be changed without changing the signature input. A signed protection attribute makes the signer's algorithm declaration part of the protected DER bytes. The verifier can compare it with the outer SignerInfo fields and the composite OID rather than silently choosing whichever identifier its cryptographic library happens to prefer.

This is not an instruction to accept any object carrying the attribute. The verifier still has to check that the attribute is well-formed, occurs under the right CMS rules, names the expected digest and signature algorithm, and is consistent with the public key and profile. Absence may be allowed by the draft's SHOULD, but it should be visible as a policy coordinate rather than disappearing behind a generic success status.

The decision receipt should answer: Were signed attributes present? Was CMSAlgorithmProtection present and signed? Did its digest identifier match SignerInfo.digestAlgorithm? Did its signature identifier match the composite OID? Were forbidden parameters absent? Was the certificate key compatible? Did every component verify? Did the recomputed content digest match?

The registry can move before the prose catches up

The draft asks IANA for one SMI Security for S/MIME Module Identifier for its ASN.1 module. The frozen revision 05 text still shows an “IANA Assigned” placeholder to be replaced. The public IANA registry captured on 2 October lists decimal 88 for id-mod-composite-mldsa-cms-2026, referencing the Internet-Draft.

Those facts can coexist. The public registry has an allocation; the Internet-Draft source still contains a publication placeholder; the document is in the RFC Editor queue; and no RFC number exists yet. Reporting only one state would collapse a multi-system publication process into a false binary.

For implementers, the public registry is the authority for the allocated module number at the capture time. For standards status, the Datatracker and eventual RFC publication remain separate evidence. Neither the allocation nor queue status proves that a library accepts the algorithms or that an operator enabled them.

Two valid components still do not authorize the signer

The companion construction requires both component signatures to pass. That is stronger than accepting either one. It also forbids reuse of the component key material in other contexts, a protection against cross-protocol exposure and loss of the composite security argument.

Yet “both passed” answers a cryptographic question, not every operational one. The certificate path may be invalid. Revocation or status information may be stale. The certificate may be valid for email protection but not code signing. The signer may lack authority for this document. The signed content may be malicious, obsolete or delivered to the wrong workflow. A valid approval object does not prove that the approved action occurred.

The receipts must therefore remain layered: parse and encoding validity; algorithm-identifier agreement; content-digest agreement; both component verdicts; certificate path and status; key-usage and policy; signer identity and authorization; application disposition; delivery; durable storage; external result.