mirror of
https://github.com/matter-labs/teepot.git
synced 2025-07-22 23:44:48 +02:00
feat: add file output for attestation collateral and quote data
- Write attestation collateral and quote details to various files.
This commit is contained in:
parent
63b9d6f6ee
commit
71de3a53bc
6 changed files with 159 additions and 11 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6455,6 +6455,7 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"url",
|
"url",
|
||||||
|
"x509-cert",
|
||||||
"zksync_basic_types",
|
"zksync_basic_types",
|
||||||
"zksync_types",
|
"zksync_types",
|
||||||
"zksync_web3_decl",
|
"zksync_web3_decl",
|
||||||
|
|
|
@ -69,7 +69,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "ansi"
|
||||||
tracing-test = { version = "0.2.5", features = ["no-env-filter"] }
|
tracing-test = { version = "0.2.5", features = ["no-env-filter"] }
|
||||||
url = "2.5.2"
|
url = "2.5.2"
|
||||||
webpki-roots = "0.26.1"
|
webpki-roots = "0.26.1"
|
||||||
x509-cert = { version = "0.2", features = ["builder", "signature"] }
|
x509-cert = { version = "0.2", features = ["builder", "signature", "pem"] }
|
||||||
zeroize = { version = "1.7.0", features = ["serde"] }
|
zeroize = { version = "1.7.0", features = ["serde"] }
|
||||||
zksync_basic_types = "=0.1.0"
|
zksync_basic_types = "=0.1.0"
|
||||||
zksync_types = "=0.1.0"
|
zksync_types = "=0.1.0"
|
||||||
|
|
|
@ -21,6 +21,7 @@ tokio.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
tracing-subscriber.workspace = true
|
tracing-subscriber.workspace = true
|
||||||
url.workspace = true
|
url.workspace = true
|
||||||
|
x509-cert.workspace = true
|
||||||
zksync_basic_types.workspace = true
|
zksync_basic_types.workspace = true
|
||||||
zksync_types.workspace = true
|
zksync_types.workspace = true
|
||||||
zksync_web3_decl.workspace = true
|
zksync_web3_decl.workspace = true
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Copyright (c) 2023-2024 Matter Labs
|
// Copyright (c) 2023-2025 Matter Labs
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use clap::{ArgGroup, Args, Parser};
|
use clap::{ArgGroup, Args, Parser};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use teepot::log::LogLevelParser;
|
use teepot::{
|
||||||
use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel};
|
log::LogLevelParser,
|
||||||
|
sgx::{parse_tcb_levels, EnumSet, TcbLevel},
|
||||||
|
};
|
||||||
use tracing_subscriber::filter::LevelFilter;
|
use tracing_subscriber::filter::LevelFilter;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use zksync_basic_types::L1BatchNumber;
|
use zksync_basic_types::L1BatchNumber;
|
||||||
|
@ -43,6 +45,9 @@ pub struct Arguments {
|
||||||
/// Criteria for valid attestation policy. Invalid proofs will be rejected.
|
/// Criteria for valid attestation policy. Invalid proofs will be rejected.
|
||||||
#[clap(flatten)]
|
#[clap(flatten)]
|
||||||
pub attestation_policy: AttestationPolicyArgs,
|
pub attestation_policy: AttestationPolicyArgs,
|
||||||
|
/// Save artifacts needed for verification
|
||||||
|
#[clap(short = 's', long = "save")]
|
||||||
|
pub save: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attestation policy implemented as a set of criteria that must be met by SGX attestation.
|
/// Attestation policy implemented as a set of criteria that must be met by SGX attestation.
|
||||||
|
|
|
@ -91,6 +91,7 @@ async fn verify_batches_proofs(
|
||||||
&http_client,
|
&http_client,
|
||||||
&node_client,
|
&node_client,
|
||||||
&args.attestation_policy,
|
&args.attestation_policy,
|
||||||
|
args.save,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -141,6 +142,7 @@ async fn verify_batch_proofs(
|
||||||
http_client: &Client,
|
http_client: &Client,
|
||||||
node_client: &MainNodeClient,
|
node_client: &MainNodeClient,
|
||||||
attestation_policy: &AttestationPolicyArgs,
|
attestation_policy: &AttestationPolicyArgs,
|
||||||
|
save: bool,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let proofs = get_proofs(stop_receiver, batch_number, http_client, rpc_url).await?;
|
let proofs = get_proofs(stop_receiver, batch_number, http_client, rpc_url).await?;
|
||||||
let batch_no = batch_number.0;
|
let batch_no = batch_number.0;
|
||||||
|
@ -178,6 +180,7 @@ async fn verify_batch_proofs(
|
||||||
node_client,
|
node_client,
|
||||||
&proof.signature.unwrap_or_default(),
|
&proof.signature.unwrap_or_default(),
|
||||||
L1BatchNumber(proof.l1_batch_number),
|
L1BatchNumber(proof.l1_batch_number),
|
||||||
|
save,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,16 @@ use secp256k1::{
|
||||||
ecdsa::{RecoverableSignature, RecoveryId, Signature},
|
ecdsa::{RecoverableSignature, RecoveryId, Signature},
|
||||||
Message, SECP256K1,
|
Message, SECP256K1,
|
||||||
};
|
};
|
||||||
|
use std::fs;
|
||||||
use teepot::{
|
use teepot::{
|
||||||
client::TcbLevel,
|
client::TcbLevel,
|
||||||
ethereum::{public_key_to_ethereum_address, recover_signer},
|
ethereum::{public_key_to_ethereum_address, recover_signer},
|
||||||
prover::reportdata::ReportData,
|
prover::reportdata::ReportData,
|
||||||
quote::{tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult, Report},
|
quote::{tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult, Report},
|
||||||
|
sgx::Collateral,
|
||||||
};
|
};
|
||||||
use tracing::{debug, info, trace, warn};
|
use tracing::{debug, info, trace, warn};
|
||||||
|
use x509_cert::der::Encode;
|
||||||
use zksync_basic_types::{L1BatchNumber, H256};
|
use zksync_basic_types::{L1BatchNumber, H256};
|
||||||
|
|
||||||
struct TeeProof {
|
struct TeeProof {
|
||||||
|
@ -32,7 +35,7 @@ impl TeeProof {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self) -> Result<bool> {
|
pub fn verify(&mut self) -> Result<bool> {
|
||||||
match &self.report {
|
match &self.report {
|
||||||
ReportData::V0(report) => {
|
ReportData::V0(report) => {
|
||||||
debug!("ReportData::V0");
|
debug!("ReportData::V0");
|
||||||
|
@ -75,6 +78,9 @@ impl TeeProof {
|
||||||
);
|
);
|
||||||
if ethereum_address_from_signature == ethereum_address_from_report {
|
if ethereum_address_from_signature == ethereum_address_from_report {
|
||||||
info!("Had to use RecoveryId::{rec_id:?}");
|
info!("Had to use RecoveryId::{rec_id:?}");
|
||||||
|
self.signature.push(
|
||||||
|
u8::try_from(i32::from(rec_id)).context("recovery id to u8")? + 27,
|
||||||
|
);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,15 +106,130 @@ impl TeeProof {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn save_verification_artifacts(
|
||||||
|
batch_number: L1BatchNumber,
|
||||||
|
signature: &[u8],
|
||||||
|
root_hash: &H256,
|
||||||
|
attestation_quote_bytes: &[u8],
|
||||||
|
collateral: &Collateral,
|
||||||
|
) -> Result<()> {
|
||||||
|
fs::write(
|
||||||
|
format!("{}_signature.hex", batch_number),
|
||||||
|
hex::encode(signature),
|
||||||
|
)?;
|
||||||
|
fs::write(
|
||||||
|
format!("{}_root_hash.hex", batch_number),
|
||||||
|
format!("{:x}", root_hash),
|
||||||
|
)?;
|
||||||
|
fs::write(
|
||||||
|
format!("{}_quote.bin", batch_number),
|
||||||
|
attestation_quote_bytes,
|
||||||
|
)?;
|
||||||
|
fs::write(
|
||||||
|
format!("{}_quote.bin.hex", batch_number),
|
||||||
|
hex::encode(attestation_quote_bytes),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let certs = x509_cert::certificate::CertificateInner::<
|
||||||
|
x509_cert::certificate::Rfc5280
|
||||||
|
>::load_pem_chain(collateral.pck_crl_issuer_chain.split_last().unwrap().1)?;
|
||||||
|
|
||||||
|
let cert = certs
|
||||||
|
.into_iter()
|
||||||
|
.find(|cert| {
|
||||||
|
cert.tbs_certificate
|
||||||
|
.subject
|
||||||
|
.to_string()
|
||||||
|
.contains("PCK Platform CA")
|
||||||
|
})
|
||||||
|
.ok_or(anyhow!("PCK Platform CA cert not found"))?;
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
format!("{}_platformDer.hex", batch_number),
|
||||||
|
hex::encode(&cert.to_der()?),
|
||||||
|
)
|
||||||
|
.context("Failed to write PCK Platform CA to platformDer.hex")?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Platform CA serial {}",
|
||||||
|
cert.tbs_certificate.serial_number.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
format!("{}_rootCrlDer.hex", batch_number),
|
||||||
|
collateral.root_ca_crl.split_last().unwrap().1,
|
||||||
|
)
|
||||||
|
.context("Failed to write root_ca_crl to rootCrlDer.hex")?;
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
format!("{}_platformCrlDer.hex", batch_number),
|
||||||
|
hex::encode(collateral.pck_crl.split_last().unwrap().1),
|
||||||
|
)
|
||||||
|
.context("Failed to write pck_crl to platformCrlDer.hex")?;
|
||||||
|
|
||||||
|
let certs = x509_cert::certificate::CertificateInner::<
|
||||||
|
x509_cert::certificate::Rfc5280
|
||||||
|
>::load_pem_chain(collateral.tcb_info_issuer_chain.split_last().unwrap().1)?;
|
||||||
|
|
||||||
|
let cert = certs
|
||||||
|
.into_iter()
|
||||||
|
.find(|cert| {
|
||||||
|
cert.tbs_certificate
|
||||||
|
.subject
|
||||||
|
.to_string()
|
||||||
|
.contains("TCB Signing")
|
||||||
|
})
|
||||||
|
.ok_or(anyhow!("TCB Signing cert not found"))?;
|
||||||
|
|
||||||
|
debug!("TCB cert {}", cert.tbs_certificate.subject.to_string());
|
||||||
|
debug!(
|
||||||
|
"TCB serial {}",
|
||||||
|
cert.tbs_certificate.serial_number.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
format!("{}_tcbDer.hex", batch_number),
|
||||||
|
hex::encode(&cert.to_der()?),
|
||||||
|
)
|
||||||
|
.context("Failed to write TCB Signing CA to tcbDer.hex")?;
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
format!("{}_tcb_info.json", batch_number),
|
||||||
|
collateral.tcb_info.split_last().unwrap().1,
|
||||||
|
)
|
||||||
|
.context("Failed to write tcb_info to tcb_info.json")?;
|
||||||
|
|
||||||
|
let certs = x509_cert::certificate::CertificateInner::<
|
||||||
|
x509_cert::certificate::Rfc5280
|
||||||
|
>::load_pem_chain(collateral.qe_identity_issuer_chain.split_last().unwrap().1)?;
|
||||||
|
|
||||||
|
let _ = certs
|
||||||
|
.into_iter()
|
||||||
|
.find(|qe_cert| {
|
||||||
|
qe_cert
|
||||||
|
.tbs_certificate
|
||||||
|
.serial_number
|
||||||
|
.eq(&cert.tbs_certificate.serial_number)
|
||||||
|
})
|
||||||
|
.ok_or(anyhow!("QE identity cert != TCB cert"))?;
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
format!("{}_qe_identity.json", batch_number),
|
||||||
|
collateral.qe_identity.split_last().unwrap().1,
|
||||||
|
)
|
||||||
|
.context("Failed to write qe_identity to qe_identity.json")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn verify_batch_proof(
|
pub async fn verify_batch_proof(
|
||||||
attestation_quote_bytes: &[u8],
|
attestation_quote_bytes: &[u8],
|
||||||
attestation_policy: &AttestationPolicyArgs,
|
attestation_policy: &AttestationPolicyArgs,
|
||||||
node_client: &impl JsonRpcClient,
|
node_client: &impl JsonRpcClient,
|
||||||
signature: &[u8],
|
signature: &[u8],
|
||||||
batch_number: L1BatchNumber,
|
batch_number: L1BatchNumber,
|
||||||
|
save: bool,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
let quote_verification_result = verify_attestation_quote(attestation_quote_bytes)?;
|
let quote_verification_result = verify_attestation_quote(attestation_quote_bytes)?;
|
||||||
|
|
||||||
log_quote_verification_summary("e_verification_result);
|
log_quote_verification_summary("e_verification_result);
|
||||||
|
@ -116,12 +237,29 @@ pub async fn verify_batch_proof(
|
||||||
if !is_quote_matching_policy(attestation_policy, "e_verification_result) {
|
if !is_quote_matching_policy(attestation_policy, "e_verification_result) {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
let QuoteVerificationResult {
|
||||||
|
quote, collateral, ..
|
||||||
|
} = quote_verification_result;
|
||||||
let root_hash = node_client.get_root_hash(batch_number).await?;
|
let root_hash = node_client.get_root_hash(batch_number).await?;
|
||||||
let report_data_bytes = quote_verification_result.quote.get_report_data();
|
let report_data_bytes = quote.get_report_data();
|
||||||
|
|
||||||
let report_data = ReportData::try_from(report_data_bytes)?;
|
let report_data = ReportData::try_from(report_data_bytes)?;
|
||||||
let tee_proof = TeeProof::new(report_data, root_hash, signature.to_vec());
|
|
||||||
tee_proof.verify()
|
let mut tee_proof = TeeProof::new(report_data, root_hash, signature.to_vec());
|
||||||
|
|
||||||
|
let res = tee_proof.verify();
|
||||||
|
|
||||||
|
if save {
|
||||||
|
save_verification_artifacts(
|
||||||
|
batch_number,
|
||||||
|
tee_proof.signature.as_slice(),
|
||||||
|
&root_hash,
|
||||||
|
attestation_quote_bytes,
|
||||||
|
&collateral,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result<QuoteVerificationResult> {
|
pub fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result<QuoteVerificationResult> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue