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

verify: init #311

Merged
merged 29 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
69f64fa
verify: init
jleightcap Jan 3, 2024
6af5c49
pr feedback 2024-01-31
jleightcap Jan 31, 2024
afdf3b0
tuf: fixup target fetching
tnytown Feb 15, 2024
4dc13fe
sign, verify: use `sigstore-protobuf-specs` 0.3.2
tnytown Feb 15, 2024
428aa41
Add `bundle` feature
tnytown Feb 15, 2024
7d0db8b
verify: rework certificate validation
tnytown Feb 15, 2024
ffc2232
crypto: fixup is_root_ca & usages
tnytown Feb 16, 2024
0e79204
conformance: fixup
tnytown Feb 16, 2024
68fea4a
`cargo fmt`
tnytown Feb 16, 2024
752f87f
sign, verify: add TODOs for SCT verification
tnytown Feb 16, 2024
5c6854a
verify, crypto: asyncify, revamp error handling
tnytown Feb 23, 2024
d9fff73
verify: relax `'static` bound on async `verify`
tnytown Feb 23, 2024
8a80a36
sign, crypto: review comments
tnytown Feb 23, 2024
526c2a2
verify: basic `Verifier` / `AsyncVerifier` docs
tnytown Feb 23, 2024
230ead7
crypto/certificate: move `ExtensionErrorKind` up
tnytown Feb 23, 2024
fe83993
feedback from review
tnytown Feb 26, 2024
ce0c6cb
certificate: undo is_ca feedback changes
tnytown Feb 26, 2024
126442e
chore(deps): Update json-syntax requirement from 0.11.1 to 0.12.2
dependabot[bot] Feb 26, 2024
18a17c0
Merge remote-tracking branch 'origin/main' into jl/verify
tnytown Feb 28, 2024
34985ad
Merge remote-tracking branch 'origin/main' into jl/verify
tnytown Apr 9, 2024
caec81c
2024-04-10 pr feedback
tnytown Apr 10, 2024
11970d5
verify: publicize `verify_digest`
tnytown Apr 10, 2024
39ea179
`cargo fmt`
tnytown Apr 10, 2024
ecf8995
adjust `bundle`, `sign`, `verify` feature flags
tnytown Apr 10, 2024
3f150a2
fixup `cargo build` on features `bundle, wasm`
tnytown Apr 10, 2024
81ae539
verifier: fixup time range check
tnytown Apr 11, 2024
71f5161
trust/sigstore: test caching behavior
tnytown Apr 11, 2024
1e73783
`sign`, `verify`: reparent to `bundle`, doc fixups
tnytown Apr 11, 2024
c018346
trust/sigstore: rework tests
tnytown Apr 12, 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
22 changes: 13 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ readme = "README.md"
repository = "https://github.com/sigstore/sigstore-rs"

[features]
default = ["full-native-tls", "cached-client", "tuf", "sign"]
wasm = ["getrandom/js"]
default = ["full-native-tls", "cached-client", "tuf", "sign", "verify"]
wasm = ["getrandom/js", "ring/wasm32_unknown_unknown_js"]

