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

add certificate based verification #159

Merged
merged 7 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pkcs1 = "0.4.0"
reqwest = { version = "0.11", default-features = false, features = ["json", "multipart"] }

[dev-dependencies]
anyhow = "1.0.54"
anyhow = { version = "1.0", features = ["backtrace"] }
assert-json-diff = "2.0.2"
chrono = "0.4.20"
clap = { version = "4.0.8", features = ["derive"] }
Expand Down
58 changes: 54 additions & 4 deletions examples/cosign/verify/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

extern crate sigstore;
use sigstore::cosign::verification_constraint::{
AnnotationVerifier, CertSubjectEmailVerifier, CertSubjectUrlVerifier, PublicKeyVerifier,
VerificationConstraintVec,
AnnotationVerifier, CertSubjectEmailVerifier, CertSubjectUrlVerifier, CertificateVerifier,
PublicKeyVerifier, VerificationConstraintVec,
};
use sigstore::cosign::{CosignCapabilities, SignatureLayer};
use sigstore::crypto::SigningScheme;
Expand All @@ -27,7 +27,7 @@ use std::convert::TryFrom;
use std::time::Instant;

extern crate anyhow;
use anyhow::anyhow;
use anyhow::{anyhow, Result};

extern crate clap;
use clap::Parser;
Expand All @@ -36,7 +36,7 @@ use std::{collections::HashMap, fs};
use tokio::task::spawn_blocking;

extern crate tracing_subscriber;
use tracing::info;
use tracing::{info, warn};
use tracing_subscriber::prelude::*;
use tracing_subscriber::{fmt, EnvFilter};

Expand All @@ -47,6 +47,14 @@ struct Cli {
#[clap(short, long, required(false))]
key: Option<String>,

/// Path to verification certificate
#[clap(long, required(false))]
cert: Option<String>,

/// Path to certificate chain bundle file
#[clap(long, required(false))]
cert_chain: Option<String>,

/// Signing scheme when signing and verifying
#[clap(long, required(false))]
signing_scheme: Option<String>,
Expand Down Expand Up @@ -106,6 +114,10 @@ async fn run_app(
));
}

if cli.key.is_some() && cli.cert.is_some() {
return Err(anyhow!("'key' and 'cert' cannot be used at the same time"));
}

let auth = &sigstore::registry::Auth::Anonymous;

let mut client_builder = sigstore::cosign::ClientBuilder::default();
Expand All @@ -114,6 +126,11 @@ async fn run_app(
client_builder = client_builder.with_rekor_pub_key(key);
}

let cert_chain: Option<Vec<sigstore::registry::Certificate>> = match cli.cert_chain.as_ref() {
None => None,
Some(cert_chain_path) => Some(parse_cert_bundle(&cert_chain_path)?),
};

if !frd.fulcio_certs.is_empty() {
client_builder = client_builder.with_fulcio_certs(&frd.fulcio_certs);
}
Expand Down Expand Up @@ -163,6 +180,24 @@ async fn run_app(

verification_constraints.push(Box::new(verifier));
}
if let Some(path_to_cert) = cli.cert.as_ref() {
let cert = fs::read(path_to_cert).map_err(|e| anyhow!("Cannot read cert: {:?}", e))?;
let require_rekor_bundle = if frd.rekor_pub_key.is_some() {
true
} else {
warn!("certificate based verification is weaker when Rekor integration is disabled");
false
};

let verifier = CertificateVerifier::from_pem(
&cert,
require_rekor_bundle,
cert_chain.as_ref().map(|v| v.as_slice()),
)
.map_err(|e| anyhow!("Cannot create certificate verifier: {}", e))?;

verification_constraints.push(Box::new(verifier));
}

if !cli.annotations.is_empty() {
let mut values: HashMap<String, String> = HashMap::new();
Expand Down Expand Up @@ -266,6 +301,7 @@ pub async fn main() {
&trusted_layers,
verification_constraints.iter(),
);

match filter_result {
Ok(()) => {
println!("Image successfully verified");
Expand All @@ -291,3 +327,17 @@ pub async fn main() {
}
}
}

fn parse_cert_bundle(bundle_path: &str) -> Result<Vec<sigstore::registry::Certificate>> {
let data =
fs::read(bundle_path).map_err(|e| anyhow!("Error reading {}: {}", bundle_path, e))?;
let pems = pem::parse_many(&data)?;

Ok(pems
.iter()
.map(|pem| sigstore::registry::Certificate {
encoding: sigstore::registry::CertificateEncoding::Der,
data: pem.contents.clone(),
})
.collect())
}
2 changes: 1 addition & 1 deletion src/cosign/signature_layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl CertificateSignature {
let integrated_time = trusted_bundle.payload.integrated_time;

// ensure the certificate has been issued by Fulcio
fulcio_cert_pool.verify(cert_raw)?;
fulcio_cert_pool.verify_pem_cert(cert_raw)?;

crypto::certificate::is_trusted(&cert, integrated_time)?;

Expand Down
Loading