diff --git a/Cargo.lock b/Cargo.lock index a3dca27..65700eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3670,15 +3670,6 @@ dependencies = [ [[package]] name = "verify-attestation" version = "0.1.2-alpha.1" -dependencies = [ - "anyhow", - "hex", - "teepot", -] - -[[package]] -name = "verify-attestation-sgx" -version = "0.1.2-alpha.1" dependencies = [ "alloy-primitives", "anyhow", diff --git a/bin/verify-attestation-sgx/Cargo.toml b/bin/verify-attestation-sgx/Cargo.toml deleted file mode 100644 index feed910..0000000 --- a/bin/verify-attestation-sgx/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "verify-attestation-sgx" -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true -repository.workspace = true -homepage.workspace = true - -[dependencies] -alloy-primitives.workspace = true -anyhow.workspace = true -clap.workspace = true -hex.workspace = true -secp256k1.workspace = true -teepot.workspace = true diff --git a/bin/verify-attestation-sgx/src/main.rs b/bin/verify-attestation-sgx/src/main.rs deleted file mode 100644 index 2a0273a..0000000 --- a/bin/verify-attestation-sgx/src/main.rs +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs - -//! Tool for SGX attestation and batch signature verification - -use alloy_primitives::B256; -use anyhow::{Context, Result}; -use clap::{Args, Parser, Subcommand}; -use secp256k1::{ecdsa::Signature, Message, PublicKey}; -use std::fs; -use std::path::PathBuf; -use std::time::UNIX_EPOCH; -use teepot::{ - client::TcbLevel, - sgx::{tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, -}; - -#[derive(Parser, Debug)] -#[command(author = "Matter Labs", version, about = "SGX attestation and batch signature verifier", long_about = None)] -struct Arguments { - /// File with attestation quote proving signature originated from a TEE enclave. - #[clap()] - attestation_file: PathBuf, - /// An optional subcommand, for instance, for optional signature verification. - #[clap(subcommand)] - command: Option, -} - -#[derive(Args, Debug)] -struct SignatureArgs { - /// File containing a batch signature signed within a TEE enclave. - #[arg(long)] - signature_file: PathBuf, - /// Batch root hash for signature verification. - #[arg(long)] - root_hash: B256, -} - -#[derive(Subcommand, Debug)] -enum SubCommands { - /// Provide both signature_file and root_hash - SignVerify(SignatureArgs), -} - -fn main() -> Result<()> { - let args = Arguments::parse(); - - let attestation_quote_bytes = fs::read(&args.attestation_file)?; - let quote_verification_result = verify_attestation_quote(&attestation_quote_bytes)?; - print_quote_verification_summary("e_verification_result); - - match &args.command { - Some(SubCommands::SignVerify(signature_args)) => { - verify_signature("e_verification_result, signature_args)?; - } - None => {} - } - Ok(()) -} - -fn verify_signature( - quote_verification_result: &QuoteVerificationResult, - signature_args: &SignatureArgs, -) -> Result<()> { - let reportdata = "e_verification_result.quote.report_body.reportdata; - let public_key = PublicKey::from_slice(reportdata)?; - println!("Public key from attestation quote: {}", public_key); - let signature_bytes = fs::read(&signature_args.signature_file)?; - let signature = Signature::from_compact(&signature_bytes)?; - let root_hash_msg = Message::from_digest_slice(&signature_args.root_hash.0)?; - if signature.verify(&root_hash_msg, &public_key).is_ok() { - println!("Signature verified successfully"); - } else { - println!("Failed to verify signature"); - } - Ok(()) -} - -fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { - println!( - "Verifying quote ({} bytes)...", - attestation_quote_bytes.len() - ); - let collateral = - tee_qv_get_collateral(&attestation_quote_bytes).context("Failed to get collateral")?; - let unix_time: i64 = std::time::SystemTime::now() - .duration_since(UNIX_EPOCH)? - .as_secs() as _; - verify_quote_with_collateral(&attestation_quote_bytes, Some(&collateral), unix_time) - .context("Failed to verify quote with collateral") -} - -fn print_quote_verification_summary(quote_verification_result: &QuoteVerificationResult) { - let QuoteVerificationResult { - collateral_expired, - result, - - quote, - advisories, - .. - } = quote_verification_result; - if *collateral_expired { - println!("Freshly fetched collateral expired"); - } - let tcblevel = TcbLevel::from(*result); - for advisory in advisories { - println!("\tInfo: Advisory ID: {advisory}"); - } - println!("Quote verification result: {}", tcblevel); - println!("mrsigner: {}", hex::encode(quote.report_body.mrsigner)); - println!("mrenclave: {}", hex::encode(quote.report_body.mrenclave)); - println!("reportdata: {}", hex::encode(quote.report_body.reportdata)); -} diff --git a/bin/verify-attestation/Cargo.toml b/bin/verify-attestation/Cargo.toml index 007b526..9a17bfc 100644 --- a/bin/verify-attestation/Cargo.toml +++ b/bin/verify-attestation/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true repository.workspace = true [dependencies] +alloy-primitives.workspace = true anyhow.workspace = true +clap.workspace = true hex.workspace = true +secp256k1.workspace = true teepot.workspace = true diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index 7fa15d6..3b8ffc1 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -1,60 +1,134 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2023-2024 Matter Labs -//! Simple TEE attestation verification test +//! Tool for SGX attestation and batch signature verification -#![deny(missing_docs)] -#![deny(clippy::all)] +use alloy_primitives::B256; +use anyhow::{Context, Result}; +use clap::{Args, Parser, Subcommand}; +use secp256k1::{ecdsa::Signature, Message, PublicKey}; +use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; +use teepot::{ + client::TcbLevel, + sgx::{tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, +}; -use anyhow::{bail, Context, Result}; -use std::io::Read; -use std::time::UNIX_EPOCH; -use teepot::client::TcbLevel; -use teepot::sgx::{tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}; +#[derive(Parser, Debug)] +#[command(author = "Matter Labs", version, about = "SGX attestation and batch signature verifier", long_about = None)] +struct Arguments { + /// Attestation quote proving the signature originated from a TEE enclave. + #[clap(value_parser)] + attestation: ArgSource, + /// An optional subcommand, for instance, for optional signature verification. + #[clap(subcommand)] + command: Option, +} + +#[derive(Debug, Clone)] +enum ArgSource { + File(PathBuf), + Stdin, +} + +impl FromStr for ArgSource { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + "-" => Ok(ArgSource::Stdin), + _ => Ok(ArgSource::File(PathBuf::from(s))), + } + } +} + +#[derive(Args, Debug)] +struct SignatureArgs { + /// File containing a batch signature signed within a TEE enclave. + #[arg(long)] + signature_file: PathBuf, + /// Batch root hash for signature verification. + #[arg(long)] + root_hash: B256, +} + +#[derive(Subcommand, Debug)] +enum SubCommands { + /// Verify a batch signature signed within a TEE enclave. + SignVerify(SignatureArgs), +} fn main() -> Result<()> { - // read myquote from stdin - let mut myquote = Vec::new(); - std::io::stdin() - .read_to_end(&mut myquote) - .context("Failed to read quote from stdin")?; + let args = Arguments::parse(); + let attestation_quote_bytes = match args.attestation { + ArgSource::File(path) => fs::read(&path)?, + ArgSource::Stdin => { + let mut quote = Vec::new(); + std::io::stdin() + .read_to_end(&mut quote) + .context("Failed to read attestation quote from stdin")?; + quote + } + }; + let quote_verification_result = verify_attestation_quote(&attestation_quote_bytes)?; + print_quote_verification_summary("e_verification_result); + match &args.command { + Some(SubCommands::SignVerify(signature_args)) => { + verify_signature("e_verification_result, signature_args)?; + } + None => {} + } + Ok(()) +} - println!("Verifying quote ({} bytes)...", myquote.len()); - - let collateral = tee_qv_get_collateral(&myquote).context("Failed to get collateral")?; +fn verify_signature( + quote_verification_result: &QuoteVerificationResult, + signature_args: &SignatureArgs, +) -> Result<()> { + let reportdata = "e_verification_result.quote.report_body.reportdata; + let public_key = PublicKey::from_slice(reportdata)?; + println!("Public key from attestation quote: {}", public_key); + let signature_bytes = fs::read(&signature_args.signature_file)?; + let signature = Signature::from_compact(&signature_bytes)?; + let root_hash_msg = Message::from_digest_slice(&signature_args.root_hash.0)?; + if signature.verify(&root_hash_msg, &public_key).is_ok() { + println!("Signature verified successfully"); + } else { + println!("Failed to verify signature"); + } + Ok(()) +} +fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { + println!( + "Verifying quote ({} bytes)...", + attestation_quote_bytes.len() + ); + let collateral = + tee_qv_get_collateral(&attestation_quote_bytes).context("Failed to get collateral")?; let unix_time: i64 = std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() + .duration_since(UNIX_EPOCH)? .as_secs() as _; + verify_quote_with_collateral(&attestation_quote_bytes, Some(&collateral), unix_time) + .context("Failed to verify quote with collateral") +} +fn print_quote_verification_summary(quote_verification_result: &QuoteVerificationResult) { let QuoteVerificationResult { collateral_expired, result, - quote, advisories, .. - } = verify_quote_with_collateral(&myquote, Some(&collateral), unix_time.saturating_add(60)) - .context("Failed to verify quote with collateral")?; - - if collateral_expired { - bail!("Freshly fetched collateral expired"); + } = quote_verification_result; + if *collateral_expired { + println!("Freshly fetched collateral expired"); } - - let tcblevel = TcbLevel::from(result); - if tcblevel != TcbLevel::Ok { - println!("Quote verification result: {}", tcblevel); - } - + let tcblevel = TcbLevel::from(*result); for advisory in advisories { println!("\tInfo: Advisory ID: {advisory}"); } - - println!("Quote verified successfully: {}", tcblevel); + println!("Quote verification result: {}", tcblevel); println!("mrsigner: {}", hex::encode(quote.report_body.mrsigner)); println!("mrenclave: {}", hex::encode(quote.report_body.mrenclave)); println!("reportdata: {}", hex::encode(quote.report_body.reportdata)); - - Ok(()) } diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index 8f04925..1a8745c 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -29,7 +29,6 @@ "vault_admin" "vault_unseal" "verify_attestation" - "verify_attestation_sgx" ]; postInstall = '' removeReferencesToVendoredSources "$out" "$cargoVendorDir"