full-native-tls = [
"fulcio-native-tls",
Expand Down Expand Up @@ -42,7 +42,9 @@ rekor = ["reqwest"]

tuf = ["tough", "regex"]

sign = []
bundle = []
sign = ["bundle"]
verify = ["bundle"]

cosign-native-tls = [
"oci-distribution/native-tls",
Expand Down Expand Up @@ -75,7 +77,7 @@ base64 = "0.21.0"
cached = { version = "0.49.2", optional = true, features = ["async"] }
cfg-if = "1.0.0"
chrono = { version = "0.4.27", default-features = false, features = ["serde"] }
const-oid = "0.9.1"
const-oid = { version = "0.9.6", features = ["db"] }
digest = { version = "0.10.3", default-features = false }
ecdsa = { version = "0.16.7", features = ["pkcs8", "digest", "der", "signing"] }
ed25519 = { version = "2.2.1", features = ["alloc"] }
Expand All @@ -87,9 +89,9 @@ olpc-cjson = "0.1"
openidconnect = { version = "3.0", default-features = false, features = [
"reqwest",
], optional = true }
p256 = "0.13.2"
p256 = "0.13"
p384 = "0.13"
webbrowser = "0.8.4"
webbrowser = "0.8.12"
pem = { version = "3.0", features = ["serde"] }
pkcs1 = { version = "0.7.5", features = ["std"] }
pkcs8 = { version = "0.10.2", features = [
Expand All @@ -109,23 +111,25 @@ rsa = "0.9.2"
scrypt = "0.11.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
serde_with = { version = "3.4.0", features = ["base64"] }
flavio marked this conversation as resolved.
Show resolved Hide resolved
serde_with = { version = "3.4.0", features = ["base64", "json"] }
sha2 = { version = "0.10.6", features = ["oid"] }
signature = { version = "2.0" }
sigstore_protobuf_specs = "0.1.0-rc.2"
sigstore_protobuf_specs = "0.3.2"
thiserror = "1.0.30"
tokio = { version = "1.17.0", features = ["rt"] }
tokio-util = { version = "0.7.10", features = ["io-util"] }
tough = { version = "0.14", features = ["http"], optional = true }
tracing = "0.1.31"
url = "2.2.2"
x509-cert = { version = "0.2.2", features = ["builder", "pem", "std"] }
x509-cert = { version = "0.2.5", features = ["builder", "pem", "std", "sct"] }
crypto_secretbox = "0.1.1"
zeroize = "1.5.7"
rustls-webpki = { version = "0.102.1", features = ["alloc"] }
serde_repr = "0.1.16"
hex = "0.4.3"
json-syntax = { version = "0.12.2", features = ["canonicalize", "serde"] }
tls_codec = { version = "0.4.1", features = ["derive"] }
ring = "0.17.6"

[dev-dependencies]
anyhow = { version = "1.0", features = ["backtrace"] }
Expand Down
2 changes: 1 addition & 1 deletion examples/cosign/verify/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ async fn fulcio_and_rekor_data(cli: &Cli) -> anyhow::Result<Box<dyn sigstore::tu
if cli.use_sigstore_tuf_data {
let repo: sigstore::errors::Result<SigstoreRepository> = spawn_blocking(|| {
info!("Downloading data from Sigstore TUF repository");
SigstoreRepository::new(None)?.prefetch()
SigstoreRepository::new(None)
})
.await
.map_err(|e| anyhow!("Error spawning blocking task inside of tokio: {}", e))?;
Expand Down
94 changes: 91 additions & 3 deletions src/bundle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,109 @@
//! Useful types for Sigstore bundles.

use std::fmt::Display;
use std::str::FromStr;

pub use sigstore_protobuf_specs::Bundle;
use base64::{engine::general_purpose::STANDARD as base64, Engine as _};
use json_syntax::Print;
pub use sigstore_protobuf_specs::dev::sigstore::bundle::v1::Bundle;
use sigstore_protobuf_specs::dev::sigstore::{
common::v1::LogId,
rekor::v1::{Checkpoint, InclusionPromise, InclusionProof, KindVersion, TransparencyLogEntry},
};

use crate::rekor::models::{
log_entry::InclusionProof as RekorInclusionProof, LogEntry as RekorLogEntry,
};

// Known Sigstore bundle media types.
#[derive(Clone, Copy, Debug)]
pub enum Version {
_Bundle0_1,
Bundle0_1,
Bundle0_2,
}

impl Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match &self {
Version::_Bundle0_1 => "application/vnd.dev.sigstore.bundle+json;version=0.1",
Version::Bundle0_1 => "application/vnd.dev.sigstore.bundle+json;version=0.1",
Version::Bundle0_2 => "application/vnd.dev.sigstore.bundle+json;version=0.2",
})
}
}

impl FromStr for Version {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"application/vnd.dev.sigstore.bundle+json;version=0.1" => Ok(Version::Bundle0_1),
"application/vnd.dev.sigstore.bundle+json;version=0.2" => Ok(Version::Bundle0_2),
_ => Err(()),
}
}
}

#[inline]
fn decode_hex<S: AsRef<str>>(hex: S) -> Result<Vec<u8>, ()> {
hex::decode(hex.as_ref()).or(Err(()))
}

impl TryFrom<RekorInclusionProof> for InclusionProof {
type Error = ();

fn try_from(value: RekorInclusionProof) -> Result<Self, Self::Error> {
let hashes = value
.hashes
.iter()
.map(decode_hex)
.collect::<Result<Vec<_>, _>>()?;

Ok(InclusionProof {
checkpoint: Some(Checkpoint {
envelope: value.checkpoint,
}),
hashes,
log_index: value.log_index,
root_hash: decode_hex(value.root_hash)?,
tree_size: value.tree_size,
})
}
}

