Skip to content

Commit

Permalink
Merge pull request #186 from danbev/bundle-example
Browse files Browse the repository at this point in the history
Add cosign verify-bundle example
  • Loading branch information
flavio authored Jan 12, 2023
2 parents 438858d + 126b286 commit 084286a
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ serial_test = "0.10.0"
name = "verify"
path = "examples/cosign/verify/main.rs"

[[example]]
name = "verify-bundle"
path = "examples/cosign/verify-bundle/main.rs"

[[example]]
name = "sign"
path = "examples/cosign/sign/main.rs"
Expand Down
2 changes: 2 additions & 0 deletions examples/cosign/verify-bundle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
artifact.bundle
artifact.txt
20 changes: 20 additions & 0 deletions examples/cosign/verify-bundle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
This example shows how to verify a blob, using a bundle that was created by the
`cosign sign-blob` command.

### Create the artifact to be signed.
```console
echo something > artifact.txt
```

### Sign the artifact.txt file using cosign
```
COSIGN_EXPERIMENTAL=1 cosign sign-blob --bundle=artifact.bundle artifact.txt
```

### Verify using sigstore-rs:
```console
cargo run --example verify-bundle -- \
--rekor-pub-key ~/.sigstore/root/targets/rekor.pub \
--bundle artifact.bundle \
artifact.txt
```
68 changes: 68 additions & 0 deletions examples/cosign/verify-bundle/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// Copyright 2021 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 clap::Parser;
use sigstore::cosign::bundle::SignedArtifactBundle;
use sigstore::crypto::{CosignVerificationKey, SigningScheme};
use std::fs;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{fmt, EnvFilter};

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Path to bundle file
#[clap(short, long)]
bundle: String,

/// Path to artifact to be verified
blob: String,

/// File containing Rekor's public key (e.g.: ~/.sigstore/root/targets/rekor.pub)
#[clap(long, required(false))]
rekor_pub_key: String,

/// Enable verbose mode
#[clap(short, long)]
verbose: bool,
}

#[tokio::main]
pub async fn main() {
let cli = Cli::parse();

// setup logging
let level_filter = if cli.verbose { "debug" } else { "info" };
let filter_layer = EnvFilter::new(level_filter);
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt::layer().with_writer(std::io::stderr))
.init();

let rekor_pub_pem =
fs::read_to_string(&cli.rekor_pub_key).expect("error reading rekor's public key");
let rekor_pub_key =
CosignVerificationKey::from_pem(rekor_pub_pem.as_bytes(), &SigningScheme::default())
.expect("Cannot create Rekor verification key");
let bundle_json = fs::read_to_string(&cli.bundle).expect("error reading bundle json file");
let blob = fs::read(&cli.blob.as_str()).expect("error reading blob file");

let bundle = SignedArtifactBundle::new_verified(&bundle_json, &rekor_pub_key).unwrap();
if bundle.verify_blob(&blob).is_ok() {
println!("Verification succeeded");
} else {
eprintln!("Verification failed");
}
}
17 changes: 17 additions & 0 deletions examples/cosign/verify-bundle/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
BLOB="artifact.txt"
BUNDLE="artifact.bundle"

echo -e "\nGenerate the blob to be signed"
echo something > $BLOB

echo -e "\nSign the artifact.txt file using sign-blob"
COSIGN_EXPERIMENTAL=1 cosign sign-blob --bundle=$BUNDLE $BLOB

echo -e "\nVerify using cosign. TODO: remove this later"
cosign verify-blob --bundle=$BUNDLE $BLOB

echo -e "\nRun examples/cosign/verify-bundle"
cargo run --example verify-bundle -- \
--rekor-pub-key ~/.sigstore/root/targets/rekor.pub \
--bundle $BUNDLE \
$BLOB
19 changes: 17 additions & 2 deletions src/cosign/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use base64::{engine::general_purpose::STANDARD as BASE64_STD_ENGINE, Engine as _};
use olpc_cjson::CanonicalFormatter;
use serde::{Deserialize, Serialize};
use std::cmp::PartialEq;
use std::convert::TryFrom;

use crate::crypto::{CosignVerificationKey, Signature};
use crate::errors::{Result, SigstoreError};
Expand Down Expand Up @@ -43,13 +45,26 @@ impl SignedArtifactBundle {
///
/// **Note well:** The bundle will be returned only if it can be verified
/// using the supplied `rekor_pub_key` public key.
#[allow(dead_code)]
pub(crate) fn new_verified(raw: &str, rekor_pub_key: &CosignVerificationKey) -> Result<Self> {
pub fn new_verified(raw: &str, rekor_pub_key: &CosignVerificationKey) -> Result<Self> {
let bundle: SignedArtifactBundle = serde_json::from_str(raw).map_err(|e| {
SigstoreError::UnexpectedError(format!("Cannot parse bundle |{}|: {:?}", raw, e))
})?;
Bundle::verify_bundle(&bundle.rekor_bundle, rekor_pub_key).map(|_| bundle)
}

/// Verifies the passed-in blob against the signature in this
/// SignedArtifactBundle.
pub fn verify_blob(&self, blob: &[u8]) -> Result<()> {
let cert = BASE64_STD_ENGINE.decode(&self.cert)?;
let (_, pem) = x509_parser::pem::parse_x509_pem(&cert)?;
let (_, cert) = x509_parser::parse_x509_certificate(&pem.contents)?;
let subject_public_key = cert.public_key();
let ver_key =
CosignVerificationKey::try_from(subject_public_key).expect("conversion failed");
let signature = Signature::Base64Encoded(self.base64_signature.as_bytes());
ver_key.verify_signature(signature, blob)?;
Ok(())
}
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
Expand Down
2 changes: 1 addition & 1 deletion src/cosign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use tracing::warn;
use crate::errors::{Result, SigstoreApplicationConstraintsError, SigstoreVerifyConstraintsError};
use crate::registry::{Auth, PushResponse};

mod bundle;
pub mod bundle;
pub(crate) mod constants;
pub mod signature_layers;
pub use signature_layers::SignatureLayer;
Expand Down

0 comments on commit 084286a

Please sign in to comment.