Skip to content

Conversation

@wolfv
Copy link
Contributor

@wolfv wolfv commented Nov 2, 2025

This PR adds support for DSSE envelopes used in in-toto attestations. It's part of our efforts to upstream support for v0.3 bundles (see also #513). The code was mostly written by Claude using sigstore-python and sigstore-go as references.

  • src/bundle/dsse.rs: DSSE envelope implementation with Pre-Authentication Encoding (PAE) support. Provides DsseEnvelope wrapper around protobuf Envelope with convenient APIs for creating and manipulating DSSE envelopes.

  • src/bundle/intoto.rs: in-toto Statement support including StatementBuilder, Subject, and predicate handling. Supports creating in-toto attestations with multiple subjects and custom predicates.

  • src/rekor/models/dsse.rs: Rekor DSSE entry models for submitting DSSE envelopes to the transparency log.

Key Features:

  • Correct PAE computation per DSSE spec
  • Support for application/vnd.in-toto+json payload type
  • Builder pattern for creating statements
  • Multiple digest algorithms per subject
  • Comprehensive unit tests

This PR lays the groundwork for Bundle v0.3 DSSE verification support and attestation signing capabilities.

@wolfv wolfv force-pushed the pr4-dsse-bundle-support branch 2 times, most recently from d3051f1 to 967ca5a Compare November 3, 2025 15:51
This PR adds support for DSSE envelopes used in in-toto attestations:

- **src/bundle/dsse.rs**: DSSE envelope implementation with Pre-Authentication
  Encoding (PAE) support. Provides DsseEnvelope wrapper around protobuf
  Envelope with convenient APIs for creating and manipulating DSSE envelopes.

- **src/bundle/intoto.rs**: in-toto Statement support including StatementBuilder,
  Subject, and predicate handling. Supports creating in-toto attestations with
  multiple subjects and custom predicates.

- **src/rekor/models/dsse.rs**: Rekor DSSE entry models for submitting DSSE
  envelopes to the transparency log.

- **rust-toolchain**: Pin to Rust 1.90.0 for edition 2024 support

Key Features:
- Correct PAE computation per DSSE spec
- Support for application/vnd.in-toto+json payload type
- Builder pattern for creating statements
- Multiple digest algorithms per subject
- Comprehensive unit tests

This PR lays the groundwork for Bundle v0.3 DSSE verification support
and attestation signing capabilities.

Signed-off-by: Wolf Vollprecht <[email protected]>
@wolfv wolfv force-pushed the pr4-dsse-bundle-support branch from 42ff244 to 517acd6 Compare November 3, 2025 15:56
wolfv added 2 commits November 3, 2025 17:14
Signed-off-by: Wolf Vollprecht <[email protected]>
Signed-off-by: Wolf Vollprecht <[email protected]>
Copy link
Member

@Xynnn007 Xynnn007 left a comment

Choose a reason for hiding this comment

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

Hi @wolfv , nice work! I am also seeking to add support oci v1.1 & bundle v0.3 support in sigstore-rs to work with images signed by cosign v3. Some comments

use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Dsse {
Copy link
Member

Choose a reason for hiding this comment

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

We can use #[serde(rename_all = "camelCase")] macro upon this struct to avoid each field-level serde macros. According to document https://serde.rs/attr-rename.html

Comment on lines +38 to +45
pub struct Spec {
#[serde(rename = "root", skip_serializing_if = "Option::is_none")]
pub root: Option<String>,
#[serde(rename = "proposedContent")]
pub proposed_content: ProposedContent,
#[serde(rename = "payloadHash", skip_serializing_if = "Option::is_none")]
pub payload_hash: Option<Hash>,
}
Copy link
Member

Choose a reason for hiding this comment

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

Also, we can use #[serde(rename_all = "camelCase")] macro upon this struct to avoid each field-level serde macros. According to document https://serde.rs/attr-rename.html

Comment on lines +49 to +51
#[serde(rename = "envelope", skip_serializing_if = "Option::is_none")]
pub envelope: Option<String>,
#[serde(rename = "verifiers")]
Copy link
Member

Choose a reason for hiding this comment

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

looks like the two rename macro target is the same as field name, thus we might not need the rename macros?

Comment on lines +57 to +60
#[serde(rename = "algorithm")]
pub algorithm: String,
#[serde(rename = "value")]
pub value: String,
Copy link
Member

Choose a reason for hiding this comment

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

looks like the two rename macro target is the same as field name, thus we might not need the rename macros?

//! that can be signed and wrapped in DSSE envelopes.
//!
//! Note: This implements the v0.1 specification, which is currently used by cosign and Rekor.
//! See: <https://github.com/in-toto/attestation/blob/main/spec/v0.1.0/statement.md>
Copy link
Member

Choose a reason for hiding this comment

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

This file is not available. It might be the new link https://github.com/in-toto/attestation/tree/main/spec/v0.1.0#statement?

Comment on lines +64 to +75
pub fn new(
name: impl Into<String>,
algorithm: impl Into<String>,
digest: impl Into<String>,
) -> Self {
let mut digest_map = HashMap::new();
digest_map.insert(algorithm.into(), digest.into());
Self {
name: name.into(),
digest: digest_map,
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Just a little thought:

Could we make this new() to only receive name parameter? In this way it looks more "natural"

let subject = Subject::new("name")
    .with_digest(...)
    .with_digest(...);

Not sure this makes sense to you

/// Builds the statement.
///
/// Returns an error if required fields are missing.
pub fn build(self) -> Result<Statement, &'static str> {
Copy link
Member

Choose a reason for hiding this comment

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

Could we add a new error enum here and replace the Result<Statement, &'static str> with a unified error/result type?

let payload_json = serde_json::to_vec(statement)?;

Ok(Self(Envelope {
payload: payload_json, // Store RAW bytes, not base64!
Copy link
Member

Choose a reason for hiding this comment

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

I understand the purpose here is to make calculating PAE more convenient, even though the standard documentation requires base64 encoding. From a code maintenance perspective, it seems better to store this variable in standard base64 encoding?

wdyt?

//!
//! See: <https://github.com/secure-systems-lab/dsse/blob/v1.0.0/envelope.md>

use sigstore_protobuf_specs::io::intoto::{Envelope, Signature as DsseSignature};
Copy link
Member

Choose a reason for hiding this comment

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

We might need to re-export the Envelope and DsseSignature like

pub use sigstore_protobuf_specs::io::intoto::{Envelope, Signature as DsseSignature};

As the function signatures() and as_inner() returns the two structs, while we cannot expect the caller have imported the dependency sigstore_protobuf_specs

};
use std::fs;

#[test]
Copy link
Member

Choose a reason for hiding this comment

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

at the first glance, these test cases can be moved to under src/bundle/dsse.rs or src/bundle/mod.rs as unit tests, as they did not call codes of other parts of the project.

@wolfv
Copy link
Contributor Author

wolfv commented Dec 1, 2025

Hey @Xynnn007 thanks so much for your review. I'll try to address the comments swiftly. Just FYI I also started a separate project for a leaner sigstore implementation in Rust (no OCI handling and tiny crates here: https://github.com/wolfv/sigstore-rust - if you want to review / give your feedback on those / try them out that would be highly appreciated as well!).

@Xynnn007
Copy link
Member

Xynnn007 commented Dec 2, 2025

@wolfv Yes, will take a look!

if you want to review / give your feedback on those / try them out that would be highly appreciated as well!).

Good! I will take a look

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