/// Convert log entries returned from Rekor into Sigstore Bundle format entries.
impl TryFrom<RekorLogEntry> for TransparencyLogEntry {
type Error = ();

fn try_from(value: RekorLogEntry) -> Result<Self, Self::Error> {
let canonicalized_body = {
let mut body = json_syntax::to_value(value.body).or(Err(()))?;
body.canonicalize();
body.compact_print().to_string().into_bytes()
};
let inclusion_promise = Some(InclusionPromise {
signed_entry_timestamp: base64
.decode(value.verification.signed_entry_timestamp)
.or(Err(()))?,
});
let inclusion_proof = value
.verification
.inclusion_proof
.map(|p| p.try_into())
.transpose()?;

Ok(TransparencyLogEntry {
canonicalized_body,
inclusion_promise,
inclusion_proof,
integrated_time: value.integrated_time,
kind_version: Some(KindVersion {
kind: "hashedrekord".to_owned(),
version: "0.0.1".to_owned(),
flavio marked this conversation as resolved.
Show resolved Hide resolved
}),
log_id: Some(LogId {
key_id: decode_hex(value.log_i_d)?,
}),
log_index: value.log_index,
})
}
}
10 changes: 5 additions & 5 deletions src/cosign/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ pub const CONFIG_DATA: &str = "{}";
/// Cosign Client
///
/// Instances of `Client` can be built via [`sigstore::cosign::ClientBuilder`](crate::cosign::ClientBuilder).
pub struct Client<'a> {
pub struct Client {
pub(crate) registry_client: Box<dyn crate::registry::ClientCapabilities>,
pub(crate) rekor_pub_key: Option<CosignVerificationKey>,
pub(crate) fulcio_cert_pool: Option<CertificatePool<'a>>,
pub(crate) fulcio_cert_pool: Option<CertificatePool>,
}

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl CosignCapabilities for Client<'_> {
impl CosignCapabilities for Client {
async fn triangulate(
&mut self,
image: &OciReference,
Expand Down Expand Up @@ -140,7 +140,7 @@ impl CosignCapabilities for Client<'_> {
}
}

impl Client<'_> {
impl Client {
/// Internal helper method used to fetch data from an OCI registry
async fn fetch_manifest_and_layers(
&mut self,
Expand Down Expand Up @@ -177,7 +177,7 @@ mod tests {
use crate::crypto::SigningScheme;
use crate::mock_client::test::MockOciClient;

fn build_test_client(mock_client: MockOciClient) -> Client<'static> {
fn build_test_client(mock_client: MockOciClient) -> Client {
let rekor_pub_key =
CosignVerificationKey::from_pem(REKOR_PUB_KEY.as_bytes(), &SigningScheme::default())
.expect("Cannot create CosignVerificationKey");
Expand Down
2 changes: 1 addition & 1 deletion src/cosign/client_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl<'a> ClientBuilder<'a> {
self
}

pub fn build(self) -> Result<Client<'a>> {
pub fn build(self) -> Result<Client> {
let rekor_pub_key = match self.rekor_pub_key {
None => {
info!("Rekor public key not provided. Rekor integration disabled");
Expand Down
4 changes: 2 additions & 2 deletions src/cosign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
#[cfg(feature = "test-registry")]
const SIGNED_IMAGE: &str = "busybox:1.34";

pub(crate) fn get_fulcio_cert_pool() -> CertificatePool<'static> {
pub(crate) fn get_fulcio_cert_pool() -> CertificatePool {
fn pem_to_der<'a>(input: &'a str) -> CertificateDer<'a> {
let pem_cert = pem::parse(input).unwrap();
assert_eq!(pem_cert.tag(), "CERTIFICATE");
Expand Down Expand Up @@ -644,7 +644,7 @@ TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ
}

#[cfg(feature = "test-registry")]
async fn prepare_image_to_be_signed(client: &mut Client<'_>, image_ref: &OciReference) {
async fn prepare_image_to_be_signed(client: &mut Client, image_ref: &OciReference) {
let data = client
.registry_client
.pull(
Expand Down
Loading
Loading