Merge pull request #156 from matter-labs/patrick/sgx-attestation-verifier

feat(verify-attestation): attestation and batch signature verification binary
This commit is contained in:
Harald Hoyer 2024-07-12 08:54:36 +02:00 committed by GitHub
commit c48cbc636d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 879 additions and 179 deletions

900
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@ homepage = "https://github.com/matter-labs/teepot"
actix-http = "3"
actix-tls = "3"
actix-web = { version = "4.5", features = ["rustls-0_22"] }
alloy-primitives = "0.7.7"
anyhow = "1.0.82"
awc = { version = "3.4", features = ["rustls-0_22-webpki-roots"] }
base64 = "0.22.0"
@ -34,7 +35,7 @@ getrandom = "0.2.14"
hex = { version = "0.4.3", features = ["std"], default-features = false }
intel-tee-quote-verification-rs = { package = "teepot-tee-quote-verification-rs", path = "crates/teepot-tee-quote-verification-rs", version = "0.2.3-alpha.1" }
intel-tee-quote-verification-sys = { version = "0.2.1" }
secp256k1 = { version = "0.29", features = ["rand-std"] }
secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] }
log = "0.4"
num-integer = "0.1.46"
num-traits = "0.2.18"

View file

@ -14,7 +14,7 @@ $ nix build -L .#container-self-attestation-test-sgx-azure && docker load -i res
docker run -i --init --rm --privileged --device /dev/sgx_enclave \
matterlabsrobot/teepot-self-attestation-test-sgx-azure:latest \
| base64 -d --ignore-garbage \
| docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest
| docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest -
aesm_service: warning: Turn to daemon. Use "--no-daemon" option to execute in foreground.
Gramine is starting. Parsing TOML manifest file, this may take some time...
@ -33,7 +33,7 @@ reportdata: 00000000000000000000000000000000000000000000000000000000000000000000
docker run -i --init --rm --privileged --device /dev/sgx_enclave \
matterlabsrobot/teepot-self-attestation-test-sgx-dcap:latest \
| base64 -d --ignore-garbage \
| docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest
| docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest -
aesm_service: warning: Turn to daemon. Use "--no-daemon" option to execute in foreground.
Gramine is starting. Parsing TOML manifest file, this may take some time...
@ -50,7 +50,7 @@ On an outdated machine, this might look like this:
docker run -i --init --rm --privileged --device /dev/sgx_enclave \
matterlabsrobot/teepot-self-attestation-test-sgx-dcap:latest \
| base64 -d --ignore-garbage \
| docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest
| docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest -
aesm_service: warning: Turn to daemon. Use "--no-daemon" option to execute in foreground.
Gramine is starting. Parsing TOML manifest file, this may take some time...

View file

@ -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

View file

@ -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(name = "attestation_file", value_parser)]
attestation: ArgSource,
/// An optional subcommand, for instance, for optional signature verification.
#[clap(subcommand)]
command: Option<SubCommands>,
}
#[derive(Debug, Clone)]
enum ArgSource {
File(PathBuf),
Stdin,
}
impl FromStr for ArgSource {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
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(&quote_verification_result);
match &args.command {
Some(SubCommands::SignVerify(signature_args)) => {
verify_signature(&quote_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 = &quote_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<QuoteVerificationResult> {
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(())
}

View file

@ -416,7 +416,7 @@ impl<'a> Deref for SgxQlQveCollateralT<'a> {
/// SGX/TDX Quote, presented as u8 vector.
///
/// # Return
/// Result type of quote_collecteral.
/// Result type of quote_collateral.
///
/// - **quote_collateral**\
/// This is the Quote Certification Collateral retrieved based on Quote.

View file

@ -10,7 +10,7 @@
dockerTools.buildLayeredImage {
name = "verify-attestation-sgx";
config.Cmd = [ "${teepot.teepot.verify_attestation}/bin/verify-attestation" ];
config.Entrypoint = [ "${teepot.teepot.verify_attestation}/bin/verify-attestation" ];
config.Env = [ "LD_LIBRARY_PATH=/lib" ];
contents = buildEnv {
name = "image-root";