
Rekor DSSE 类型全解析透明日志中 DSSE 信封的存储、校验与检索机制【免费下载链接】buildkitconcurrent, cache-efficient, and Dockerfile-agnostic builder toolkit项目地址: https://gitcode.com/GitHub_Trending/bu/buildkit导读DSSEDead Simple Signing Envelope是 Sigstore 生态中用于承载数字签名的标准信封格式Rekor 通过可插拔类型Pluggable Types机制将其作为一类独立的透明日志条目进行记录。本文以当前仓库 vendored 的sigstore/rekor源码为基础逐字段拆解 DSSE 类型的 JSON Schema深入讲解 Rekor 如何识别、校验、哈希化并持久化 DSSE 信封——包括只存哈希与签名、不存完整信封的核心设计以及 in-toto 声明Statement主体摘要的索引提取逻辑。读者可以借此理解构建链供应链安全中签名证据如何进入透明日志、如何被检索与验证的完整链路。一、背景DSSE、in-toto 与 Rekor 透明日志1.1 什么是 DSSE 信封DSSEDead Simple Signing Envelope是一种将**载荷Payload与一个或多个签名Signature**打包在一起的标准格式。它的设计初衷是消除对什么签名、签的是哪种形式的数据这类歧义签名覆盖的是信封内部的明文载荷而非任何序列化后的字节表示因此同一份载荷无论以何种方式打包签名始终有效。在 Sigstore 体系中DSSE 常被用作承载 in-toto 声明的载体。in-toto 的 Statement声明以application/vnd.in-totojson作为payloadType见 vendor/github.com/in-toto/in-toto-golang/in_toto/envelope.go#L17声明内部通过subject字段列出被验证物件的摘要例如镜像的 sha256 digest。1.2 Rekor 的可插拔类型机制Rekor 使用可插拔类型Pluggable Types机制支持不同种类的日志条目每种类型都有独立的 JSON Schema 与版本化实现。根据 vendor/github.com/sigstore/rekor/pkg/types/README.mdRekor 目前支持的条目类型包括 Alpine 包、COSE 信封、DSSE 信封、HashedRekord、Helm、In-Toto 证明、JAR、Rekord默认、RFC3161 时间戳、RPM 与 TUF 元数据等其中DSSE Envelopes的类型注册名为dsse当前仅有一个版本0.0.1。DSSE 类型在 Go 侧由 vendor/github.com/sigstore/rekor/pkg/types/dsse/dsse.go 实现KIND dsse被注册进全局类型表dsse.go#L28-L37版本化条目工厂VersionMap则在 vendor/github.com/sigstore/rekor/pkg/types/dsse/v0.0.1/entry.go#L51-L55 中通过init()完成注册默认版本为0.0.1。二、如何识别一个 DSSE 对象Rekor 接收的每个日志条目请求都带有类型信息。对 DSSE 类型而言识别特征非常直接条目的Body字段即spec中必然包含dsseObj字段。从 Go 模型看models.DSSE结构包含APIVersion与Spec两个字段见 vendor/github.com/sigstore/rekor/pkg/generated/models/dsse.go#L35-L44其中Spec的类型为DSSESchema其oneOf约束引用了唯一的v0.0.1子 Schema见 vendor/github.com/sigstore/rekor/pkg/types/dsse/dsse_schema.json。换言之dsseObj就是 DSSE 条目在日志中的核心数据结构后续所有字段定义都围绕它展开。三、DSSE v0.0.1 字段定义详解DSSE 类型的全部字段约束定义在 vendor/github.com/sigstore/rekor/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json 中。该 Schema 包含四个顶层字段并通过oneOf约束保证提交时与入库后两种形态互斥。3.1 字段总览表字段类型读写属性是否必填说明proposedContentobjectwriteOnly二选一客户端提交时携带的原始内容signaturesarrayreadOnly二选一服务端提取并排序后的签名集合最少 1 个元素envelopeHashobjectreadOnly二选一整个信封含签名的 SHA-256 摘要payloadHashobjectreadOnly二选一信封内载荷的 SHA-256 摘要oneOf约束dsse_v0_0_1_schema.json#L88-L95规定两种合法形态提交形态只含proposedContent入库形态同时含signatures、envelopeHash、payloadHash。3.2 proposedContentwriteOnly提交时使用该字段是客户端提交新条目时唯一需要提供的部分包含两个子字段envelopestring以 JSON 字符串形式序列化后的完整 DSSE 信封。服务端会将其反序列化为dsse.Envelope结构进行校验。verifiersarray最少 1 个元素所有用于验证信封签名的验证材料如公钥或证书以 base64 编码字符串表示格式为byte。值得注意的是proposedContent被标记为writeOnly意味着它永远不会出现在日志的可检索内容中——它是提交专用的临时载体。3.3 signaturesreadOnly入库后使用服务端校验通过后生成的签名集合每个元素包含signaturestring对载荷的 base64 编码签名Schema 用正则^(?:[A-Za-z0-9\/]{4})*(?:[A-Za-z0-9\/]{2}|[A-Za-z0-9\/]{3}|[A-Za-z0-9\/]{4})$强制其必须是合法的 base64 字符串verifierstring格式byte与对应签名匹配的验证材料同样 base64 编码。Schema 明确要求签名元素按 base64 编码签名串的字典序lexicographical order排序。这一规范化规则在 vendor/github.com/sigstore/rekor/pkg/generated/models/dsse_v001_schema.go#L49-L52 有同样描述保证同一信封无论以何种顺序提交最终入库的条目结构都一致从而确保日志内容的可重复性与可验证性。3.4 envelopeHash 与 payloadHashreadOnly服务端计算两者结构相同均含algorithm与value两个必填字段envelopeHash覆盖整个发送给 Rekor 的信封包含所有签名的摘要payloadHash仅覆盖信封内被签名保护的载荷的摘要。当前版本algorithm仅允许枚举值sha256见 dsse_v0_0_1_schema.json#L60 与 dsse_v0_0_1_schema.json#L76。在生成的 Go 模型中对应常量分别为DSSEV001SchemaEnvelopeHashAlgorithmSha256与DSSEV001SchemaPayloadHashAlgorithmSha256dsse_v001_schema.go#L385-L387、dsse_v001_schema.go#L495-L497。四、核心设计Rekor 究竟存储了 DSSE 的哪些数据这是 DSSE 类型最关键的存储策略原文档明确了三点只存储载荷的哈希即payloadHash——内容是被信封内数字签名所覆盖的载荷存储整个 DSSE 信封的哈希即envelopeHash——包含签名在内的完整信封摘要存储签名及对应的验证材料如公钥或证书。而即使 Rekor 配置了 attestation storage证明存储后端完整的 DSSE 信封也绝不会被持久化。这一策略在源码中得到双重印证vendor/github.com/sigstore/rekor/pkg/types/dsse/v0.0.1/entry.go#L396 的注释明确指出AttestationKey和AttestationKeyValue两个接口方法未被实现因此信封不会被持久化到 Rekorentry.go#L359-L361 在完成所有处理后会主动清空内存中的载荷字符串与ProposedContent作为内存优化手段也印证了原始载荷不保留的设计取向。从工程角度看这套策略兼顾了三方面诉求隐私与体积载荷可能很大如 SBOM、provenance 文档只存哈希可显著降低日志体积并避免敏感内容扩散完整性锚定payloadHash将载荷内容钉在透明日志中任何篡改都会导致摘要不匹配可验证性envelopeHash连同签名与验证材料足以在未来对某条日志记录做完整的密码学复核。五、提交全流程从信封到日志条目结合 entry.go 的Unmarshal实现L236-L364一次 DSSE 条目提交的完整处理链路如下类型断言与解码将请求断言为*models.DSSE通过DecodeEntry将Spec解码为DSSEV001SchemaL140-L234。Schema 校验调用生成的模型Validate()做字段级校验必填、枚举、正则等。形态互斥检查若同时携带proposedContent与服务端计算字段或两者皆缺都会报错either proposedContent or envelopeHash, payloadHash, and signatures must be present but not bothL253-L265防止客户端伪造服务端字段。信封解析与签名验证将字符串化信封解析为dsse.Envelope要求至少含 1 个签名L275-L277随后调用verifyEnvelopeL467-L510用提交的每个 verifier 逐一尝试验证所有签名只要有一个签名找不到匹配公钥整个提交即被拒绝all signatures must have a key that verifies it。签名规范化以 base64 签名串为键建立签名 → 公钥映射按字典序排序后填充signatures数组同时将公钥转为规范化值CanonicalValue存入verifierL293-L312。摘要计算对解码后的载荷计算sha256得到payloadHash对完整信封字符串计算sha256得到envelopeHashL342-L352。索引键预提取若payloadType为 in-toto 类型则提前从载荷中提取 subject 与 materials 的 digest用于日志检索详见下一节。内存清理清空载荷与ProposedContent标记isInsertable trueL354-L363。此外entry.go#L398-L462 的CreateFromArtifactProperties提供了从本地文件如信封文件与公钥文件直接构造ProposedEntry的路径并明确限制DSSE 信封与公钥均不能通过 HTTP(S) 远程获取dsse envelopes cannot be fetched over HTTP(S)只允许读取本地路径。六、in-toto 声明识别与索引键提取原文档指出in-toto statements 是 DSSE 信封中被识别并解析的内容类型其中发现的 subject 哈希会被索引以便检索。源码中该逻辑位于Unmarshal的索引提取阶段entry.go#L321-L340与IndexKeys方法entry.go#L91-L136仅当env.PayloadType in_toto.PayloadType即application/vnd.in-totojson时才尝试将载荷解析为 in-toto Statement 结构从 Statement 的subject数组提取digest映射中的每一项形如sha256:...追加到extractedIndexKeys若predicate非空还会尝试按materials结构解析并提取其中的 digestentry.go#L74-L78 定义了materialsExtract结构IndexKeys返回的检索键集合包含每个签名的公钥哈希sha256:公钥规范化值的sha256、公钥的 subject 信息、payloadHash、envelopeHash以及上述提取出的 in-toto subject/materials digest。Statement 结构在 vendor/github.com/in-toto/in-toto-golang/in_toto/attestations.go#L70-L74 中定义它内嵌StatementHeader含subject数组与predicateType见 attestations.go#L53-L56并携带predicate。这就是按镜像 digest 搜索 Rekor 日志即可找到对应 provenance/SBOM 声明记录的底层实现依据。对非 in-toto 载荷类型IndexKeys仅返回签名公钥与两个哈希键并记录一条提示日志entry.go#L132。七、入库后的其他关键操作7.1 Canonicalize日志持久化形态Canonicalizeentry.go#L371-L394决定条目最终写入日志的形态它显式丢弃ProposedContentProposedContent: nil注释强调envelope 不会被 canonicalize仅保留signatures、envelopeHash、payloadHash并再次对签名按字典序排序。随后序列化出的 JSON 还会经过 JSON Canonicalization SchemeJCS进一步规范化后才落盘。这一设计与只存哈希不存信封的策略完全一致。7.2 ArtifactHash 与 VerifiersArtifactHashentry.go#L528-L533返回小写形式的payloadHash如sha256:...作为条目的工件哈希标识。Verifiersentry.go#L512-L526从入库的signatures中恢复全部公钥对象供日志一致性校验与审计使用。7.3 Insertable 与错误语义Insertableentry.go#L535-L550在提交入口检查proposedContent及其envelope、verifiers是否齐备。结合Unmarshal中的互斥校验可以归纳出 DSSE 条目的完整错误语义场景结果仅提交proposedContent服务端完成签名验证与哈希计算正常入库仅提交服务端计算字段作为已存在条目被识别用于查询/一致性校验同时提交两者拒绝must be present but not both两者皆缺拒绝要求提供其中一组完整字段信封无签名 / 签名无匹配公钥拒绝DSSE envelope must contain 1 or more signatures/all signatures must have a key that verifies it八、在 buildkit 仓库中的定位本仓库buildkit的vendor/github.com/sigstore/rekor目录下 vendored 了上述 DSSE 类型实现它属于构建链软件供应链安全基础设施的一部分buildkit 生成的 SLSA provenance 与 SBOM 等 in-toto attestation 通常以 DSSE 信封形式承载并可作为签名证据提交到 Rekor 透明日志供事后检索与审计。相关配套代码还包括同一 vendor 树下的pkg/types/intotoin-toto attestation 条目类型与pkg/pki/x509公钥解析它们共同构成了签名 → 透明日志 → 可审计证明的完整闭环。本文所讲解的字段定义、存储策略与索引提取逻辑正是理解这套闭环如何在日志侧落地的基础。九、小结识别DSSE 条目以spec中的dsseObj字段为标志类型注册名为dsse版本0.0.1。存储只存payloadHash、envelopeHash、签名与验证材料完整信封永不持久化——即使启用了 attestation storage。校验提交时必须提供完整信封与至少一个 verifier服务端验证所有签名后方可入库且拒绝混合提交服务端字段。规范化签名按 base64 字典序排序Canonicalize丢弃原始信封保证日志条目可重复、可验证。可检索in-toto 声明中的 subject及 materialsdigest 被提取为索引键支持按镜像摘要反查日志记录。实现位置所有逻辑集中于 vendor/github.com/sigstore/rekor/pkg/types/dsse/dsse.go 与 vendor/github.com/sigstore/rekor/pkg/types/dsse/v0.0.1/entry.go字段约束见 vendor/github.com/sigstore/rekor/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json。对于希望深入源码的读者建议按以下顺序阅读先通读 Schema 理解字段约束再阅读entry.go的Unmarshal→verifyEnvelope→IndexKeys调用链最后对照Canonicalize理解日志持久化形态即可完整掌握 Rekor 对 DSSE 信条的存储与检索机制。【免费下载链接】buildkitconcurrent, cache-efficient, and Dockerfile-agnostic builder toolkit项目地址: https://gitcode.com/GitHub_Trending/bu/buildkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考