摘要
- Composite ML-DSA 用一个 OID 和一个结果封装两种签名,但 CMS 仍在
SignedData、SignerInfo与签名属性中分别声明算法。digestAlgorithm必须与复合算法固定的预哈希一致,signatureAlgorithm的参数必须缺省。 - 验证者还要重建准确的签名字节、重算内容摘要、比对签名保护属性,并把证书路径、状态、用途与签署授权分别判断。两个 component 通过,不等于整个决策链成立。
安全仪表盘上亮起了两个绿色结果:ML-DSA component 有效,传统 component 也有效。可同一个 CMS 对象的外层 SignerInfo.digestAlgorithm,却声称使用了不属于该复合算法的摘要。
两个绿灯与一份自相矛盾的封套,谁有权决定文件有效?
draft-ietf-lamps-cms-composite-sigs-05 的实际价值,就在于禁止验证者随意回答这个问题。该文档是 LAMPS 工作组在 IETF stream 中的活跃 Internet-Draft,目标状态为 Proposed Standard。第 05 版日期是 2026 年 5 月 22 日,有效期到 11 月 23 日。Datatracker 在 10 月 1 日记录流程变更,目前显示它进入 RFC Editor 队列,等待第二位编辑。它仍不是 RFC;排队进度不证明某个库已经支持、某张证书已经签发、某套系统已经启用或迁移已经完成。
它是 Composite ML-DSA 基础草案的 CMS 配套规范。基础草案把 ML-DSA 与 RSA、ECDSA、Ed25519 或 Ed448 组合成一个公钥与签名接口,并要求所有 component 签名都通过,复合验证才成功。CMS 配套草案解决的,是这些运算究竟覆盖哪一组字节,以及外层各处算法声明如何保持一致。
一个复合 OID 并没有消除 CMS 外层
第 05 版列出 18 种复合算法 OID,覆盖不同 ML-DSA 参数集与传统算法组合。同一个 AlgorithmIdentifier 用于标识复合公钥与签名算法,其 parameters 字段必须缺省。
这套单一接口避免应用自行拼装“两份签名”和任意解释两个结果。基础草案规定复合编码、component 绑定和统一验证操作;其安全目标是在至少一个 component 对经典与量子能力攻击者仍保持 EUF-CMA 安全时,保留抗伪造能力。
但 CMS 本来就有多层算法字段。SignedData.digestAlgorithms 是一个集合;每个 SignerInfo 还有自己的 digestAlgorithm 与 signatureAlgorithm;签名属性可以加入 CMSAlgorithmProtection;证书则声明公钥算法。若这些位置互相矛盾,单纯调用复合密码原语无法替应用选出“应当相信”的那一个。
因此审计记录不能只留下“PQ signature valid”。它应分别保存复合 OID、证书密钥算法、SignerInfo 签名 OID、参数是否缺省、外层摘要 OID、签入的算法保护值、两个 component 的结果以及最终政策判定。单个布尔值会把解析选择与密码学事实混成一件事。
预哈希由复合算法名称固定
这一 CMS profile 只使用 Composite ML-DSA 的 pre-hash 模式。每一种复合算法名称都绑定一个面向 CMS 的摘要:有些用 SHA-256,多数用 SHA-512,Ed448 组合使用 SHAKE256。
SignerInfo.digestAlgorithm 必须等于选定复合算法对应的预哈希。SHA-256 与 SHA-512 的 parameters 必须缺省;SHAKE256 的 parameters 同样必须缺省,并且输出长度是 64 字节。
传统 component 内部可能采用另一个摘要。例如某个 ECDSA P-384 component 内部使用 SHA-384,而复合算法面向 CMS 的预哈希仍是 SHA-512。草案明确说,内部摘要与 CMS 使用无关。日志若不给摘要名称标注层级,会把合法内部差异误报成外层冲突;若完全忽略层级,又可能漏过真正的 SignerInfo 不一致。
SignedData.digestAlgorithms 集合应该包含相应摘要,以帮助 one-pass verifier 预先计算。缺少它时,一次遍历验证器可能无法完成验证。但这个集合并不能替代 SignerInfo 中的强制相等检查:前者是容器级处理提示,后者是该 signer 的明确选择。
signedAttrs 改变了真正签入的字节
CMS 有两条签名路径。没有签名属性时,签名覆盖 encapContentInfo.eContent OCTET STRING 的值,不包括 tag 与 length 字节。
存在签名属性时,签名不再直接覆盖内容,而是覆盖 SignedAttrs 值的完整 DER 编码。该编码包含 tag 与 length,并且签名输入使用 EXPLICIT SET OF tag,不是最终 SignerInfo 中出现的 IMPLICIT [0] tag。
签名属性至少包括 content-type 与 message-digest。message-digest 装载内容摘要,接收者必须从收到的内容重新计算并比对。若解析器重编码出另一组属性字节,或者没有核对内容摘要,即便 component 数学运算能对某些输入返回成功,也没有完成 CMS 验证。
证据链应从原始 CMS 对象的哈希开始,然后记录解析出的内容哈希、准确 DER signedAttrs 哈希、收到与重算的 message-digest、实际交给复合验证器的字节范围。美化后的 ASN.1 树、JSON 投影或重新序列化对象都不能替代原始字节证据。
复合原语本身支持 context string,但这个 CMS 规范把它固定为空字符串。应用不能声称此处借助非空 context 区分了软件签名与付款审批。领域隔离必须由经过验证的 content type、签名属性、证书政策或其他应用规则承担。
把算法叙事也签进去
RFC 6211 定义 CMSAlgorithmProtection,允许把摘要算法以及签名或 MAC 算法放入签名属性。RFC 8933 又收紧了 CMS 的摘要一致性要求。第 05 版建议加入该属性,以抵御算法替换。
外层未签字段可以在不改变签名输入的情况下被改写。算法保护属性进入 DER signedAttrs 后,签署者关于算法的声明也受签名保护。验证器便能把它与外层 SignerInfo 和复合 OID 比对,而不是默默采用密码库优先识别的字段。
“存在该属性”本身仍不是验收结论。验证器必须检查属性结构、出现位置、摘要与签名 OID、参数规则、证书密钥兼容性以及 profile 限制。草案使用 SHOULD 而不是 MUST,意味着缺失状态也要成为显式政策输入,不能被通用成功码抹掉。
完整回执应回答:是否存在 signedAttrs;是否存在并签入 CMSAlgorithmProtection;其中的摘要是否匹配 SignerInfo.digestAlgorithm;签名标识是否匹配复合 OID;禁止参数是否确实缺省;证书密钥是否兼容;每个 component 是否成功;内容摘要是否重算一致。
注册表可以先于草案文字变化
草案向 IANA 请求一个 S/MIME ASN.1 模块标识。冻结的第 05 版文本仍带有等待替换的模块号占位符。2026 年 10 月 2 日抓取的 IANA 公共注册表则已列出 decimal 88,对应 id-mod-composite-mldsa-cms-2026,引用这份 Internet-Draft。
这并不矛盾。公共注册表已有分配;草案源文件仍保留出版占位符;文档处于 RFC Editor 队列;RFC 编号仍未产生。把任何一个状态单独写成“标准已完成”都会越界。
对实现者而言,抓取时的 IANA 公共表是模块编号的直接证据;对标准状态而言,Datatracker 与未来正式 RFC 是另一套证据。分配与排队都不证明产品支持或运营方启用。
两项签名有效,仍不等于签署者有权
基础复合规范要求所有 component 验证成功,并禁止把复合密钥中的 component key material 复用于其他上下文。这个限制保护复合安全论证,也减少跨协议暴露。
但“双通过”回答的只是密码学问题。证书链可能不可信,状态信息可能过期,证书用途可能不适用,签署者可能无权批准该内容,内容可能过时或恶意,接收流程也可能不是预期对象。一个有效的审批文件更不证明审批事项已经执行。
所以验收必须保留多层坐标:解析与编码、算法标识一致性、内容摘要、两个 component verdict、证书路径与状态、key usage 与政策、签署者身份与授权、应用处置、交付、持久化以及外部结果。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance

