Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Repository trait and ManualRepository struct no longer require a feature flag #331

Merged
merged 18 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
717fb2d
Moved the Repository trait and the ManualRepository struct out of 'tu…
tannaurus Feb 26, 2024
5588934
Re-exported Repository trait and ManualRepository struct out of 'tuf'…
tannaurus Feb 26, 2024
8db4b11
Corrected previous commit: had previously re-exported from the wrong …
tannaurus Feb 27, 2024
05be0b4
Corrected copyright date: 2021 -> 2024
tannaurus Feb 27, 2024
97357d3
Removed 'repository' feature flag: 'repository' modual is no longer h…
tannaurus Feb 27, 2024
1b17986
Renamed 'tuf' feature flag to 'sigstore-repository'
tannaurus Feb 27, 2024
7ab25d0
Revert "Renamed 'tuf' feature flag to 'sigstore-repository'"
tannaurus Feb 28, 2024
7609a34
Renamed 'repository' modual to 'repo'
tannaurus Feb 28, 2024
0a72702
Removed left over 'all' cfg attr, left behind from a revert.
tannaurus Feb 28, 2024
2d1ceb9
Ran cargo fmt: set up Rust Rover recently and negelected to enable th…
tannaurus Mar 1, 2024
92685e6
Renames: mod repo -> mod trust. trait Repository -> trait TrustRoot. …
tannaurus Mar 1, 2024
78f680e
Renames: mod tuf -> mod sigstore
tannaurus Mar 1, 2024
54f236d
Moved: sigstore module (previously tuf module) moved into sub-module …
tannaurus Mar 1, 2024
77ed1f9
Renamed impacted types in /examples
tannaurus Mar 1, 2024
e7db276
Renames: SigstoreRespository -> SigstoreTrustRoot
tannaurus Mar 1, 2024
0ab5e61
Renames: struct SigstoreRepository -> struct SigstoreTrustRoot. featu…
tannaurus Mar 1, 2024
01f0fb1
Fixed up comments that still referenced previous iterations of the re…
tannaurus Mar 1, 2024
1f52b41
Renamed SigstoreRootTrust to SigstoreTrustRoot
tannaurus Mar 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ readme = "README.md"
repository = "https://github.com/sigstore/sigstore-rs"

[features]
default = ["full-native-tls", "cached-client", "tuf", "sign"]
default = ["full-native-tls", "cached-client", "sigstore-trust-root", "sign"]
wasm = ["getrandom/js"]

