diff --git a/attestation-service/verifier/Cargo.toml b/attestation-service/verifier/Cargo.toml index 3a3a8a8820..89246e4d38 100644 --- a/attestation-service/verifier/Cargo.toml +++ b/attestation-service/verifier/Cargo.toml @@ -16,6 +16,7 @@ cca-verifier = [ "ear", "jsonwebtoken", "veraison-apiclient" ] [dependencies] anyhow.workspace = true +thiserror.workspace=true asn1-rs = { version = "0.5.1", optional = true } async-trait.workspace = true az-snp-vtpm = { version = "0.5.1", default-features = false, features = ["verifier"], optional = true } @@ -30,6 +31,7 @@ csv-rs = { git = "https://github.com/openanolis/csv-rs", rev = "b74aa8c", option eventlog-rs = { version = "0.1.3", optional = true } hex.workspace = true jsonwebtoken = { workspace = true, default-features = false, optional = true } +jsonwebkey = "0.3.5" kbs-types.workspace = true log.workspace = true openssl = { version = "0.10.55", optional = true } diff --git a/attestation-service/verifier/src/az_snp_vtpm/mod.rs b/attestation-service/verifier/src/az_snp_vtpm/mod.rs index 0dfdc6f8c6..2e2d66c705 100644 --- a/attestation-service/verifier/src/az_snp_vtpm/mod.rs +++ b/attestation-service/verifier/src/az_snp_vtpm/mod.rs @@ -5,6 +5,9 @@ use crate::{InitDataHash, ReportData}; +use az_snp_vtpm::vtpm::QuoteError; +use thiserror::Error; + use super::{TeeEvidenceParsedClaim, Verifier}; use crate::snp::{ load_milan_cert_chain, parse_tee_evidence, verify_report_signature, VendorCertificates, @@ -33,10 +36,28 @@ pub struct AzSnpVtpm { vendor_certs: VendorCertificates, } +#[derive(Error, Debug)] +pub enum CertError { + #[error("Failed to load Milan cert chain")] + LoadMilanCert, + #[error("TPM quote nonce doesn't match expected report_data")] + NonceMismatch, + #[error("SNP report report_data mismatch")] + SnpReportMismatch, + #[error("VMPL of SNP report is not {0}")] + VmplIncorrect(String), + #[error("Quote error")] + Quote(#[from] QuoteError), + #[error("jsonewebkey conversion error")] + JsonWebkey(#[from] jsonwebkey::ConversionError), + #[error(transparent)] + Anyhow(#[from] anyhow::Error), +} + impl AzSnpVtpm { - pub fn new() -> Result { + pub fn new() -> Result { let Result::Ok(vendor_certs) = load_milan_cert_chain() else { - bail!("Failed to load Milan cert chain"); + return Err(CertError::LoadMilanCert); }; let vendor_certs = vendor_certs.clone(); Ok(Self { vendor_certs }) @@ -88,10 +109,10 @@ impl Verifier for AzSnpVtpm { } } -fn verify_nonce(quote: &Quote, report_data: &[u8]) -> Result<()> { +fn verify_nonce(quote: &Quote, report_data: &[u8]) -> Result<(), CertError> { let nonce = quote.nonce()?; if nonce != report_data[..] { - bail!("TPM quote nonce doesn't match expected report_data"); + return Err(CertError::NonceMismatch); } debug!("TPM report_data verification completed successfully"); Ok(()) @@ -117,9 +138,12 @@ fn verify_pcrs(quote: &Quote) -> Result<()> { Ok(()) } -fn verify_report_data(var_data_hash: &[u8; 32], snp_report: &AttestationReport) -> Result<()> { +fn verify_report_data( + var_data_hash: &[u8; 32], + snp_report: &AttestationReport, +) -> Result<(), CertError> { if *var_data_hash != snp_report.report_data[..32] { - bail!("SNP report report_data mismatch"); + return Err(CertError::SnpReportMismatch); } debug!("SNP report_data verification completed successfully"); Ok(()) @@ -129,13 +153,13 @@ fn verify_snp_report( snp_report: &AttestationReport, vcek: &Vcek, vendor_certs: &VendorCertificates, -) -> Result<()> { +) -> Result<(), CertError> { let vcek_data = vcek.0.to_der().context("Failed to get raw VCEK data")?; let cert_chain = [CertTableEntry::new(CertType::VCEK, vcek_data)]; verify_report_signature(snp_report, &cert_chain, vendor_certs)?; if snp_report.vmpl != HCL_VMPL_VALUE { - bail!("VMPL of SNP report is not {HCL_VMPL_VALUE}"); + return Err(CertError::VmplIncorrect(HCL_VMPL_VALUE.to_string())); } Ok(())