use anyhow::Result;
use sigstore::crypto::{CosignVerificationKey, Signature};
use crate::errors::{LoadError, sbom_binds_component};
pub struct TrustPolicy {
keys: Vec<CosignVerificationKey>,
}
impl TrustPolicy {
pub fn from_pem_keys<I, B>(pems: I) -> Result<Self>
where
I: IntoIterator<Item = B>,
B: AsRef<[u8]>,
{
let keys = pems
.into_iter()
.map(|pem| {
CosignVerificationKey::try_from_pem(pem.as_ref())
.map_err(|e| anyhow::anyhow!("invalid trusted public key (PEM): {e}"))
})
.collect::<Result<Vec<_>>>()?;
Ok(Self { keys })
}
pub fn empty() -> Self {
Self { keys: Vec::new() }
}
pub(crate) fn verifies(&self, signature_der: &[u8], msg: &[u8]) -> bool {
self.keys.iter().any(|k| {
k.verify_signature(Signature::Raw(signature_der), msg)
.is_ok()
})
}
pub fn verify_artifact(&self, artifact: &SignedArtifact<'_>) -> Result<(), LoadError> {
if artifact.sbom.is_empty() {
return Err(LoadError::MissingSbom);
}
if !self.verifies(artifact.component_signature, artifact.component_bytes) {
return Err(LoadError::UnverifiedComponentSignature);
}
if !self.verifies(artifact.sbom_signature, artifact.sbom) {
return Err(LoadError::UnverifiedSbomSignature);
}
sbom_binds_component(artifact.sbom, artifact.component_bytes)
}
}
pub struct SignedArtifact<'a> {
pub component_bytes: &'a [u8],
pub component_signature: &'a [u8],
pub sbom: &'a [u8],
pub sbom_signature: &'a [u8],
}