full-native-tls = [
Expand Down Expand Up @@ -40,7 +40,7 @@ rekor-native-tls = ["reqwest/native-tls", "rekor"]
rekor-rustls-tls = ["reqwest/rustls-tls", "rekor"]
rekor = ["reqwest"]

tuf = ["tough", "regex"]
sigstore-trust-root = ["tough", "regex"]

sign = []

Expand Down
12 changes: 6 additions & 6 deletions examples/cosign/verify/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use sigstore::cosign::{CosignCapabilities, SignatureLayer};
use sigstore::crypto::SigningScheme;
use sigstore::errors::SigstoreVerifyConstraintsError;
use sigstore::registry::{ClientConfig, ClientProtocol, OciReference};
use sigstore::tuf::SigstoreRepository;
use sigstore::trust::sigstore::SigstoreTrustRoot;
use std::boxed::Box;
use std::convert::TryFrom;
use std::time::Instant;
Expand Down Expand Up @@ -110,7 +110,7 @@ struct Cli {

async fn run_app(
cli: &Cli,
frd: &dyn sigstore::tuf::Repository,
frd: &dyn sigstore::trust::TrustRoot,
) -> anyhow::Result<(Vec<SignatureLayer>, VerificationConstraintVec)> {
// Note well: this a limitation deliberately introduced by this example.
if cli.cert_email.is_some() && cli.cert_url.is_some() {
Expand Down Expand Up @@ -228,19 +228,19 @@ async fn run_app(
Ok((trusted_layers, verification_constraints))
}

async fn fulcio_and_rekor_data(cli: &Cli) -> anyhow::Result<Box<dyn sigstore::tuf::Repository>> {
async fn fulcio_and_rekor_data(cli: &Cli) -> anyhow::Result<Box<dyn sigstore::trust::TrustRoot>> {
if cli.use_sigstore_tuf_data {
let repo: sigstore::errors::Result<SigstoreRepository> = spawn_blocking(|| {
let repo: sigstore::errors::Result<SigstoreTrustRoot> = spawn_blocking(|| {
info!("Downloading data from Sigstore TUF repository");
SigstoreRepository::new(None)?.prefetch()
SigstoreTrustRoot::new(None)?.prefetch()
})
.await
.map_err(|e| anyhow!("Error spawning blocking task inside of tokio: {}", e))?;

return Ok(Box::new(repo?));
};

let mut data = sigstore::tuf::ManualRepository::default();
let mut data = sigstore::trust::ManualTrustRoot::default();
if let Some(path) = cli.rekor_pub_key.as_ref() {
data.rekor_key = Some(
fs::read(path)
Expand Down
14 changes: 7 additions & 7 deletions src/cosign/client_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ use crate::crypto::SigningScheme;
use crate::crypto::{certificate_pool::CertificatePool, CosignVerificationKey};
use crate::errors::Result;
use crate::registry::ClientConfig;
use crate::tuf::Repository;
use crate::trust::TrustRoot;

/// A builder that generates Client objects.
///
/// ## Rekor integration
///
/// Rekor integration can be enabled by specifying Rekor's public key.
/// This can be provided via a [`crate::tuf::ManualRepository`].
/// This can be provided via a [`crate::sigstore::ManualTrustRoot`].
///
/// > Note well: the [`tuf`](crate::tuf) module provides helper structs and methods
/// > Note well: the [`sigstore`](crate::sigstore) module provides helper structs and methods
/// > to obtain this data from the official TUF repository of the Sigstore project.
///
/// ## Fulcio integration
///
/// Fulcio integration can be enabled by specifying Fulcio's certificate.
/// This can be provided via a [`crate::tuf::ManualRepository`].
/// This can be provided via a [`crate::sigstore::ManualTrustRoot`].
///
/// > Note well: the [`tuf`](crate::tuf) module provides helper structs and methods
/// > Note well: the [`sigstore`](crate::sigstore) module provides helper structs and methods
/// > to obtain this data from the official TUF repository of the Sigstore project.
///
/// ## Registry caching
Expand Down Expand Up @@ -71,8 +71,8 @@ impl<'a> ClientBuilder<'a> {
/// Optional - Configures the roots of trust.
///
/// Enables Fulcio and Rekor integration with the given trust repository.
/// See [crate::tuf::Repository] for more details on trust repositories.
pub fn with_trust_repository<R: Repository + ?Sized>(mut self, repo: &'a R) -> Result<Self> {
/// See [crate::sigstore::TrustRoot] for more details on trust repositories.
pub fn with_trust_repository<R: TrustRoot + ?Sized>(mut self, repo: &'a R) -> Result<Self> {
let rekor_keys = repo.rekor_keys()?;
if !rekor_keys.is_empty() {
self.rekor_pub_key = Some(rekor_keys[0]);
Expand Down
6 changes: 3 additions & 3 deletions src/cosign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ pub trait CosignCapabilities {
/// must be satisfied:
///
/// * The [`sigstore::cosign::Client`](crate::cosign::client::Client) must
/// have been created with Rekor integration enabled (see [`crate::tuf::ManualRepository`])
/// have been created with Rekor integration enabled (see [`crate::sigstore::ManualTrustRoot`])
/// * The [`sigstore::cosign::Client`](crate::cosign::client::Client) must
/// have been created with Fulcio integration enabled (see [`crate::tuf::ManualRepository])
/// have been created with Fulcio integration enabled (see [`crate::sigstore::ManualTrustRoot])
/// * The layer must include a bundle produced by Rekor
///
/// > Note well: the [`tuf`](crate::tuf) module provides helper structs and methods
/// > Note well: the [`sigstore`](crate::sigstore) module provides helper structs and methods
/// > to obtain this data from the official TUF repository of the Sigstore project.
///
/// When the embedded certificate cannot be verified, [`SignatureLayer::certificate_signature`]
Expand Down
2 changes: 1 addition & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub enum SigstoreError {
#[error("No Signature Layer passed verification")]
SigstoreNoVerifiedLayer,

#[cfg(feature = "tuf")]
#[cfg(feature = "sigstore-trust-root")]
#[error(transparent)]
TufError(#[from] Box<tough::error::Error>),

Expand Down
12 changes: 5 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
//!
//! Verify the signature of a container image/oci artifact:
//!
//! ```rust,no_run
//!```rust,no_run
//! use crate::sigstore::cosign::{
//! CosignCapabilities,
//! verify_constraints,
Expand Down Expand Up @@ -92,7 +92,7 @@
//! data: fulcio_cert_data
//! };
//!
//! let mut repo = sigstore::tuf::ManualRepository {
//! let mut repo = sigstore::trust::ManualTrustRoot {
//! fulcio_certs: Some(vec![fulcio_cert.try_into().unwrap()]),
//! rekor_key: Some(rekor_pub_key),
//! ..Default::default()
Expand Down Expand Up @@ -228,7 +228,7 @@
//! requires the following data to work: Fulcio's certificate and Rekor's public key.
//!
//! These files are safely distributed by the Sigstore project via a TUF repository.
//! The [`sigstore::tuf`](crate::tuf) module provides the helper structures to deal
//! The [`sigstore::trust::sigstore`](crate::trust::sigstore) module provides the helper structures to deal
//! with it.
//!
//! # Feature Flags
Expand All @@ -254,12 +254,13 @@
//! - `cached-client`: Enables support for OCI registry client caching.
//!
//! - `test-registry`: Enables tests based on a temporary OCI registry.
//! - `tuf`: Enables support for TUF to request for fulcio certs and rekor public key.
//! - `sigstore-trust-root`: Enables support for TUF to request for fulcio certs and rekor public key.

#![forbid(unsafe_code)]
#![warn(clippy::unwrap_used, clippy::panic)]

pub mod crypto;
pub mod trust;

#[cfg(feature = "mock-client")]
mod mock_client;
Expand All @@ -281,9 +282,6 @@ pub mod registry;
#[cfg(feature = "rekor")]
pub mod rekor;

#[cfg(feature = "tuf")]
pub mod tuf;

// Don't export yet -- these types should only be useful internally.
mod bundle;
pub use bundle::Bundle;
Expand Down
49 changes: 49 additions & 0 deletions src/trust/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use webpki::types::CertificateDer;

#[cfg(feature = "sigstore-trust-root")]
pub mod sigstore;

/// A `TrustRoot` owns all key material necessary for establishing a root of trust.
pub trait TrustRoot {
fn fulcio_certs(&self) -> crate::errors::Result<Vec<CertificateDer>>;
fn rekor_keys(&self) -> crate::errors::Result<Vec<&[u8]>>;
}

/// A `ManualTrustRoot` is a [TrustRoot] with out-of-band trust materials.
/// As it does not establish a trust root with TUF, users must initialize its materials themselves.
#[derive(Debug, Default)]
pub struct ManualTrustRoot<'a> {
pub fulcio_certs: Option<Vec<CertificateDer<'a>>>,
pub rekor_key: Option<Vec<u8>>,
}

impl TrustRoot for ManualTrustRoot<'_> {
fn fulcio_certs(&self) -> crate::errors::Result<Vec<CertificateDer>> {
Ok(match &self.fulcio_certs {
Some(certs) => certs.clone(),
None => Vec::new(),
})
}

fn rekor_keys(&self) -> crate::errors::Result<Vec<&[u8]>> {
Ok(match &self.rekor_key {
Some(key) => vec![&key[..]],
None => Vec::new(),
})
}
}
File renamed without changes.
54 changes: 13 additions & 41 deletions src/tuf/mod.rs → src/trust/sigstore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@

//! Helper Structs to interact with the Sigstore TUF repository.
//!
//! The main interaction point is [`SigstoreRepository`], which fetches Rekor's
//! The main interaction point is [`SigstoreTrustRoot`], which fetches Rekor's
//! public key and Fulcio's certificate.
//!
//! These can later be given to [`cosign::ClientBuilder`](crate::cosign::ClientBuilder)
//! to enable Fulcio and Rekor integrations.
//!
//! # Example
//!
//! The `SigstoreRepository` instance can be created via the [`SigstoreRepository::prefetch`]
//! The `SigstoreRootTrust` instance can be created via the [`SigstoreTrustRoot::prefetch`]
//! method.
//!
//! ```rust,no_run
//! use sigstore::tuf::SigstoreRepository;
//! let repo = SigstoreRepository::new(None).unwrap().prefetch().unwrap();
//! use sigstore::trust::sigstore::SigstoreTrustRoot;
//! let repo = SigstoreTrustRoot::new(None).unwrap().prefetch().unwrap();
//! ```
use std::{
cell::OnceCell,
Expand All @@ -47,47 +47,19 @@ use webpki::types::CertificateDer;

use self::trustroot::{CertificateAuthority, TimeRange, TransparencyLogInstance, TrustedRoot};

use super::errors::{Result, SigstoreError};
use crate::errors::{Result, SigstoreError};

/// A `Repository` owns all key material necessary for establishing a root of trust.
pub trait Repository {
fn fulcio_certs(&self) -> Result<Vec<CertificateDer>>;
fn rekor_keys(&self) -> Result<Vec<&[u8]>>;
}

/// A `ManualRepository` is a [Repository] with out-of-band trust materials.
/// As it does not establish a trust root with TUF, users must initialize its materials themselves.
#[derive(Debug, Default)]
pub struct ManualRepository<'a> {
pub fulcio_certs: Option<Vec<CertificateDer<'a>>>,
pub rekor_key: Option<Vec<u8>>,
}

impl Repository for ManualRepository<'_> {
fn fulcio_certs(&self) -> Result<Vec<CertificateDer>> {
Ok(match &self.fulcio_certs {
Some(certs) => certs.clone(),
None => Vec::new(),
})
}

fn rekor_keys(&self) -> Result<Vec<&[u8]>> {
Ok(match &self.rekor_key {
Some(key) => vec![&key[..]],
None => Vec::new(),
})
}
}
pub use crate::trust::{ManualTrustRoot, TrustRoot};

/// Securely fetches Rekor public key and Fulcio certificates from Sigstore's TUF repository.
#[derive(Debug)]
pub struct SigstoreRepository {
pub struct SigstoreTrustRoot {
repository: tough::Repository,
checkout_dir: Option<PathBuf>,
trusted_root: OnceCell<TrustedRoot>,
}

impl SigstoreRepository {
impl SigstoreTrustRoot {
/// Constructs a new trust repository established by a [tough::Repository].
pub fn new(checkout_dir: Option<&Path>) -> Result<Self> {
// These are statically defined and should always parse correctly.
Expand Down Expand Up @@ -136,18 +108,18 @@ impl SigstoreRepository {

/// Prefetches trust materials.
///
/// [Repository::fulcio_certs()] and [Repository::rekor_keys()] on [SigstoreRepository] lazily
/// [TrustRoot::fulcio_certs()] and [TrustRoot::rekor_keys()] on [SigstoreTrustRoot] lazily
/// fetches the requested data, which is problematic for async callers. Those callers should
/// use this method to fetch the trust root ahead of time.
///
/// ```rust
/// # use tokio::task::spawn_blocking;
/// # use sigstore::tuf::SigstoreRepository;
/// # use sigstore::trust::sigstore::SigstoreTrustRoot;
/// # use sigstore::errors::Result;
/// # #[tokio::main]
/// # async fn main() -> std::result::Result<(), anyhow::Error> {
/// let repo: Result<SigstoreRepository> = spawn_blocking(|| Ok(SigstoreRepository::new(None)?.prefetch()?)).await?;
/// // Now, get Fulcio and Rekor trust roots with the returned `SigstoreRepository`
/// let repo: Result<SigstoreTrustRoot> = spawn_blocking(|| Ok(SigstoreTrustRoot::new(None)?.prefetch()?)).await?;
/// // Now, get Fulcio and Rekor trust roots with the returned `SigstoreRootTrust`
/// # Ok(())
/// # }
/// ```
Expand Down Expand Up @@ -177,7 +149,7 @@ impl SigstoreRepository {
}
}

impl Repository for SigstoreRepository {
impl crate::trust::TrustRoot for SigstoreTrustRoot {
/// Fetch Fulcio certificates from the given TUF repository or reuse
/// the local cache if its contents are not outdated.
///
Expand Down
File renamed without changes.
File renamed without changes.
Loading