From e7b743b213aac9c72d43a41812e29913f5ce4936 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 17 Sep 2024 14:48:49 +0200 Subject: [PATCH 001/114] chore: tag container with git tag Allow all tags and tag the matterlabsrobot container with it. Signed-off-by: Harald Hoyer --- .github/workflows/nix.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 7300c28..ae23eb4 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -5,7 +5,7 @@ on: branches: [ "main" ] push: branches: [ "main" ] - tags: [ "*-sgx-*" ] + tags: [ "*" ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -121,6 +121,12 @@ jobs: docker tag "${{ steps.build.outputs.IMAGE_TAG }}" matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:latest" docker push matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:latest" + - name: Tag container with tag + if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} + run: | + docker tag "${{ steps.build.outputs.IMAGE_TAG }}" matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:$GITHUB_REF_NAME" + docker push matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:$GITHUB_REF_NAME" + - name: Generate build ID for Flux Image Automation id: flux if: ${{ github.event_name == 'push' && !startsWith(github.ref, 'refs/tags') }} From 9bf40c9cb9e94275a4cf15c063fb1372c072c075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20B=C4=99za?= Date: Wed, 18 Sep 2024 14:03:07 +0200 Subject: [PATCH 002/114] feat(tee): use hex deserialization for RPC requests Following Anton's suggestion, we have switched to hex serialization for API/RPC requests and responses. Previously, we used default JSON serialization for Vec, which resulted in a lengthy comma-separated list of integers. This change standardizes serialization, making it more efficient and reducing the size of the responses. The previous format, with a series of comma-separated integers for pubkey-like fields, looked odd. Then: ``` curl -X POST\ -H "Content-Type: application/json" \ --data '{"jsonrpc": "2.0", "id": 1, "method": "unstable_getTeeProofs", "params": [491882, "Sgx"] }' \ https://mainnet.era.zksync.io {"jsonrpc":"2.0","result":[{"attestation":[3,0,2,0,0,0,0,0,10, ``` Now: ``` $ curl -X POST \ -H "Content-Type: application/json" \ --data '{"jsonrpc": "2.0", "id": 1, "method": "unstable_getTeeProofs", "params": [1, "sgx"] }' \ http://localhost:3050 {"jsonrpc":"2.0","result":[{"l1BatchNumber":1,"teeType":"sgx","pubkey":"0506070809","signature":"0001020304","proof":"0a0b0c0d0e","provedAt":"2024-09-16T11:53:38.253033Z","attestation":"0403020100"}],"id":1} ``` This change needs to be deployed in lockstep with: https://github.com/matter-labs/zksync-era/pull/2887. --- Cargo.lock | 1 + bin/verify-era-proof-attestation/Cargo.toml | 1 + bin/verify-era-proof-attestation/src/proof.rs | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 7ed6d55..1010857 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5636,6 +5636,7 @@ dependencies = [ "reqwest 0.12.7", "secp256k1 0.29.1", "serde", + "serde_with 3.9.0", "teepot", "tokio", "tracing", diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index b0b8909..acd88a9 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -16,6 +16,7 @@ jsonrpsee-types.workspace = true reqwest.workspace = true secp256k1.workspace = true serde.workspace = true +serde_with = { workspace = true, features = ["hex"] } teepot.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/bin/verify-era-proof-attestation/src/proof.rs b/bin/verify-era-proof-attestation/src/proof.rs index 6f1fdb7..3cd0ec1 100644 --- a/bin/verify-era-proof-attestation/src/proof.rs +++ b/bin/verify-era-proof-attestation/src/proof.rs @@ -5,6 +5,7 @@ use anyhow::{bail, Result}; use jsonrpsee_types::error::ErrorObject; use reqwest::Client; use serde::{Deserialize, Serialize}; +use serde_with::{hex::Hex, serde_as}; use std::time::Duration; use tokio::sync::watch; use tracing::{error, warn}; @@ -146,14 +147,19 @@ pub struct GetProofsResponse { pub error: Option>, } +#[serde_as] #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Proof { pub l1_batch_number: u32, pub tee_type: String, + #[serde_as(as = "Hex")] pub pubkey: Vec, + #[serde_as(as = "Hex")] pub signature: Vec, + #[serde_as(as = "Hex")] pub proof: Vec, pub proved_at: String, + #[serde_as(as = "Hex")] pub attestation: Vec, } From 21a9ecdee1eac7d5daa8917d3092b0c8666489e4 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 18 Sep 2024 13:35:25 +0200 Subject: [PATCH 003/114] fix(flake.nix): remove redundant crane input follow - Removed the unnecessary crane input follow from flake.nix. ``` warning: input 'crane' has an override for a non-existent input 'nixpkgs' ``` --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 0c6f684..c1834b6 100644 --- a/flake.nix +++ b/flake.nix @@ -23,7 +23,6 @@ crane = { url = "github:ipetkov/crane?tag=v0.17.3"; - inputs.nixpkgs.follows = "nixsgx-flake/nixpkgs"; }; }; From 9bce6edfaa376e95e2eeb65d2a14a2f7f3190d39 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 18 Sep 2024 14:49:16 +0200 Subject: [PATCH 004/114] ci: remove magic nix cache Signed-off-by: Harald Hoyer --- .github/workflows/nix.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index ae23eb4..20d9047 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -29,8 +29,6 @@ jobs: endpoint: https://attic.teepot.org/ cache: tee-pot token: ${{ secrets.ATTIC_TOKEN }} - - name: Enable magic Nix cache - uses: DeterminateSystems/magic-nix-cache-action@main - run: nix flake check -L --show-trace --keep-going @@ -52,8 +50,6 @@ jobs: endpoint: https://attic.teepot.org/ cache: tee-pot token: ${{ secrets.ATTIC_TOKEN }} - - name: Enable magic Nix cache - uses: DeterminateSystems/magic-nix-cache-action@main - name: nix build run: nix run github:nixos/nixpkgs/nixos-23.11#nixci @@ -92,8 +88,6 @@ jobs: endpoint: https://attic.teepot.org/ cache: tee-pot token: ${{ secrets.ATTIC_TOKEN }} - - name: Enable magic Nix cache - uses: DeterminateSystems/magic-nix-cache-action@main - name: Log in to Docker Hub uses: docker/login-action@v3 From af3ab51320a67f20cbf5a47679559298f983e03c Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 18 Sep 2024 13:21:12 +0200 Subject: [PATCH 005/114] feat(logging): centralize logging setup in teepot crate - Added a new logging module in `teepot` crate. - Removed redundant logging setup code from individual projects. - Updated dependencies and references for logging setup. Signed-off-by: Harald Hoyer --- Cargo.lock | 2 + bin/vault-admin/src/main.rs | 19 +++--- bin/verify-era-proof-attestation/src/args.rs | 34 +---------- bin/verify-era-proof-attestation/src/main.rs | 32 ++-------- crates/teepot/Cargo.toml | 2 + crates/teepot/src/lib.rs | 1 + crates/teepot/src/log/mod.rs | 63 ++++++++++++++++++++ 7 files changed, 85 insertions(+), 68 deletions(-) create mode 100644 crates/teepot/src/log/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 1010857..0bf6a65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4952,6 +4952,8 @@ dependencies = [ "testaso", "thiserror", "tracing", + "tracing-log 0.2.0", + "tracing-subscriber", "webpki-roots", "x509-cert", "zeroize", diff --git a/bin/vault-admin/src/main.rs b/bin/vault-admin/src/main.rs index 91d17e0..db6d6eb 100644 --- a/bin/vault-admin/src/main.rs +++ b/bin/vault-admin/src/main.rs @@ -15,12 +15,11 @@ use teepot::json::http::{ SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands, VaultCommandsResponse, DIGEST_URL, }; +use teepot::log::{setup_logging, LogLevelParser}; use teepot::server::signatures::verify_sig; use teepot::sgx::sign::Signature; +use tracing::level_filters::LevelFilter; use tracing::{error, info}; -use tracing_log::LogTracer; -use tracing_subscriber::Registry; -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; #[derive(Args, Debug)] struct SendArgs { @@ -101,18 +100,18 @@ enum SubCommands { struct Arguments { #[clap(subcommand)] cmd: SubCommands, + /// Log level for the log output. + /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` + #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] + pub log_level: LevelFilter, } #[actix_web::main] async fn main() -> Result<()> { - LogTracer::init().context("Failed to set logger")?; - - let subscriber = Registry::default() - .with(EnvFilter::from_default_env()) - .with(fmt::layer().with_writer(std::io::stderr)); - tracing::subscriber::set_global_default(subscriber).unwrap(); - let args = Arguments::parse(); + + setup_logging(&args.log_level)?; + info!("Quote verified! Connection secure!"); match args.cmd { diff --git a/bin/verify-era-proof-attestation/src/args.rs b/bin/verify-era-proof-attestation/src/args.rs index 95555a5..cea2a1c 100644 --- a/bin/verify-era-proof-attestation/src/args.rs +++ b/bin/verify-era-proof-attestation/src/args.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, Result}; use clap::{ArgGroup, Args, Parser}; use std::time::Duration; +use teepot::log::LogLevelParser; use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; use tracing_subscriber::filter::LevelFilter; use url::Url; @@ -18,6 +19,8 @@ use zksync_types::L2ChainId; .args(&["batch_range", "continuous"]), ))] pub struct Arguments { + /// Log level for the log output. + /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] pub log_level: LevelFilter, /// The batch number or range of batch numbers to verify the attestation and signature (e.g., @@ -90,34 +93,3 @@ fn parse_duration(s: &str) -> Result { let millis = s.parse()?; Ok(Duration::from_millis(millis)) } - -#[derive(Clone)] -struct LogLevelParser; - -impl clap::builder::TypedValueParser for LogLevelParser { - type Value = LevelFilter; - - fn parse_ref( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: &std::ffi::OsStr, - ) -> Result { - clap::builder::TypedValueParser::parse(self, cmd, arg, value.to_owned()) - } - - fn parse( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: std::ffi::OsString, - ) -> std::result::Result { - use std::str::FromStr; - let p = clap::builder::PossibleValuesParser::new([ - "off", "error", "warn", "info", "debug", "trace", - ]); - let v = p.parse(cmd, arg, value)?; - - Ok(LevelFilter::from_str(&v).unwrap()) - } -} diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index cbb263a..affdc0a 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -8,23 +8,21 @@ mod client; mod proof; mod verification; -use anyhow::{Context, Result}; +use crate::verification::{ + log_quote_verification_summary, verify_attestation_quote, verify_batch_proof, +}; +use anyhow::Result; use args::{Arguments, AttestationPolicyArgs}; use clap::Parser; use client::MainNodeClient; use proof::get_proofs; use reqwest::Client; +use teepot::log::setup_logging; use tokio::{signal, sync::watch}; use tracing::{debug, error, info, trace, warn}; -use tracing_log::LogTracer; -use tracing_subscriber::{filter::LevelFilter, fmt, prelude::*, EnvFilter, Registry}; use url::Url; use zksync_basic_types::L1BatchNumber; -use crate::verification::{ - log_quote_verification_summary, verify_attestation_quote, verify_batch_proof, -}; - #[tokio::main] async fn main() -> Result<()> { let args = Arguments::parse(); @@ -45,26 +43,6 @@ async fn main() -> Result<()> { Ok(()) } -fn setup_logging(log_level: &LevelFilter) -> Result<()> { - LogTracer::init().context("Failed to set logger")?; - let filter = EnvFilter::builder() - .try_from_env() - .unwrap_or(match *log_level { - LevelFilter::OFF => EnvFilter::new("off"), - _ => EnvFilter::new(format!( - "warn,{crate_name}={log_level},teepot={log_level}", - crate_name = env!("CARGO_CRATE_NAME"), - log_level = log_level - )), - }); - let subscriber = Registry::default() - .with(filter) - .with(fmt::layer().with_writer(std::io::stderr)); - tracing::subscriber::set_global_default(subscriber)?; - - Ok(()) -} - fn validate_arguments(args: &Arguments) -> Result<()> { if args.attestation_policy.sgx_mrsigners.is_none() && args.attestation_policy.sgx_mrenclaves.is_none() diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index a2c48bf..c33aa89 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -39,6 +39,8 @@ sha2.workspace = true signature.workspace = true thiserror.workspace = true tracing.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true webpki-roots.workspace = true x509-cert.workspace = true zeroize.workspace = true diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 8d38678..b3bcf16 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -11,4 +11,5 @@ pub mod json; pub mod server; pub mod sgx; +pub mod log; pub mod quote; diff --git a/crates/teepot/src/log/mod.rs b/crates/teepot/src/log/mod.rs new file mode 100644 index 0000000..e91b7fa --- /dev/null +++ b/crates/teepot/src/log/mod.rs @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +//! Logging related stuff + +use anyhow::Context; +use tracing::level_filters::LevelFilter; +use tracing_log::LogTracer; +use tracing_subscriber::Registry; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +/// A log level parser for clap, with "off", "error", "warn", "info", "debug", "trace" as valid values +#[derive(Clone)] +pub struct LogLevelParser; + +impl clap::builder::TypedValueParser for LogLevelParser { + type Value = LevelFilter; + + fn parse_ref( + &self, + cmd: &clap::Command, + arg: Option<&clap::Arg>, + value: &std::ffi::OsStr, + ) -> anyhow::Result { + clap::builder::TypedValueParser::parse(self, cmd, arg, value.to_owned()) + } + + fn parse( + &self, + cmd: &clap::Command, + arg: Option<&clap::Arg>, + value: std::ffi::OsString, + ) -> std::result::Result { + use std::str::FromStr; + let p = clap::builder::PossibleValuesParser::new([ + "off", "error", "warn", "info", "debug", "trace", + ]); + let v = p.parse(cmd, arg, value)?; + + Ok(LevelFilter::from_str(&v).unwrap()) + } +} + +/// Setup standard logging and loglevel for the current crate and the `teepot` crate. +pub fn setup_logging(log_level: &LevelFilter) -> anyhow::Result<()> { + LogTracer::init().context("Failed to set logger")?; + let filter = EnvFilter::builder() + .try_from_env() + .unwrap_or(match *log_level { + LevelFilter::OFF => EnvFilter::new("off"), + _ => EnvFilter::new(format!( + "warn,{crate_name}={log_level},teepot={log_level}", + crate_name = env!("CARGO_CRATE_NAME"), + log_level = log_level + )), + }); + let subscriber = Registry::default() + .with(filter) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber)?; + + Ok(()) +} From e63d0901fad5c622cc04191d9b0cb1d516f7caff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20B=C4=99za?= Date: Tue, 26 Nov 2024 16:16:40 +0100 Subject: [PATCH 006/114] feat(verifier): don't retry verifying permanently ignored batches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the [TEE verifier][1] – the tool for continuous SGX attestation and batch signature verification – is [stuck][2] on batches that failed to be proven and are marked as `permanently_ignored`. The tool should be able to distinguish between batches that are permanently ignored (and should be skipped) and batches that have failed but will be retried. This PR enables that distinction. This commit goes hand in hand with the following PR: https://github.com/matter-labs/zksync-era/pull/3321 [1]: https://github.com/matter-labs/teepot/blob/main/bin/verify-era-proof-attestation/src/main.rs [2]: https://grafana.matterlabs.dev/goto/unFqf57Hg?orgId=1 --- bin/verify-era-proof-attestation/src/main.rs | 19 +++++++++------ bin/verify-era-proof-attestation/src/proof.rs | 24 ++++++++++++------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index affdc0a..9ee0b1b 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -155,19 +155,24 @@ async fn verify_batch_proofs( total_proofs_count += 1; let tee_type = proof.tee_type.to_uppercase(); + if proof.status.eq_ignore_ascii_case("permanently_ignored") { + trace!( + batch_no, + tee_type, + "Proof is marked as permanently ignored. Skipping." + ); + continue; + } trace!(batch_no, tee_type, proof.proved_at, "Verifying proof."); - debug!( - batch_no, - "Verifying quote ({} bytes)...", - proof.attestation.len() - ); - let quote_verification_result = verify_attestation_quote(&proof.attestation)?; + let attestation = proof.attestation.unwrap_or_default(); + debug!(batch_no, "Verifying quote ({} bytes)...", attestation.len()); + let quote_verification_result = verify_attestation_quote(&attestation)?; let verified_successfully = verify_batch_proof( "e_verification_result, attestation_policy, node_client, - &proof.signature, + &proof.signature.unwrap_or_default(), L1BatchNumber(proof.l1_batch_number), ) .await?; diff --git a/bin/verify-era-proof-attestation/src/proof.rs b/bin/verify-era-proof-attestation/src/proof.rs index 3cd0ec1..9da43ea 100644 --- a/bin/verify-era-proof-attestation/src/proof.rs +++ b/bin/verify-era-proof-attestation/src/proof.rs @@ -37,7 +37,12 @@ pub async fn get_proofs( .send(stop_receiver, http_client, rpc_url) .await?; - if !proofs.is_empty() { + if !proofs.is_empty() + && proofs.iter().all(|proof| { + !proof.status.eq_ignore_ascii_case("failed") + && !proof.status.eq_ignore_ascii_case("picked_by_prover") + }) + { return Ok(proofs); } @@ -153,13 +158,14 @@ pub struct GetProofsResponse { pub struct Proof { pub l1_batch_number: u32, pub tee_type: String, - #[serde_as(as = "Hex")] - pub pubkey: Vec, - #[serde_as(as = "Hex")] - pub signature: Vec, - #[serde_as(as = "Hex")] - pub proof: Vec, + #[serde_as(as = "Option")] + pub pubkey: Option>, + #[serde_as(as = "Option")] + pub signature: Option>, + #[serde_as(as = "Option")] + pub proof: Option>, pub proved_at: String, - #[serde_as(as = "Hex")] - pub attestation: Vec, + pub status: String, + #[serde_as(as = "Option")] + pub attestation: Option>, } From 2c6a62a4711bb6ba819a964360c26200dea2e376 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 27 Nov 2024 08:50:42 +0100 Subject: [PATCH 007/114] chore: update lint workflow actions - Changed spdx action to reference a stable commit instead of master. - Changed license list to conform to new action parameter format --- .github/workflows/lint.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e4a5757..dd9157b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,9 +16,12 @@ jobs: steps: - name: checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - - uses: enarx/spdx@master + - uses: enarx/spdx@c3e8116ed31c31b3c2e58a26ba5cac407510ca37 with: - licenses: Apache-2.0 BSD-3-Clause MIT + licenses: |- + Apache-2.0 + BSD-3-Clause + MIT taplo: name: taplo From d8239dba2fc4b0a5caa9f8f0a161435c61bb18e6 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 28 Nov 2024 15:45:39 +0100 Subject: [PATCH 008/114] chore: update dependencies and enhance shell configuration - Updated multiple dependencies in flake.lock to their latest revisions. - Improved the shell configuration in the teepot with enhanced environment variable settings for SGX support. - Reinstated OPENSSL_NO_VENDOR and added library paths to ensure compatibility and proper linking. --- flake.lock | 24 ++++++++++++------------ shells/teepot/default.nix | 26 ++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/flake.lock b/flake.lock index 5432091..c44d03c 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "crane": { "locked": { - "lastModified": 1725125250, - "narHash": "sha256-CB20rDD5eHikF6mMTTJdwPP1qvyoiyyw1RDUzwIaIF8=", + "lastModified": 1732407143, + "narHash": "sha256-qJOGDT6PACoX+GbNH2PPx2ievlmtT1NVeTB80EkRLys=", "owner": "ipetkov", "repo": "crane", - "rev": "96fd12c7100e9e05fa1a0a5bd108525600ce282f", + "rev": "f2b4b472983817021d9ffb60838b2b36b9376b20", "type": "github" }, "original": { @@ -141,11 +141,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1719707984, - "narHash": "sha256-RoxIr/fbndtuKqulGvNCcuzC6KdAib85Q8gXnjzA1dw=", + "lastModified": 1728740863, + "narHash": "sha256-u+rxA79a0lyhG+u+oPBRtTDtzz8kvkc9a6SWSt9ekVc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7dca15289a1c2990efbe4680f0923ce14139b042", + "rev": "a3f9ad65a0bf298ed5847629a57808b97e6e8077", "type": "github" }, "original": { @@ -177,11 +177,11 @@ "snowfall-lib": "snowfall-lib" }, "locked": { - "lastModified": 1725271440, - "narHash": "sha256-CY79oPHWtDQdCDSJTMPZPYVgONAgsqCUZHr2idff53U=", + "lastModified": 1732034035, + "narHash": "sha256-VMIIgtuBNksCRvcHxFtkzveEYz2w7lO+ltuC23QpBD8=", "owner": "matter-labs", "repo": "nixsgx", - "rev": "00bb72e3ef79c79030ab622cfe9ced39d21006cc", + "rev": "b6b4571d43616ffc7719941daafa350a453a9d44", "type": "github" }, "original": { @@ -233,11 +233,11 @@ ] }, "locked": { - "lastModified": 1725243956, - "narHash": "sha256-0A5ZP8uDCyBdYUzayZfy6JFdTefP79oZVAjyqA/yuSI=", + "lastModified": 1732761189, + "narHash": "sha256-A2a4Cw66421Wojv1uqSGkD1XW960uJ7wHuwmvGCUJ8s=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "a10c8092d5f82622be79ed4dd12289f72011f850", + "rev": "fd0e3bf854b937632c92819d55d4ff8a130d5658", "type": "github" }, "original": { diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index faeb573..7055b44 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -7,18 +7,36 @@ , taplo , vault , cargo-release +, nixsgx +, stdenv }: mkShell { inputsFrom = [ teepot.teepot ]; - shellHook = '' - export OPENSSL_NO_VENDOR="1"; - ''; - packages = [ dive taplo vault cargo-release ]; + + TEE_LD_LIBRARY_PATH = lib.makeLibraryPath [ + nixsgx.sgx-dcap + nixsgx.sgx-dcap.quote_verify + nixsgx.sgx-dcap.default_qpl + ]; + + QCNL_CONF_PATH = "${nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf"; + OPENSSL_NO_VENDOR = "1"; + + shellHook = '' + if [ "x$NIX_LD" = "x" ]; then + export NIX_LD=$(<${stdenv.cc}/nix-support/dynamic-linker) + fi + if [ "x$NIX_LD_LIBRARY_PATH" = "x" ]; then + export NIX_LD_LIBRARY_PATH="$TEE_LD_LIBRARY_PATH" + else + export NIX_LD_LIBRARY_PATH="$NIX_LD_LIBRARY_PATH:$TEE_LD_LIBRARY_PATH" + fi + ''; } From 4a0a4f6e5ec8eca62bf19fb5b164553d3f3f9ea5 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 28 Nov 2024 15:48:05 +0100 Subject: [PATCH 009/114] fix(proof-validation): handle optional proof status Ensure proof status is treated as optional, preventing crashes when status is absent. - Modify status field to `Option` in `Proof` struct. - Update validation logic to handle `None` values safely. - Adjust main logic to check for "permanently_ignored" safely. --- bin/verify-era-proof-attestation/src/main.rs | 5 ++++- bin/verify-era-proof-attestation/src/proof.rs | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index 9ee0b1b..137db06 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -155,7 +155,10 @@ async fn verify_batch_proofs( total_proofs_count += 1; let tee_type = proof.tee_type.to_uppercase(); - if proof.status.eq_ignore_ascii_case("permanently_ignored") { + if proof + .status + .map_or(false, |s| s.eq_ignore_ascii_case("permanently_ignored")) + { trace!( batch_no, tee_type, diff --git a/bin/verify-era-proof-attestation/src/proof.rs b/bin/verify-era-proof-attestation/src/proof.rs index 9da43ea..3ee9990 100644 --- a/bin/verify-era-proof-attestation/src/proof.rs +++ b/bin/verify-era-proof-attestation/src/proof.rs @@ -39,8 +39,9 @@ pub async fn get_proofs( if !proofs.is_empty() && proofs.iter().all(|proof| { - !proof.status.eq_ignore_ascii_case("failed") - && !proof.status.eq_ignore_ascii_case("picked_by_prover") + !proof.status.as_ref().map_or(false, |s| { + s.eq_ignore_ascii_case("failed") | s.eq_ignore_ascii_case("picked_by_prover") + }) }) { return Ok(proofs); @@ -165,7 +166,7 @@ pub struct Proof { #[serde_as(as = "Option")] pub proof: Option>, pub proved_at: String, - pub status: String, + pub status: Option, #[serde_as(as = "Option")] pub attestation: Option>, } From f0fea5c1224e4aaa518f7a28edd3b437ff614f9f Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 28 Nov 2024 15:47:16 +0100 Subject: [PATCH 010/114] refactor(logging): enhance logging setup and usage - Modified the `setup_logging` function to return a `Subscriber`, improving flexibility and reuse. - Integrated `tracing::subscriber::set_global_default` in the main functions to establish the logging subscriber globally. - Added configurations for span events and control over file and line information display. Signed-off-by: Harald Hoyer --- bin/vault-admin/src/main.rs | 5 +++- bin/verify-era-proof-attestation/src/main.rs | 6 ++++- crates/teepot/src/log/mod.rs | 24 +++++++++++++------- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/bin/vault-admin/src/main.rs b/bin/vault-admin/src/main.rs index db6d6eb..f37bc8e 100644 --- a/bin/vault-admin/src/main.rs +++ b/bin/vault-admin/src/main.rs @@ -110,7 +110,10 @@ struct Arguments { async fn main() -> Result<()> { let args = Arguments::parse(); - setup_logging(&args.log_level)?; + tracing::subscriber::set_global_default(setup_logging( + env!("CARGO_CRATE_NAME"), + &args.log_level, + )?)?; info!("Quote verified! Connection secure!"); diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index 9ee0b1b..feeb2d7 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -26,7 +26,11 @@ use zksync_basic_types::L1BatchNumber; #[tokio::main] async fn main() -> Result<()> { let args = Arguments::parse(); - setup_logging(&args.log_level)?; + tracing::subscriber::set_global_default(setup_logging( + env!("CARGO_CRATE_NAME"), + &args.log_level, + )?)?; + validate_arguments(&args)?; let (stop_sender, stop_receiver) = watch::channel(false); let mut process_handle = tokio::spawn(verify_batches_proofs(stop_receiver, args)); diff --git a/crates/teepot/src/log/mod.rs b/crates/teepot/src/log/mod.rs index e91b7fa..d0fd107 100644 --- a/crates/teepot/src/log/mod.rs +++ b/crates/teepot/src/log/mod.rs @@ -5,9 +5,11 @@ use anyhow::Context; use tracing::level_filters::LevelFilter; +use tracing::Subscriber; use tracing_log::LogTracer; +use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::Registry; -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; +use tracing_subscriber::{prelude::*, EnvFilter}; /// A log level parser for clap, with "off", "error", "warn", "info", "debug", "trace" as valid values #[derive(Clone)] @@ -42,7 +44,10 @@ impl clap::builder::TypedValueParser for LogLevelParser { } /// Setup standard logging and loglevel for the current crate and the `teepot` crate. -pub fn setup_logging(log_level: &LevelFilter) -> anyhow::Result<()> { +pub fn setup_logging( + crate_name: &str, + log_level: &LevelFilter, +) -> anyhow::Result { LogTracer::init().context("Failed to set logger")?; let filter = EnvFilter::builder() .try_from_env() @@ -50,14 +55,17 @@ pub fn setup_logging(log_level: &LevelFilter) -> anyhow::Result<()> { LevelFilter::OFF => EnvFilter::new("off"), _ => EnvFilter::new(format!( "warn,{crate_name}={log_level},teepot={log_level}", - crate_name = env!("CARGO_CRATE_NAME"), log_level = log_level )), }); - let subscriber = Registry::default() - .with(filter) - .with(fmt::layer().with_writer(std::io::stderr)); - tracing::subscriber::set_global_default(subscriber)?; - Ok(()) + let fmt_layer = tracing_subscriber::fmt::layer() + .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) + .with_file(false) + .with_line_number(false) + .with_writer(std::io::stderr); + + let subscriber = Registry::default().with(filter).with(fmt_layer); + + Ok(subscriber) } From 83d57bf35433a04a254fb8d699fdd698980734c7 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:00:01 +0100 Subject: [PATCH 011/114] chore: update Rust toolchain to version 1.83 - Upgraded the Rust version in rust-toolchain.toml to 1.83. - Ensures compatibility and access to the latest features and fixes. Signed-off-by: Harald Hoyer --- flake.lock | 6 +++--- packages/teepot/default.nix | 1 + rust-toolchain.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index c44d03c..59217d8 100644 --- a/flake.lock +++ b/flake.lock @@ -233,11 +233,11 @@ ] }, "locked": { - "lastModified": 1732761189, - "narHash": "sha256-A2a4Cw66421Wojv1uqSGkD1XW960uJ7wHuwmvGCUJ8s=", + "lastModified": 1734661750, + "narHash": "sha256-BI58NBdimxu1lnpOrG9XxBz7Cwqy+qIf99zunWofX5w=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "fd0e3bf854b937632c92819d55d4ff8a130d5658", + "rev": "7d3d910d5fd575e6e8c5600d83d54e5c47273bfe", "type": "github" }, "original": { diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index fb0e3fa..91ce8f9 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -30,6 +30,7 @@ ]; postInstall = '' removeReferencesToVendoredSources "$out" "$cargoVendorDir" + removeReferencesToVendoredSources "$out" "${teepotCrate.rustVersion}/lib/rustlib/" mkdir -p $out/nix-support for i in $outputs; do [[ $i == "out" ]] && continue diff --git a/rust-toolchain.toml b/rust-toolchain.toml index bac2303..dbe555f 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.78" +channel = "1.83" components = ["rustfmt", "clippy", "rust-src"] From f818ac61c254b6d8475c82db329b292927f88c1d Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:00:24 +0100 Subject: [PATCH 012/114] chore(flake.nix): update crane to ref 8ff9c45 - Upgraded crane from v0.17.3 to v0.19.3 using a specific commit ref. - Ensures compatibility with the latest improvements and fixes in crane. Signed-off-by: Harald Hoyer --- flake.lock | 7 ++++--- flake.nix | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 59217d8..3074bcb 100644 --- a/flake.lock +++ b/flake.lock @@ -2,15 +2,16 @@ "nodes": { "crane": { "locked": { - "lastModified": 1732407143, - "narHash": "sha256-qJOGDT6PACoX+GbNH2PPx2ievlmtT1NVeTB80EkRLys=", + "lastModified": 1731974531, + "narHash": "sha256-z7hiGBWsbWwSnu5UMmYyfHEehlSmfB8sCA8iH4nmxm8=", "owner": "ipetkov", "repo": "crane", - "rev": "f2b4b472983817021d9ffb60838b2b36b9376b20", + "rev": "8ff9c457d60951bdd37a05ae903423de7ff55c6e", "type": "github" }, "original": { "owner": "ipetkov", + "ref": "8ff9c457d60951bdd37a05ae903423de7ff55c6e", "repo": "crane", "type": "github" } diff --git a/flake.nix b/flake.nix index c1834b6..dfff539 100644 --- a/flake.nix +++ b/flake.nix @@ -21,9 +21,7 @@ inputs.nixpkgs.follows = "nixsgx-flake/nixpkgs"; }; - crane = { - url = "github:ipetkov/crane?tag=v0.17.3"; - }; + crane.url = "github:ipetkov/crane?ref=8ff9c457d60951bdd37a05ae903423de7ff55c6e"; # v0.19.3 }; outputs = inputs: From b066cdd15adb47dfa5a098dafe9d6c317898ec95 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:01:50 +0100 Subject: [PATCH 013/114] fix: update build process for teepot package - Fix output format for propagated-user-env-packages. - Remove empty bin directory after binaries are moved. --- packages/teepot/default.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index 91ce8f9..fbc280f 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -35,10 +35,11 @@ for i in $outputs; do [[ $i == "out" ]] && continue mkdir -p "''${!i}/bin" - echo "''${!i}" >> $out/nix-support/propagated-user-env-packages + echo -n "''${!i} " >> $out/nix-support/propagated-user-env-packages binname=''${i//_/-} mv "$out/bin/$binname" "''${!i}/bin/" done + rmdir "$out/bin" ''; } ) From 34a00bc5bdaafe3bfc1db8328707534256eb275a Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:03:01 +0100 Subject: [PATCH 014/114] feat(shell): enhance teepot shell with Rust tools support - Add rustfmt, clippy, and rust-src as extensions in the Rust toolchain. - Include bindgenHook and pkg-config in nativeBuildInputs for improved build support. - Set RUST_SRC_PATH for better Rust library integration. --- shells/teepot/default.nix | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index 7055b44..effb413 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -9,10 +9,23 @@ , cargo-release , nixsgx , stdenv +, teepotCrate +, pkg-config }: +let + toolchain_with_src = (teepotCrate.rustVersion.override { + extensions = [ "rustfmt" "clippy" "rust-src" ]; + }); +in mkShell { inputsFrom = [ teepot.teepot ]; + nativeBuildInputs = [ + toolchain_with_src + pkg-config + teepotCrate.rustPlatform.bindgenHook + ]; + packages = [ dive taplo @@ -28,6 +41,7 @@ mkShell { QCNL_CONF_PATH = "${nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf"; OPENSSL_NO_VENDOR = "1"; + RUST_SRC_PATH = "${toolchain_with_src}/lib/rustlib/src/rust/library"; shellHook = '' if [ "x$NIX_LD" = "x" ]; then From a0f101acf1ad4615983a9511bb3f74e1177cc351 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:03:56 +0100 Subject: [PATCH 015/114] feat(teepot-crate): add libtdx_attest to dependencies - Included `nixsgx.sgx-dcap.libtdx_attest` in the dependencies list. - Ensures support for TDX attestation in the build environment. --- teepot-crate.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/teepot-crate.nix b/teepot-crate.nix index 1b2081d..4b59a63 100644 --- a/teepot-crate.nix +++ b/teepot-crate.nix @@ -28,6 +28,7 @@ let nixsgx.sgx-sdk nixsgx.sgx-dcap nixsgx.sgx-dcap.quote_verify + nixsgx.sgx-dcap.libtdx_attest ]; strictDeps = true; From c2e8bb6f94441ba07c87a3d1a466b18e5e006a61 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:04:25 +0100 Subject: [PATCH 016/114] chore(licensing): clarify licenses for TDX packages - Added explicit license clarifications for `tdx-attest-sys` and `tdx-attest-rs` packages. - Ensured compliance with BSD-3-Clause for both packages. --- deny.toml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/deny.toml b/deny.toml index 72b56af..ec551a1 100644 --- a/deny.toml +++ b/deny.toml @@ -46,6 +46,18 @@ version = "*" expression = "MIT AND ISC AND OpenSSL" license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] +[[licenses.clarify]] +name = "tdx-attest-sys" +version = "*" +expression = "BSD-3-Clause" +license-files = [] + +[[licenses.clarify]] +name = "tdx-attest-rs" +version = "*" +expression = "BSD-3-Clause" +license-files = [] + [licenses.private] ignore = false registries = [] From f4fba51e3e8561cf37d5b6dd2a98734edbd1ca9d Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:06:14 +0100 Subject: [PATCH 017/114] chore: rustfmt --- .../src/lib.rs | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/crates/teepot-tee-quote-verification-rs/src/lib.rs b/crates/teepot-tee-quote-verification-rs/src/lib.rs index 22c8055..d337924 100644 --- a/crates/teepot-tee-quote-verification-rs/src/lib.rs +++ b/crates/teepot-tee-quote-verification-rs/src/lib.rs @@ -68,15 +68,15 @@ pub use qvl_sys::tee_supp_data_descriptor_t; /// /// # Param /// - **policy**\ -/// Set the requested enclave loading policy to either *SGX_QL_PERSISTENT*, *SGX_QL_EPHEMERAL* or *SGX_QL_DEFAULT*. +/// Set the requested enclave loading policy to either *SGX_QL_PERSISTENT*, *SGX_QL_EPHEMERAL* or *SGX_QL_DEFAULT*. /// /// # Return /// - ***SGX_QL_SUCCESS***\ -/// Successfully set the enclave loading policy for the quoting library's enclaves.\ +/// Successfully set the enclave loading policy for the quoting library's enclaves.\ /// - ***SGX_QL_UNSUPPORTED_LOADING_POLICY***\ -/// The selected policy is not support by the quoting library.\ +/// The selected policy is not support by the quoting library.\ /// - ***SGX_QL_ERROR_UNEXPECTED***\ -/// Unexpected internal error. +/// Unexpected internal error. /// /// # Examples /// ``` @@ -123,19 +123,19 @@ pub fn sgx_qv_get_quote_supplemental_data_size() -> Result /// /// # Param /// - **quote**\ -/// SGX Quote, presented as u8 vector. +/// SGX Quote, presented as u8 vector. /// - **quote_collateral**\ -/// Quote Certification Collateral provided by the caller. +/// Quote Certification Collateral provided by the caller. /// - **expiration_check_date**\ -/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. /// - **qve_report_info**\ -/// This parameter can be used in 2 ways.\ +/// This parameter can be used in 2 ways.\ /// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ /// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. /// - **supplemental_data_size**\ -/// Size of the supplemental data (in bytes). +/// Size of the supplemental data (in bytes). /// - **supplemental_data**\ -/// The parameter is optional. If it is None, supplemental_data_size must be 0. +/// The parameter is optional. If it is None, supplemental_data_size must be 0. /// /// # Return /// Result type of (collateral_expiration_status, verification_result). @@ -223,19 +223,19 @@ pub fn tdx_qv_get_quote_supplemental_data_size() -> Result /// /// # Param /// - **quote**\ -/// TDX Quote, presented as u8 vector. +/// TDX Quote, presented as u8 vector. /// - **quote_collateral**\ -/// Quote Certification Collateral provided by the caller. +/// Quote Certification Collateral provided by the caller. /// - **expiration_check_date**\ -/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. /// - **qve_report_info**\ -/// This parameter can be used in 2 ways.\ +/// This parameter can be used in 2 ways.\ /// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ /// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. /// - **supplemental_data_size**\ -/// Size of the supplemental data (in bytes). +/// Size of the supplemental data (in bytes). /// - **supplemental_data**\ -/// The parameter is optional. If it is None, supplemental_data_size must be 0. +/// The parameter is optional. If it is None, supplemental_data_size must be 0. /// /// # Return /// Result type of (collateral_expiration_status, verification_result). @@ -296,15 +296,15 @@ pub fn tdx_qv_verify_quote( /// /// # Param /// - **path_type**\ -/// The type of binary being passed in. +/// The type of binary being passed in. /// - **path**\ -/// It should be a valid full path. +/// It should be a valid full path. /// /// # Return /// - ***SGX_QL_SUCCESS***\ -/// Successfully set the full path. +/// Successfully set the full path. /// - ***SGX_QL_ERROR_INVALID_PARAMETER***\ -/// Path is not a valid full path or the path is too long. +/// Path is not a valid full path or the path is too long. /// #[cfg(target_os = "linux")] pub fn sgx_qv_set_path(path_type: sgx_qv_path_type_t, path: &str) -> quote3_error_t { @@ -401,7 +401,7 @@ impl<'a> From<&'a Collateral> for SgxQlQveCollateralT<'a> { } } -impl<'a> Deref for SgxQlQveCollateralT<'a> { +impl Deref for SgxQlQveCollateralT<'_> { type Target = sgx_ql_qve_collateral_t; fn deref(&self) -> &Self::Target { @@ -413,13 +413,13 @@ impl<'a> Deref for SgxQlQveCollateralT<'a> { /// /// # Param /// - **quote**\ -/// SGX/TDX Quote, presented as u8 vector. +/// SGX/TDX Quote, presented as u8 vector. /// /// # Return /// Result type of quote_collateral. /// /// - **quote_collateral**\ -/// This is the Quote Certification Collateral retrieved based on Quote. +/// This is the Quote Certification Collateral retrieved based on Quote. /// /// Status code of the operation, one of: /// - *SGX_QL_ERROR_INVALID_PARAMETER* @@ -457,15 +457,15 @@ pub fn tee_qv_get_collateral(quote: &[u8]) -> Result /// /// # Param /// - **quote**\ -/// SGX/TDX Quote, presented as u8 vector. +/// SGX/TDX Quote, presented as u8 vector. /// /// # Return /// Result type of (version, data_size) tuple. /// /// - **version**\ -/// Latest version of the supplemental data. +/// Latest version of the supplemental data. /// - **data_size**\ -/// The size of the buffer in bytes required to contain all of the supplemental data. +/// The size of the buffer in bytes required to contain all of the supplemental data. /// pub fn tee_get_supplemental_data_version_and_size( quote: &[u8], @@ -491,22 +491,22 @@ pub fn tee_get_supplemental_data_version_and_size( /// /// # Param /// - **quote**\ -/// SGX/TDX Quote, presented as u8 vector. +/// SGX/TDX Quote, presented as u8 vector. /// - **quote_collateral**\ -/// Quote Certification Collateral provided by the caller. +/// Quote Certification Collateral provided by the caller. /// - **expiration_check_date**\ -/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. /// - **qve_report_info**\ -/// This parameter can be used in 2 ways.\ +/// This parameter can be used in 2 ways.\ /// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ /// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. /// - **supp_datal_descriptor**\ -/// *tee_supp_data_descriptor_t* structure.\ -/// You can specify the major version of supplemental data by setting supp_datal_descriptor.major_version.\ -/// If supp_datal_descriptor is None, no supplemental data is returned.\ -/// If supp_datal_descriptor.major_version == 0, then return the latest version of the *sgx_ql_qv_supplemental_t* structure.\ -/// If supp_datal_descriptor.major_version <= latest supported version, return the latest minor version associated with that major version.\ -/// If supp_datal_descriptor.major_version > latest supported version, return an error *SGX_QL_SUPPLEMENTAL_DATA_VERSION_NOT_SUPPORTED*. +/// *tee_supp_data_descriptor_t* structure.\ +/// You can specify the major version of supplemental data by setting supp_datal_descriptor.major_version.\ +/// If supp_datal_descriptor is None, no supplemental data is returned.\ +/// If supp_datal_descriptor.major_version == 0, then return the latest version of the *sgx_ql_qv_supplemental_t* structure.\ +/// If supp_datal_descriptor.major_version <= latest supported version, return the latest minor version associated with that major version.\ +/// If supp_datal_descriptor.major_version > latest supported version, return an error *SGX_QL_SUPPLEMENTAL_DATA_VERSION_NOT_SUPPORTED*. /// /// # Return /// Result type of (collateral_expiration_status, verification_result). From 4610475fae86c8068d2539deaeb512dbd19dd710 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 09:07:36 +0100 Subject: [PATCH 018/114] feat: add TDX support Signed-off-by: Harald Hoyer --- Cargo.lock | 184 ++- Cargo.toml | 9 +- bin/tee-key-preexec/src/main.rs | 10 +- bin/verify-attestation/src/main.rs | 15 +- .../src/verification.rs | 67 +- crates/teepot/Cargo.toml | 4 +- crates/teepot/src/client/mod.rs | 20 +- crates/teepot/src/client/vault.rs | 34 +- crates/teepot/src/lib.rs | 6 +- crates/teepot/src/quote/error.rs | 85 ++ crates/teepot/src/quote/mod.rs | 729 +++++++++- crates/teepot/src/server/attestation.rs | 25 +- crates/teepot/src/server/pki.rs | 55 +- crates/teepot/src/sgx/error.rs | 50 - crates/teepot/src/sgx/mod.rs | 168 +-- crates/teepot/src/tdx/mod.rs | 30 + crates/teepot/tests/sgx_quote_verification.rs | 1184 ++++++++++++++++- packages/teepot/default.nix | 10 +- 18 files changed, 2316 insertions(+), 369 deletions(-) create mode 100644 crates/teepot/src/quote/error.rs delete mode 100644 crates/teepot/src/sgx/error.rs create mode 100644 crates/teepot/src/tdx/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 0bf6a65..355096c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "actix-codec" @@ -311,6 +311,15 @@ dependencies = [ "libc", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anstyle" version = "1.0.8" @@ -358,6 +367,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -535,6 +555,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "bindgen" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "clap 2.34.0", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + [[package]] name = "bindgen" version = "0.65.1" @@ -849,6 +892,21 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "clap" version = "4.5.17" @@ -1486,6 +1544,19 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "envy" version = "0.4.2" @@ -1948,6 +2019,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.9" @@ -2066,6 +2146,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.30" @@ -2794,7 +2880,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "log", "wasi", @@ -4702,6 +4788,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.10.0" @@ -4827,12 +4919,28 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tdx-attest-rs" +version = "0.1.2" +source = "git+https://github.com/intel/SGXDataCenterAttestationPrimitives.git?rev=aa239d25a437a28f3f4de92c38f5b6809faac842#aa239d25a437a28f3f4de92c38f5b6809faac842" +dependencies = [ + "tdx-attest-sys", +] + +[[package]] +name = "tdx-attest-sys" +version = "0.1.0" +source = "git+https://github.com/intel/SGXDataCenterAttestationPrimitives.git?rev=aa239d25a437a28f3f4de92c38f5b6809faac842#aa239d25a437a28f3f4de92c38f5b6809faac842" +dependencies = [ + "bindgen 0.59.2", +] + [[package]] name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap", + "clap 4.5.17", "rand", "secp256k1 0.29.1", "teepot", @@ -4846,7 +4954,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap", + "clap 4.5.17", "rsa", "teepot", "tracing", @@ -4874,7 +4982,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap", + "clap 4.5.17", "serde", "teepot", "tracing", @@ -4890,7 +4998,7 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap", + "clap 4.5.17", "hex", "rustls 0.22.4", "serde_json", @@ -4909,7 +5017,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap", + "clap 4.5.17", "rustls 0.22.4", "serde_json", "teepot", @@ -4929,7 +5037,7 @@ dependencies = [ "base64 0.22.1", "bytemuck", "bytes", - "clap", + "clap 4.5.17", "const-oid", "enumset", "futures-core", @@ -4948,12 +5056,15 @@ dependencies = [ "serde_with 3.9.0", "sha2", "signature 2.2.0", + "tdx-attest-rs", "teepot-tee-quote-verification-rs", "testaso", "thiserror", + "tokio", "tracing", "tracing-log 0.2.0", "tracing-subscriber", + "tracing-test", "webpki-roots", "x509-cert", "zeroize", @@ -4966,7 +5077,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap", + "clap 4.5.17", "serde_json", "teepot", "tracing", @@ -4989,7 +5100,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap", + "clap 4.5.17", "serde_json", "teepot", "tracing", @@ -5010,6 +5121,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.3.0" @@ -5026,6 +5146,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b4d2149a2f578665ca39f8115084635847e9dd6921b5442dcafc7f87bb8e99" +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -5432,6 +5561,27 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracing-test" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68" +dependencies = [ + "tracing-core", + "tracing-subscriber", + "tracing-test-macro", +] + +[[package]] +name = "tracing-test-macro" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" +dependencies = [ + "quote", + "syn 2.0.77", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -5583,7 +5733,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap", + "clap 4.5.17", "hex", "pgp", "serde_json", @@ -5600,7 +5750,7 @@ dependencies = [ "actix-web", "anyhow", "base64 0.22.1", - "clap", + "clap 4.5.17", "serde_json", "teepot", "tracing", @@ -5614,12 +5764,18 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap", + "clap 4.5.17", "hex", "secp256k1 0.29.1", "teepot", @@ -5631,7 +5787,7 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap", + "clap 4.5.17", "ctrlc", "hex", "jsonrpsee-types", diff --git a/Cargo.toml b/Cargo.toml index 7064332..d36677f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,18 +17,15 @@ homepage = "https://github.com/matter-labs/teepot" [workspace.dependencies] actix-http = "3" -actix-tls = "3" actix-web = { version = "4.5", features = ["rustls-0_22"] } anyhow = "1.0.82" awc = { version = "3.4", features = ["rustls-0_22-webpki-roots"] } base64 = "0.22.0" -bitflags = "2.5" bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "extern_crate_std"] } bytes = "1" clap = { version = "4.5", features = ["std", "derive", "env", "error-context", "help", "usage", "wrap_help"], default-features = false } const-oid = { version = "0.9", default-features = false } ctrlc = "3.4" -der = "0.7.9" enumset = { version = "1.1", features = ["serde"] } futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } getrandom = "0.2.14" @@ -36,7 +33,6 @@ 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.3.0" } intel-tee-quote-verification-sys = { version = "0.2.1" } jsonrpsee-types = { version = "0.23", default-features = false } -log = "0.4" num-integer = "0.1.46" num-traits = "0.2.18" p256 = "0.13.2" @@ -44,17 +40,15 @@ pgp = "0.13" pkcs8 = { version = "0.10" } rand = "0.8" reqwest = { version = "0.12", features = ["json"] } -ring = { version = "0.17.8", features = ["std"], default-features = false } rsa = { version = "0.9.6", features = ["sha2", "pem"] } rustls = { version = "0.22" } -rustls-pemfile = "2" -sec1 = { version = "0.7.3", features = ["der"], default-features = false } secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] } serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" serde_with = { version = "3.8", features = ["base64", "hex"] } sha2 = "0.10.8" signature = "2.2.0" +tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } teepot = { path = "crates/teepot" } testaso = "0.1.0" thiserror = "1.0.59" @@ -63,6 +57,7 @@ tracing = "0.1" tracing-actix-web = "0.7" tracing-log = "0.2" tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-test = { version = "0.2.5", features = ["no-env-filter"] } url = "2.5.2" webpki-roots = "0.26.1" x509-cert = { version = "0.2", features = ["builder", "signature"] } diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 6af0c09..70be9c4 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -9,9 +9,7 @@ use anyhow::{Context, Result}; use clap::Parser; use secp256k1::{rand, Keypair, PublicKey, Secp256k1, SecretKey}; -use std::ffi::OsString; -use std::os::unix::process::CommandExt; -use std::process::Command; +use std::{ffi::OsString, os::unix::process::CommandExt, process::Command}; use teepot::quote::get_quote; use tracing::error; use tracing_log::LogTracer; @@ -47,15 +45,15 @@ fn main_with_error() -> Result<()> { let verifying_key = PublicKey::from_keypair(&keypair); let verifying_key_bytes = verifying_key.serialize(); let tee_type = match get_quote(verifying_key_bytes.as_ref()) { - Ok(quote) => { + Ok((tee_type, quote)) => { // save quote to file std::fs::write(TEE_QUOTE_FILE, quote)?; - "sgx" + tee_type.to_string() } Err(e) => { error!("Failed to get quote: {}", e); std::fs::write(TEE_QUOTE_FILE, [])?; - "none" + "none".to_string() } }; diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index 7f0c380..d799462 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -9,7 +9,7 @@ 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}, + quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, }; use zksync_basic_types::H256; @@ -84,7 +84,7 @@ fn verify_signature( quote_verification_result: &QuoteVerificationResult, signature_args: &SignatureArgs, ) -> Result<()> { - let reportdata = "e_verification_result.quote.report_body.reportdata; + let reportdata = "e_verification_result.quote.get_report_data(); let public_key = PublicKey::from_slice(reportdata)?; println!("Public key from attestation quote: {}", public_key); let signature_bytes = fs::read(&signature_args.signature_file)?; @@ -103,8 +103,10 @@ fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result, + quote_verification_result: &QuoteVerificationResult, attestation_policy: &AttestationPolicyArgs, node_client: &impl JsonRpcClient, signature: &[u8], @@ -28,7 +29,7 @@ pub async fn verify_batch_proof( let batch_no = batch_number.0; let public_key = PublicKey::from_slice( - "e_verification_result.quote.report_body.reportdata[..PUBLIC_KEY_SIZE], + "e_verification_result.quote.get_report_data()[..PUBLIC_KEY_SIZE], )?; debug!(batch_no, "public key: {}", public_key); @@ -45,8 +46,10 @@ pub async fn verify_batch_proof( } pub fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { - let collateral = - tee_qv_get_collateral(attestation_quote_bytes).context("Failed to get collateral!")?; + let collateral = QuoteContext::context( + tee_qv_get_collateral(attestation_quote_bytes), + "Failed to get collateral!", + )?; let unix_time: i64 = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH)? .as_secs() as _; @@ -66,17 +69,19 @@ pub fn log_quote_verification_summary(quote_verification_result: &QuoteVerificat warn!("Freshly fetched collateral expired!"); } let tcblevel = TcbLevel::from(*result); + let advisories = if advisories.is_empty() { + "None".to_string() + } else { + advisories + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + }; + info!( - "Quote verification result: {}. mrsigner: {}, mrenclave: {}, reportdata: {}. Advisory IDs: {}.", - tcblevel, - hex::encode(quote.report_body.mrsigner), - hex::encode(quote.report_body.mrenclave), - hex::encode(quote.report_body.reportdata), - if advisories.is_empty() { - "None".to_string() - } else { - advisories.iter().map(ToString::to_string).collect::>().join(", ") - } + "Quote verification result: {tcblevel}. {report}. Advisory IDs: {advisories}.", + report = "e.report ); } @@ -88,7 +93,7 @@ fn verify_signature(signature: &[u8], public_key: PublicKey, root_hash: H256) -> fn is_quote_matching_policy( attestation_policy: &AttestationPolicyArgs, - quote_verification_result: &QuoteVerificationResult<'_>, + quote_verification_result: &QuoteVerificationResult, ) -> bool { let quote = "e_verification_result.quote; let tcblevel = TcbLevel::from(quote_verification_result.result); @@ -100,16 +105,20 @@ fn is_quote_matching_policy( ); return false; } - - check_policy( - attestation_policy.sgx_mrsigners.as_deref(), - "e.report_body.mrsigner, - "mrsigner", - ) && check_policy( - attestation_policy.sgx_mrenclaves.as_deref(), - "e.report_body.mrenclave, - "mrenclave", - ) + match "e.report { + Report::SgxEnclave(report_body) => { + check_policy( + attestation_policy.sgx_mrsigners.as_deref(), + &report_body.mr_signer, + "mrsigner", + ) && check_policy( + attestation_policy.sgx_mrenclaves.as_deref(), + &report_body.mr_enclave, + "mrenclave", + ) + } + _ => false, + } } fn check_policy(policy: Option<&str>, actual_value: &[u8], field_name: &str) -> bool { diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index c33aa89..df20004 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -37,6 +37,7 @@ serde_json.workspace = true serde_with.workspace = true sha2.workspace = true signature.workspace = true +tdx-attest-rs.workspace = true thiserror.workspace = true tracing.workspace = true tracing-log.workspace = true @@ -48,5 +49,6 @@ zeroize.workspace = true [dev-dependencies] anyhow.workspace = true base64.workspace = true -hex.workspace = true testaso.workspace = true +tokio.workspace = true +tracing-test.workspace = true diff --git a/crates/teepot/src/client/mod.rs b/crates/teepot/src/client/mod.rs index 3b21841..284468d 100644 --- a/crates/teepot/src/client/mod.rs +++ b/crates/teepot/src/client/mod.rs @@ -8,12 +8,12 @@ pub mod vault; +pub use crate::quote::verify_quote_with_collateral; +pub use crate::quote::QuoteVerificationResult; +use crate::quote::Report; use crate::server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}; use crate::sgx::Quote; -pub use crate::sgx::{ - parse_tcb_levels, sgx_ql_qv_result_t, verify_quote_with_collateral, EnumSet, - QuoteVerificationResult, TcbLevel, -}; +pub use crate::sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}; use actix_web::http::header; use anyhow::Result; use awc::{Client, Connector}; @@ -195,6 +195,10 @@ impl TeeConnection { } = verify_quote_with_collateral(quote_bytes, collateral.as_ref(), current_time) .unwrap(); + let Report::SgxEnclave(report_body) = quote.report else { + return Err(Error::General("TDX quote and not SGX quote".into())); + }; + if collateral_expired || result != sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK { if collateral_expired { error!( @@ -230,10 +234,10 @@ impl TeeConnection { if let Some(mrsigner) = &self.args.sgx_mrsigner { let mrsigner_bytes = hex::decode(mrsigner) .map_err(|e| Error::General(format!("Failed to decode mrsigner: {}", e)))?; - if quote.report_body.mrsigner[..] != mrsigner_bytes { + if report_body.mr_signer[..] != mrsigner_bytes { return Err(Error::General(format!( "mrsigner mismatch: got {}, expected {}", - hex::encode(quote.report_body.mrsigner), + hex::encode(report_body.mr_signer), &mrsigner ))); } else { @@ -245,10 +249,10 @@ impl TeeConnection { let mrenclave_bytes = hex::decode(mrenclave).map_err(|e| { Error::General(format!("Failed to decode mrenclave: {}", e)) })?; - if quote.report_body.mrenclave[..] != mrenclave_bytes { + if report_body.mr_enclave[..] != mrenclave_bytes { return Err(Error::General(format!( "mrenclave mismatch: got {}, expected {}", - hex::encode(quote.report_body.mrenclave), + hex::encode(report_body.mr_enclave), &mrenclave ))); } else { diff --git a/crates/teepot/src/client/vault.rs b/crates/teepot/src/client/vault.rs index 8d7ef43..fd25d4b 100644 --- a/crates/teepot/src/client/vault.rs +++ b/crates/teepot/src/client/vault.rs @@ -7,26 +7,34 @@ #![deny(clippy::all)] use super::{AttestationArgs, TeeConnection}; -use crate::json::http::{AuthRequest, AuthResponse}; -use crate::server::pki::make_self_signed_cert; -use crate::server::{AnyHowResponseError, HttpResponseError, Status}; -pub use crate::sgx::{ - parse_tcb_levels, sgx_gramine_get_quote, sgx_ql_qv_result_t, tee_qv_get_collateral, - verify_quote_with_collateral, Collateral, EnumSet, QuoteVerificationResult, TcbLevel, +use crate::{ + json::http::{AuthRequest, AuthResponse}, + quote::error::QuoteContext, + server::{pki::make_self_signed_cert, AnyHowResponseError, HttpResponseError, Status}, +}; +pub use crate::{ + quote::{verify_quote_with_collateral, QuoteVerificationResult}, + sgx::{ + parse_tcb_levels, sgx_gramine_get_quote, sgx_ql_qv_result_t, Collateral, EnumSet, TcbLevel, + }, }; use actix_http::error::PayloadError; -use actix_web::http::header; -use actix_web::ResponseError; +use actix_web::{http::header, ResponseError}; use anyhow::{anyhow, bail, Context, Result}; -use awc::error::{SendRequestError, StatusCode}; -use awc::{Client, ClientResponse, Connector}; +use awc::{ + error::{SendRequestError, StatusCode}, + Client, ClientResponse, Connector, +}; use bytes::Bytes; use futures_core::Stream; +use intel_tee_quote_verification_rs::tee_qv_get_collateral; use rustls::ClientConfig; use serde_json::{json, Value}; -use std::fmt::{Display, Formatter}; -use std::sync::Arc; -use std::time; +use std::{ + fmt::{Display, Formatter}, + sync::Arc, + time, +}; use tracing::{debug, error, info, trace}; const VAULT_TOKEN_HEADER: &str = "X-Vault-Token"; diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index b3bcf16..293ef83 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -8,8 +8,8 @@ pub mod client; pub mod json; -pub mod server; -pub mod sgx; - pub mod log; pub mod quote; +pub mod server; +pub mod sgx; +pub mod tdx; diff --git a/crates/teepot/src/quote/error.rs b/crates/teepot/src/quote/error.rs new file mode 100644 index 0000000..508b5f3 --- /dev/null +++ b/crates/teepot/src/quote/error.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +//! Quote Error type + +use intel_tee_quote_verification_rs::quote3_error_t; +use std::io; +use tdx_attest_rs::tdx_attest_error_t; +use thiserror::Error; + +/// Quote parsing error +#[derive(Error, Debug)] +#[allow(missing_docs)] +pub enum QuoteError { + #[error("I/O Error")] + IoError { context: String, source: io::Error }, + #[error("parsing bytes")] + ConvertError(#[from] bytemuck::PodCastError), + #[error("unsupported quote version")] + QuoteVersion, + #[error("invalid tee type")] + InvalidTeeType, + #[error("unsupported body type")] + UnsupportedBodyType, + #[error("quote verification error {msg}: {inner:?}")] + Quote3Error { inner: quote3_error_t, msg: String }, + #[error("tdx_att_get_quote error {msg}: {inner:?}")] + TdxAttGetQuote { + inner: tdx_attest_error_t, + msg: String, + }, + #[error("invalid version")] + InvalidVersion, + #[error("report data too long")] + ReportDataSize, + #[error("can't get a quote: unknown TEE")] + UnknownTee, +} + +impl From for QuoteError { + fn from(code: tdx_attest_error_t) -> Self { + Self::TdxAttGetQuote { + inner: code, + msg: "code".to_string(), + } + } +} + +/// Usability trait for easy QuoteError annotation +pub trait QuoteContext { + /// The Ok Type + type Ok; + /// The Context + fn context>(self, msg: I) -> Result; +} + +impl QuoteContext for Result { + type Ok = T; + fn context>(self, msg: I) -> Result { + self.map_err(|e| QuoteError::IoError { + context: msg.into(), + source: e, + }) + } +} + +impl QuoteContext for Result { + type Ok = T; + fn context>(self, msg: I) -> Result { + self.map_err(|e| QuoteError::Quote3Error { + msg: msg.into(), + inner: e, + }) + } +} + +impl QuoteContext for Result { + type Ok = T; + fn context>(self, msg: I) -> Result { + self.map_err(|e| QuoteError::TdxAttGetQuote { + msg: msg.into(), + inner: e, + }) + } +} diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 4d8ae51..5f01993 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -1,40 +1,733 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2023-2024 Matter Labs +// Parts of it are Copyright (c) 2024 Phala Network +// and copied from https://github.com/Phala-Network/dcap-qvl + //! Get a quote from a TEE +pub mod error; -use crate::sgx::sgx_gramine_get_quote; -use std::io; +use crate::{ + quote::error::{QuoteContext as _, QuoteError}, + sgx::sgx_gramine_get_quote, + tdx::tgx_get_quote, +}; +use bytemuck::{cast_slice, AnyBitPattern}; +use intel_tee_quote_verification_rs::{ + sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, tee_get_supplemental_data_version_and_size, + tee_supp_data_descriptor_t, tee_verify_quote, Collateral, +}; +use serde::{Deserialize, Serialize}; +use std::{ + ffi::CStr, + fmt::{Display, Formatter}, + io::Read, + mem, + str::FromStr, +}; +use tracing::{trace, warn}; + +pub use intel_tee_quote_verification_rs::tee_qv_get_collateral; -#[derive(Debug, thiserror::Error)] #[allow(missing_docs)] -#[error("{msg}")] -pub struct GetQuoteError { - pub(crate) msg: Box, - #[source] // optional if field name is `source` - pub(crate) source: io::Error, +pub const TEE_TYPE_SGX: u32 = 0x00000000; +#[allow(missing_docs)] +pub const TEE_TYPE_TDX: u32 = 0x00000081; + +#[allow(missing_docs)] +pub const BODY_SGX_ENCLAVE_REPORT_TYPE: u16 = 1; +#[allow(missing_docs)] +pub const BODY_TD_REPORT10_TYPE: u16 = 2; +#[allow(missing_docs)] +pub const BODY_TD_REPORT15_TYPE: u16 = 3; +#[allow(missing_docs)] +pub const ENCLAVE_REPORT_BYTE_LEN: usize = 384; + +#[allow(missing_docs)] +pub const ECDSA_SIGNATURE_BYTE_LEN: usize = 64; +#[allow(missing_docs)] +pub const ECDSA_PUBKEY_BYTE_LEN: usize = 64; +#[allow(missing_docs)] +pub const QE_REPORT_SIG_BYTE_LEN: usize = ECDSA_SIGNATURE_BYTE_LEN; + +mod serde_bytes { + use serde::Deserialize; + + pub(crate) trait FromBytes { + fn from_bytes(bytes: Vec) -> Option + where + Self: Sized; + } + impl FromBytes for Vec { + fn from_bytes(bytes: Vec) -> Option { + Some(bytes) + } + } + impl FromBytes for [u8; N] { + fn from_bytes(bytes: Vec) -> Option { + bytes.try_into().ok() + } + } + + pub(crate) fn serialize( + data: impl AsRef<[u8]>, + serializer: S, + ) -> Result { + let hex_str = hex::encode(data); + serializer.serialize_str(&hex_str) + } + + pub(crate) fn deserialize<'de, D: serde::Deserializer<'de>, T: FromBytes>( + deserializer: D, + ) -> Result { + let hex_str = String::deserialize(deserializer)?; + let bytes = hex::decode(hex_str).map_err(serde::de::Error::custom)?; + T::from_bytes(bytes).ok_or_else(|| serde::de::Error::custom("invalid bytes")) + } +} + +/// Trait that allows zero-copy read of value-references from slices in LE format. +pub trait Decode: Sized { + /// Attempt to deserialise the value from input. + fn decode(input: &mut I) -> Result; +} + +impl Decode for T { + fn decode(input: &mut I) -> Result { + let mut bytes = vec![0u8; size_of::()]; + input.read(&mut bytes).context("parsing bytes")?; + bytemuck::try_pod_read_unaligned(&bytes).map_err(Into::into) + } +} + +#[derive(Debug, Clone)] +#[allow(missing_docs)] +#[repr(C)] +pub struct Data { + pub data: Vec, + _marker: core::marker::PhantomData, +} + +impl Serialize for Data { + fn serialize(&self, serializer: S) -> Result { + serde_bytes::serialize(&self.data, serializer) + } +} + +impl<'de, T> Deserialize<'de> for Data { + fn deserialize>(deserializer: D) -> Result { + let data = serde_bytes::deserialize(deserializer)?; + Ok(Data { + data, + _marker: core::marker::PhantomData, + }) + } +} + +impl> Decode for Data { + fn decode(input: &mut I) -> Result { + let len = T::decode(input)?; + let mut data = vec![0u8; len.into() as usize]; + input.read(&mut data).context("reading bytes")?; + Ok(Data { + data, + _marker: core::marker::PhantomData, + }) + } +} + +#[allow(missing_docs)] +#[derive(AnyBitPattern, Debug, Serialize, Deserialize, Copy, Clone)] +#[repr(C, packed)] +pub struct Header { + pub version: u16, + pub attestation_key_type: u16, + pub tee_type: u32, + pub qe_svn: u16, + pub pce_svn: u16, + #[serde(with = "serde_bytes")] + pub qe_vendor_id: [u8; 16], + #[serde(with = "serde_bytes")] + pub user_data: [u8; 20], +} + +#[derive(AnyBitPattern, Debug, Copy, Clone)] +#[allow(missing_docs)] +#[repr(C, packed)] +pub struct Body { + pub body_type: u16, + pub size: u32, +} + +#[derive(Serialize, Deserialize, AnyBitPattern, Debug, Clone, Copy)] +#[allow(missing_docs)] +#[repr(C, packed)] +pub struct EnclaveReport { + #[serde(with = "serde_bytes")] + pub cpu_svn: [u8; 16], + pub misc_select: u32, + #[serde(with = "serde_bytes")] + pub reserved1: [u8; 28], + #[serde(with = "serde_bytes")] + pub attributes: [u8; 16], + #[serde(with = "serde_bytes")] + pub mr_enclave: [u8; 32], + #[serde(with = "serde_bytes")] + pub reserved2: [u8; 32], + #[serde(with = "serde_bytes")] + pub mr_signer: [u8; 32], + #[serde(with = "serde_bytes")] + pub reserved3: [u8; 96], + pub isv_prod_id: u16, + pub isv_svn: u16, + #[serde(with = "serde_bytes")] + pub reserved4: [u8; 60], + #[serde(with = "serde_bytes")] + pub report_data: [u8; 64], +} + +#[derive(AnyBitPattern, Debug, Copy, Clone, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C, packed)] +pub struct TDReport10 { + #[serde(with = "serde_bytes")] + pub tee_tcb_svn: [u8; 16], + #[serde(with = "serde_bytes")] + pub mr_seam: [u8; 48], + #[serde(with = "serde_bytes")] + pub mr_signer_seam: [u8; 48], + #[serde(with = "serde_bytes")] + pub seam_attributes: [u8; 8], + #[serde(with = "serde_bytes")] + pub td_attributes: [u8; 8], + #[serde(with = "serde_bytes")] + pub xfam: [u8; 8], + #[serde(with = "serde_bytes")] + pub mr_td: [u8; 48], + #[serde(with = "serde_bytes")] + pub mr_config_id: [u8; 48], + #[serde(with = "serde_bytes")] + pub mr_owner: [u8; 48], + #[serde(with = "serde_bytes")] + pub mr_owner_config: [u8; 48], + #[serde(with = "serde_bytes")] + pub rt_mr0: [u8; 48], + #[serde(with = "serde_bytes")] + pub rt_mr1: [u8; 48], + #[serde(with = "serde_bytes")] + pub rt_mr2: [u8; 48], + #[serde(with = "serde_bytes")] + pub rt_mr3: [u8; 48], + #[serde(with = "serde_bytes")] + pub report_data: [u8; 64], +} + +#[derive(AnyBitPattern, Debug, Copy, Clone, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C, packed)] +pub struct TDReport15 { + pub base: TDReport10, + #[serde(with = "serde_bytes")] + pub tee_tcb_svn2: [u8; 16], + #[serde(with = "serde_bytes")] + pub mr_service_td: [u8; 48], +} + +#[allow(missing_docs)] +#[derive(Serialize, Deserialize, Clone)] +#[repr(C)] +pub struct CertificationData { + pub cert_type: u16, + pub body: Data, +} + +impl Decode for CertificationData { + fn decode(input: &mut I) -> Result { + Ok(Self { + cert_type: Decode::decode(input)?, + body: Decode::decode(input)?, + }) + } +} + +impl core::fmt::Debug for CertificationData { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let body_str = String::from_utf8_lossy(&self.body.data); + f.debug_struct("CertificationData") + .field("cert_type", &self.cert_type) + .field("body", &body_str) + .finish() + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C)] +pub struct QEReportCertificationData { + #[serde(with = "serde_bytes")] + pub qe_report: [u8; ENCLAVE_REPORT_BYTE_LEN], + #[serde(with = "serde_bytes")] + pub qe_report_signature: [u8; QE_REPORT_SIG_BYTE_LEN], + pub qe_auth_data: Data, + pub certification_data: CertificationData, +} + +impl Decode for QEReportCertificationData { + fn decode(input: &mut I) -> Result { + Ok(Self { + qe_report: Decode::decode(input)?, + qe_report_signature: Decode::decode(input)?, + qe_auth_data: Decode::decode(input)?, + certification_data: Decode::decode(input)?, + }) + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C)] +pub struct AuthDataV3 { + #[serde(with = "serde_bytes")] + pub ecdsa_signature: [u8; ECDSA_SIGNATURE_BYTE_LEN], + #[serde(with = "serde_bytes")] + pub ecdsa_attestation_key: [u8; ECDSA_PUBKEY_BYTE_LEN], + #[serde(with = "serde_bytes")] + pub qe_report: [u8; ENCLAVE_REPORT_BYTE_LEN], + #[serde(with = "serde_bytes")] + pub qe_report_signature: [u8; QE_REPORT_SIG_BYTE_LEN], + pub qe_auth_data: Data, + pub certification_data: CertificationData, +} + +impl Decode for AuthDataV3 { + fn decode(input: &mut I) -> Result { + Ok(Self { + ecdsa_signature: Decode::decode(input)?, + ecdsa_attestation_key: Decode::decode(input)?, + qe_report: Decode::decode(input)?, + qe_report_signature: Decode::decode(input)?, + qe_auth_data: Decode::decode(input)?, + certification_data: Decode::decode(input)?, + }) + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C)] +pub struct AuthDataV4 { + #[serde(with = "serde_bytes")] + pub ecdsa_signature: [u8; ECDSA_SIGNATURE_BYTE_LEN], + #[serde(with = "serde_bytes")] + pub ecdsa_attestation_key: [u8; ECDSA_PUBKEY_BYTE_LEN], + pub certification_data: CertificationData, + pub qe_report_data: QEReportCertificationData, +} + +impl AuthDataV4 { + #[allow(missing_docs)] + pub fn into_v3(self) -> AuthDataV3 { + AuthDataV3 { + ecdsa_signature: self.ecdsa_signature, + ecdsa_attestation_key: self.ecdsa_attestation_key, + qe_report: self.qe_report_data.qe_report, + qe_report_signature: self.qe_report_data.qe_report_signature, + qe_auth_data: self.qe_report_data.qe_auth_data, + certification_data: self.qe_report_data.certification_data, + } + } +} + +impl Decode for AuthDataV4 { + fn decode(input: &mut I) -> Result { + let ecdsa_signature = Decode::decode(input)?; + let ecdsa_attestation_key = Decode::decode(input)?; + let certification_data: CertificationData = Decode::decode(input)?; + let qe_report_data = + QEReportCertificationData::decode(&mut &certification_data.body.data[..])?; + Ok(AuthDataV4 { + ecdsa_signature, + ecdsa_attestation_key, + certification_data, + qe_report_data, + }) + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C)] +pub enum AuthData { + V3(AuthDataV3), + V4(AuthDataV4), +} + +impl AuthData { + #[allow(missing_docs)] + pub fn into_v3(self) -> AuthDataV3 { + match self { + AuthData::V3(data) => data, + AuthData::V4(data) => data.into_v3(), + } + } +} + +fn decode_auth_data(ver: u16, input: &mut &[u8]) -> Result { + match ver { + 3 => { + let auth_data = AuthDataV3::decode(input)?; + Ok(AuthData::V3(auth_data)) + } + 4 => { + let auth_data = AuthDataV4::decode(input)?; + Ok(AuthData::V4(auth_data)) + } + _ => Err(error::QuoteError::QuoteVersion), + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C)] +#[non_exhaustive] +pub enum Report { + SgxEnclave(EnclaveReport), + TD10(TDReport10), + TD15(TDReport15), +} + +impl Report { + #[allow(missing_docs)] + pub fn is_sgx(&self) -> bool { + matches!(self, Report::SgxEnclave(_)) + } + + #[allow(missing_docs)] + pub fn as_td10(&self) -> Option<&TDReport10> { + match self { + Report::TD10(report) => Some(report), + Report::TD15(report) => Some(&report.base), + _ => None, + } + } + + #[allow(missing_docs)] + pub fn as_td15(&self) -> Option<&TDReport15> { + match self { + Report::TD15(report) => Some(report), + _ => None, + } + } + + #[allow(missing_docs)] + pub fn as_sgx(&self) -> Option<&EnclaveReport> { + match self { + Report::SgxEnclave(report) => Some(report), + _ => None, + } + } +} + +impl Display for Report { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn space_or_newline(f: &mut Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + writeln!(f) + } else { + write!(f, " ") + } + } + match self { + Report::SgxEnclave(report_body) => { + write!(f, "mrsigner: {}", hex::encode(report_body.mr_signer))?; + space_or_newline(f)?; + write!(f, "mrenclave: {}", hex::encode(report_body.mr_enclave))?; + space_or_newline(f)?; + write!( + f, + "reportdata: {}", + hex::encode(report_body.report_data.as_slice()) + )?; + } + Report::TD10(report_body) => { + write!(f, "mrtd: {}", hex::encode(report_body.mr_td))?; + space_or_newline(f)?; + write!(f, "rtmr0: {}", hex::encode(report_body.rt_mr0))?; + space_or_newline(f)?; + write!(f, "rtmr1: {}", hex::encode(report_body.rt_mr1))?; + space_or_newline(f)?; + write!(f, "rtmr2: {}", hex::encode(report_body.rt_mr2))?; + space_or_newline(f)?; + write!(f, "rtmr3: {}", hex::encode(report_body.rt_mr3))?; + space_or_newline(f)?; + write!( + f, + "reportdata: {}", + hex::encode(report_body.report_data.as_slice()) + )?; + } + Report::TD15(report_body) => { + let report_body = &report_body.base; + write!(f, "mrtd: {}", hex::encode(report_body.mr_td))?; + space_or_newline(f)?; + write!(f, "rtmr0: {}", hex::encode(report_body.rt_mr0))?; + space_or_newline(f)?; + write!(f, "rtmr1: {}", hex::encode(report_body.rt_mr1))?; + space_or_newline(f)?; + write!(f, "rtmr2: {}", hex::encode(report_body.rt_mr2))?; + space_or_newline(f)?; + write!(f, "rtmr3: {}", hex::encode(report_body.rt_mr3))?; + space_or_newline(f)?; + write!( + f, + "reportdata: {}", + hex::encode(report_body.report_data.as_slice()) + )?; + } + } + Ok(()) + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[allow(missing_docs)] +#[repr(C)] +pub struct Quote { + pub header: Header, + pub report: Report, + pub auth_data: AuthData, +} + +impl Decode for Quote { + fn decode(input: &mut I) -> Result { + let header = Header::decode(input)?; + trace!(?header); + let report; + match header.version { + 3 => { + if header.tee_type != TEE_TYPE_SGX { + return Err(error::QuoteError::InvalidTeeType); + } + report = Report::SgxEnclave(EnclaveReport::decode(input)?); + } + 4 => match header.tee_type { + TEE_TYPE_SGX => { + report = Report::SgxEnclave(EnclaveReport::decode(input)?); + } + TEE_TYPE_TDX => { + report = Report::TD10(TDReport10::decode(input)?); + } + _ => return Err(error::QuoteError::InvalidTeeType), + }, + 5 => { + let body = Body::decode(input)?; + match body.body_type { + BODY_SGX_ENCLAVE_REPORT_TYPE => { + report = Report::SgxEnclave(EnclaveReport::decode(input)?); + } + BODY_TD_REPORT10_TYPE => { + report = Report::TD10(TDReport10::decode(input)?); + } + BODY_TD_REPORT15_TYPE => { + report = Report::TD15(TDReport15::decode(input)?); + } + _ => return Err(error::QuoteError::UnsupportedBodyType), + } + } + _ => return Err(error::QuoteError::QuoteVersion), + } + let data = Data::::decode(input)?; + let auth_data = decode_auth_data(header.version, &mut &data.data[..])?; + Ok(Quote { + header, + report, + auth_data, + }) + } +} + +impl Quote { + /// Parse a TEE quote from a byte slice. + pub fn parse(quote: &[u8]) -> Result { + let mut input = quote; + let quote = Quote::decode(&mut input)?; + Ok(quote) + } + + /// Get the report data + pub fn get_report_data(&self) -> &[u8] { + match &self.report { + Report::SgxEnclave(r) => r.report_data.as_slice(), + Report::TD10(r) => r.report_data.as_slice(), + Report::TD15(r) => r.base.report_data.as_slice(), + } + } +} + +/// TEE type +#[non_exhaustive] +pub enum TEEType { + /// Intel SGX + SGX, + /// Intel TDX + TDX, + /// AMD SEV-SNP + SNP, +} + +impl Display for TEEType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + TEEType::SGX => "sgx", + TEEType::TDX => "tdx", + TEEType::SNP => "snp", + }; + write!(f, "{}", str) + } +} + +impl FromStr for TEEType { + type Err = String; + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "sgx" => Ok(TEEType::SGX), + "tdx" => Ok(TEEType::TDX), + "snp" => Ok(TEEType::SNP), + _ => Err("Invalid TEE type".to_string()), + } + } } /// Get the attestation quote from a TEE -pub fn get_quote(report_data: &[u8]) -> Result, GetQuoteError> { +pub fn get_quote(report_data: &[u8]) -> Result<(TEEType, Box<[u8]>), QuoteError> { // check, if we are running in a TEE if std::fs::metadata("/dev/attestation").is_ok() { if report_data.len() > 64 { - return Err(GetQuoteError { - msg: "Report data too long".into(), - source: io::Error::new(io::ErrorKind::Other, "Report data too long"), - }); + return Err(QuoteError::ReportDataSize); } let mut report_data_fixed = [0u8; 64]; report_data_fixed[..report_data.len()].copy_from_slice(report_data); - sgx_gramine_get_quote(&report_data_fixed) + Ok((TEEType::SGX, sgx_gramine_get_quote(&report_data_fixed)?)) + } else if std::fs::metadata("/dev/tdx_guest").is_ok() { + if report_data.len() > 64 { + return Err(QuoteError::ReportDataSize); + } + + let mut report_data_fixed = [0u8; 64]; + report_data_fixed[..report_data.len()].copy_from_slice(report_data); + + Ok((TEEType::TDX, tgx_get_quote(&report_data_fixed)?)) } else { // if not, return an error - Err(GetQuoteError { - msg: "Not running in a TEE".into(), - source: io::Error::new(io::ErrorKind::Other, "Not running in a TEE"), - }) + Err(QuoteError::UnknownTee) } } + +/// The result of the quote verification +pub struct QuoteVerificationResult { + /// the raw result + pub result: sgx_ql_qv_result_t, + /// indicates if the collateral is expired + pub collateral_expired: bool, + /// the earliest expiration date of the collateral + pub earliest_expiration_date: i64, + /// Date of the TCB level + pub tcb_level_date_tag: i64, + /// the advisory string + pub advisories: Vec, + /// the quote + pub quote: Quote, +} + +/// Verifies a quote with optional collateral material +pub fn verify_quote_with_collateral( + quote: &[u8], + collateral: Option<&Collateral>, + current_time: i64, +) -> Result { + let mut supp_data: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + let mut supp_data_desc = tee_supp_data_descriptor_t { + major_version: 0, + data_size: 0, + p_data: supp_data.as_mut_ptr() as *mut u8, + }; + trace!("tee_get_supplemental_data_version_and_size"); + let (_, supp_size) = + tee_get_supplemental_data_version_and_size(quote).map_err(|e| QuoteError::Quote3Error { + msg: "tee_get_supplemental_data_version_and_size".into(), + inner: e, + })?; + + trace!( + "tee_get_supplemental_data_version_and_size supp_size: {}", + supp_size + ); + + if supp_size == mem::size_of::() as u32 { + supp_data_desc.data_size = supp_size; + } else { + supp_data_desc.data_size = 0; + trace!( + "tee_get_supplemental_data_version_and_size supp_size: {}", + supp_size + ); + trace!( + "mem::size_of::(): {}", + mem::size_of::() + ); + warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you installed DCAP QVL and QvE from same release.") + } + + let p_supplemental_data = match supp_data_desc.data_size { + 0 => None, + _ => Some(&mut supp_data_desc), + }; + + let has_sup = p_supplemental_data.is_some(); + + trace!("tee_verify_quote"); + + let (collateral_expiration_status, result) = + tee_verify_quote(quote, collateral, current_time, None, p_supplemental_data) + .context("tee_verify_quote")?; + + trace!("tee_verify_quote end"); + + // check supplemental data if necessary + let (advisories, earliest_expiration_date, tcb_level_date_tag) = if has_sup { + unsafe { + let supp_data = supp_data.assume_init(); + // convert to valid UTF-8 string + let ads = CStr::from_bytes_until_nul(cast_slice(&supp_data.sa_list[..])) + .ok() + .and_then(|s| CStr::to_str(s).ok()) + .into_iter() + .flat_map(|s| s.split(',').map(str::trim).map(String::from)) + .filter(|s| !s.is_empty()) + .collect(); + ( + ads, + supp_data.earliest_expiration_date, + supp_data.tcb_level_date_tag, + ) + } + } else { + (vec![], 0, 0) + }; + + trace!("Quote::parse"); + let quote = Quote::parse(quote)?; + + let res = QuoteVerificationResult { + collateral_expired: collateral_expiration_status != 0, + earliest_expiration_date, + tcb_level_date_tag, + result, + quote, + advisories, + }; + + Ok(res) +} diff --git a/crates/teepot/src/server/attestation.rs b/crates/teepot/src/server/attestation.rs index e390187..9cafb4d 100644 --- a/crates/teepot/src/server/attestation.rs +++ b/crates/teepot/src/server/attestation.rs @@ -3,17 +3,22 @@ //! Common attestation API for all TEEs -use crate::client::AttestationArgs; -use crate::json::http::AttestationResponse; -use crate::sgx::{ - parse_tcb_levels, sgx_gramine_get_quote, tee_qv_get_collateral, verify_quote_with_collateral, - Collateral, EnumSet, QuoteVerificationResult, TcbLevel, +use crate::{ + client::AttestationArgs, + json::http::AttestationResponse, + quote::{ + error::QuoteContext, get_quote, verify_quote_with_collateral, QuoteVerificationResult, + }, + sgx::{parse_tcb_levels, Collateral, EnumSet, TcbLevel}, }; use anyhow::{bail, Context, Result}; use clap::Args; +use intel_tee_quote_verification_rs::tee_qv_get_collateral; use serde::{Deserialize, Serialize}; -use std::sync::{Arc, RwLock}; -use std::time::{Duration, UNIX_EPOCH}; +use std::{ + sync::{Arc, RwLock}, + time::{Duration, UNIX_EPOCH}, +}; use tracing::{debug, error, info, trace, warn}; struct Attestation { @@ -53,7 +58,7 @@ pub fn get_quote_and_collateral( } } - let myquote = sgx_gramine_get_quote(report_data).context("Failed to get own quote")?; + let (_tee_type, myquote) = get_quote(report_data).context("Failed to get own quote")?; let collateral = tee_qv_get_collateral(&myquote).context("Failed to get own collateral")?; let QuoteVerificationResult { @@ -89,8 +94,8 @@ pub fn get_quote_and_collateral( "Earliest expiration in {:?}", Duration::from_secs((earliest_expiration_date - unix_time) as _) ); - info!("mrsigner: {}", hex::encode(quote.report_body.mrsigner)); - info!("mrenclave: {}", hex::encode(quote.report_body.mrenclave)); + + info!("{:#}", quote.report); let quote: Arc<[u8]> = Arc::from(myquote); let collateral = Arc::from(collateral); diff --git a/crates/teepot/src/server/pki.rs b/crates/teepot/src/server/pki.rs index ce3c110..ffa04c3 100644 --- a/crates/teepot/src/server/pki.rs +++ b/crates/teepot/src/server/pki.rs @@ -3,39 +3,38 @@ //! Create a private key and a signed and self-signed certificates -use crate::quote::get_quote; -use crate::sgx::tee_qv_get_collateral; -pub use crate::sgx::{ - parse_tcb_levels, sgx_ql_qv_result_t, verify_quote_with_collateral, EnumSet, - QuoteVerificationResult, TcbLevel, -}; +use crate::quote::{error::QuoteContext, get_quote}; +pub use crate::sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}; use anyhow::{Context, Result}; -use const_oid::db::rfc5280::{ID_KP_CLIENT_AUTH, ID_KP_SERVER_AUTH}; -use const_oid::AssociatedOid; +use const_oid::{ + db::rfc5280::{ID_KP_CLIENT_AUTH, ID_KP_SERVER_AUTH}, + AssociatedOid, +}; use getrandom::getrandom; -use p256::ecdsa::DerSignature; -use p256::pkcs8::EncodePrivateKey; +use intel_tee_quote_verification_rs::tee_qv_get_collateral; +use p256::{ecdsa::DerSignature, pkcs8::EncodePrivateKey}; use pkcs8::der; use rustls::pki_types::PrivatePkcs8KeyDer; use sha2::{Digest, Sha256}; use signature::Signer; -use std::str::FromStr; -use std::time::Duration; +use std::{str::FromStr, time::Duration}; use tracing::debug; -use x509_cert::builder::{Builder, CertificateBuilder, Profile}; -use x509_cert::der::pem::LineEnding; -use x509_cert::der::{asn1::OctetString, Encode as _, EncodePem as _, Length}; -use x509_cert::ext::pkix::name::GeneralNames; -use x509_cert::ext::pkix::{ExtendedKeyUsage, SubjectAltName}; -use x509_cert::ext::{AsExtension, Extension}; -use x509_cert::name::{Name, RdnSequence}; -use x509_cert::serial_number::SerialNumber; -use x509_cert::spki::{ - DynSignatureAlgorithmIdentifier, EncodePublicKey, ObjectIdentifier, SignatureBitStringEncoding, - SubjectPublicKeyInfoOwned, +use x509_cert::{ + builder::{Builder, CertificateBuilder, Profile}, + der::{asn1::OctetString, pem::LineEnding, Encode as _, EncodePem as _, Length}, + ext::{ + pkix::{name::GeneralNames, ExtendedKeyUsage, SubjectAltName}, + AsExtension, Extension, + }, + name::{Name, RdnSequence}, + serial_number::SerialNumber, + spki::{ + DynSignatureAlgorithmIdentifier, EncodePublicKey, ObjectIdentifier, + SignatureBitStringEncoding, SubjectPublicKeyInfoOwned, + }, + time::Validity, + Certificate, }; -use x509_cert::time::Validity; -use x509_cert::Certificate; use zeroize::Zeroizing; /// The OID for the `gramine-ra-tls` quote extension @@ -148,7 +147,7 @@ pub fn make_self_signed_cert( let hash = Sha256::digest(verifying_key_der.as_bytes()); key_hash[..32].copy_from_slice(&hash); - let quote = get_quote(&key_hash)?; + let (_tee_type, quote) = get_quote(&key_hash)?; debug!("quote.len: {:?}", quote.len()); // Create a relative distinguished name. let rdns = RdnSequence::from_str(dn)?; @@ -185,6 +184,7 @@ pub fn make_self_signed_cert( .context("failed to add SubjectAltName")?; } + // FIXME: OID for tee_type builder .add_extension(&RaTlsQuoteExtension { quote: quote.to_vec(), @@ -234,7 +234,7 @@ where let hash = Sha256::digest(verifying_key_der.as_bytes()); key_hash[..32].copy_from_slice(&hash); - let quote = get_quote(&key_hash).context("Failed to get own quote")?; + let (_tee_type, quote) = get_quote(&key_hash).context("Failed to get own quote")?; // Create a relative distinguished name. let subject = Name::from_str(dn)?; @@ -269,6 +269,7 @@ where .context("failed to add SubjectAltName")?; } + // FIXME: oid according to tee_type builder .add_extension(&RaTlsQuoteExtension { quote: quote.to_vec(), diff --git a/crates/teepot/src/sgx/error.rs b/crates/teepot/src/sgx/error.rs deleted file mode 100644 index 492a42a..0000000 --- a/crates/teepot/src/sgx/error.rs +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs - -//! Intel SGX Enclave error wrapper - -use bytemuck::PodCastError; -use intel_tee_quote_verification_rs::quote3_error_t; -use std::fmt::Formatter; - -/// Wrapper for the quote verification Error -#[derive(Copy, Clone)] -pub struct Quote3Error { - /// error message - pub msg: &'static str, - /// raw error code - pub inner: quote3_error_t, -} - -impl std::fmt::Display for Quote3Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {:?}", self.msg, self.inner) - } -} - -impl std::fmt::Debug for Quote3Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {:?}", self.msg, self.inner) - } -} - -impl std::error::Error for Quote3Error {} - -impl From for Quote3Error { - fn from(inner: quote3_error_t) -> Self { - Self { - msg: "Generic", - inner, - } - } -} - -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -pub enum QuoteFromError { - #[error(transparent)] - PodCastError(#[from] PodCastError), - - #[error("Quote version is invalid")] - InvalidVersion, -} diff --git a/crates/teepot/src/sgx/mod.rs b/crates/teepot/src/sgx/mod.rs index 2fc289b..9ae67c6 100644 --- a/crates/teepot/src/sgx/mod.rs +++ b/crates/teepot/src/sgx/mod.rs @@ -5,24 +5,18 @@ //! Intel SGX Enclave report structures. -pub mod error; pub mod sign; pub mod tcblevel; -use bytemuck::{cast_slice, try_from_bytes, AnyBitPattern, PodCastError}; -use intel_tee_quote_verification_rs::{ - quote3_error_t, sgx_ql_qv_supplemental_t, tee_get_supplemental_data_version_and_size, - tee_supp_data_descriptor_t, tee_verify_quote, -}; -use std::ffi::CStr; -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::mem; -use tracing::{trace, warn}; - -use crate::quote::GetQuoteError; -pub use error::{Quote3Error, QuoteFromError}; +use crate::quote::error::QuoteContext; +pub use crate::quote::error::QuoteError; +use bytemuck::{try_from_bytes, AnyBitPattern, PodCastError}; pub use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; +use std::{ + fs::OpenOptions, + io::{Read, Write}, + mem, +}; pub use tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; /// Structure of a quote @@ -43,13 +37,13 @@ pub struct Quote { impl Quote { /// Creates a quote from a byte slice - pub fn try_from_bytes(bytes: &[u8]) -> Result<&Self, QuoteFromError> { + pub fn try_from_bytes(bytes: &[u8]) -> Result<&Self, QuoteError> { if bytes.len() < mem::size_of::() { return Err(PodCastError::SizeMismatch.into()); } let this: &Self = try_from_bytes(&bytes[..mem::size_of::()])?; if this.version() != 3 { - return Err(QuoteFromError::InvalidVersion); + return Err(QuoteError::InvalidVersion); } Ok(this) } @@ -98,152 +92,26 @@ pub struct ReportBody { pub reportdata: [u8; 64], } -/// The result of the quote verification -pub struct QuoteVerificationResult<'a> { - /// the raw result - pub result: sgx_ql_qv_result_t, - /// indicates if the collateral is expired - pub collateral_expired: bool, - /// the earliest expiration date of the collateral - pub earliest_expiration_date: i64, - /// Date of the TCB level - pub tcb_level_date_tag: i64, - /// the advisory string - pub advisories: Vec, - /// the quote - pub quote: &'a Quote, -} - -/// Verifies a quote with optional collateral material -pub fn verify_quote_with_collateral<'a>( - quote: &'a [u8], - collateral: Option<&Collateral>, - current_time: i64, -) -> Result, Quote3Error> { - let mut supp_data: mem::MaybeUninit = mem::MaybeUninit::zeroed(); - let mut supp_data_desc = tee_supp_data_descriptor_t { - major_version: 0, - data_size: 0, - p_data: supp_data.as_mut_ptr() as *mut u8, - }; - trace!("tee_get_supplemental_data_version_and_size"); - let (_, supp_size) = - tee_get_supplemental_data_version_and_size(quote).map_err(|e| Quote3Error { - msg: "tee_get_supplemental_data_version_and_size", - inner: e, - })?; - - trace!( - "tee_get_supplemental_data_version_and_size supp_size: {}", - supp_size - ); - - if supp_size == mem::size_of::() as u32 { - supp_data_desc.data_size = supp_size; - } else { - supp_data_desc.data_size = 0; - trace!( - "tee_get_supplemental_data_version_and_size supp_size: {}", - supp_size - ); - trace!( - "mem::size_of::(): {}", - mem::size_of::() - ); - warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you installed DCAP QVL and QvE from same release.") - } - - let p_supplemental_data = match supp_data_desc.data_size { - 0 => None, - _ => Some(&mut supp_data_desc), - }; - - let has_sup = p_supplemental_data.is_some(); - - trace!("tee_verify_quote"); - - let (collateral_expiration_status, result) = - tee_verify_quote(quote, collateral, current_time, None, p_supplemental_data).map_err( - |e| Quote3Error { - msg: "tee_verify_quote", - inner: e, - }, - )?; - - // check supplemental data if necessary - let (advisories, earliest_expiration_date, tcb_level_date_tag) = if has_sup { - unsafe { - let supp_data = supp_data.assume_init(); - // convert to valid UTF-8 string - let ads = CStr::from_bytes_until_nul(cast_slice(&supp_data.sa_list[..])) - .ok() - .and_then(|s| CStr::to_str(s).ok()) - .into_iter() - .flat_map(|s| s.split(',').map(str::trim).map(String::from)) - .filter(|s| !s.is_empty()) - .collect(); - ( - ads, - supp_data.earliest_expiration_date, - supp_data.tcb_level_date_tag, - ) - } - } else { - (vec![], 0, 0) - }; - - let quote = Quote::try_from_bytes(quote).map_err(|_| Quote3Error { - msg: "Quote::try_from_bytes", - inner: quote3_error_t::SGX_QL_QUOTE_FORMAT_UNSUPPORTED, - })?; - - let res = QuoteVerificationResult { - collateral_expired: collateral_expiration_status != 0, - earliest_expiration_date, - tcb_level_date_tag, - result, - quote, - advisories, - }; - - Ok(res) -} - /// Get the attestation report in a Gramine enclave -pub fn sgx_gramine_get_quote(report_data: &[u8; 64]) -> Result, GetQuoteError> { +pub fn sgx_gramine_get_quote(report_data: &[u8; 64]) -> Result, QuoteError> { let mut file = OpenOptions::new() .write(true) .open("/dev/attestation/user_report_data") - .map_err(|e| GetQuoteError { - msg: "Failed to open `/dev/attestation/user_report_data`".into(), - source: e, - })?; + .context("opening `/dev/attestation/user_report_data`")?; - file.write(report_data).map_err(|e| GetQuoteError { - msg: "Failed to write `/dev/attestation/user_report_data`".into(), - source: e, - })?; + file.write(report_data) + .context("writing `/dev/attestation/user_report_data`")?; drop(file); let mut file = OpenOptions::new() .read(true) .open("/dev/attestation/quote") - .map_err(|e| GetQuoteError { - msg: "Failed to open `/dev/attestation/quote`".into(), - source: e, - })?; + .context("opening `/dev/attestation/quote`")?; let mut quote = Vec::new(); - file.read_to_end(&mut quote).map_err(|e| GetQuoteError { - msg: "Failed to read `/dev/attestation/quote`".into(), - source: e, - })?; + file.read_to_end(&mut quote) + .context("reading `/dev/attestation/quote`")?; + Ok(quote.into_boxed_slice()) } - -/// Wrapper func for error -/// TODO: move to intel_tee_quote_verification_rs -pub fn tee_qv_get_collateral(quote: &[u8]) -> Result { - intel_tee_quote_verification_rs::tee_qv_get_collateral(quote).map_err(Into::into) -} diff --git a/crates/teepot/src/tdx/mod.rs b/crates/teepot/src/tdx/mod.rs new file mode 100644 index 0000000..37c03de --- /dev/null +++ b/crates/teepot/src/tdx/mod.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2024 Matter Labs + +//! Intel TDX helper functions. + +pub use crate::sgx::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; +use crate::sgx::QuoteError; +pub use intel_tee_quote_verification_rs::Collateral; +use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; + +/// Get a TDX quote +pub fn tgx_get_quote(report_data_bytes: &[u8; 64]) -> Result, QuoteError> { + let mut tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; + tdx_report_data.d.copy_from_slice(report_data_bytes); + + let (error, quote) = tdx_att_get_quote(Some(&tdx_report_data), None, None, 0); + + if error == tdx_attest_error_t::TDX_ATTEST_SUCCESS { + if let Some(quote) = quote { + Ok(quote.into()) + } else { + Err(QuoteError::TdxAttGetQuote { + msg: "tdx_att_get_quote: No quote returned".into(), + inner: error, + }) + } + } else { + Err(error.into()) + } +} diff --git a/crates/teepot/tests/sgx_quote_verification.rs b/crates/teepot/tests/sgx_quote_verification.rs index 4f04d2f..27a3d41 100644 --- a/crates/teepot/tests/sgx_quote_verification.rs +++ b/crates/teepot/tests/sgx_quote_verification.rs @@ -2,14 +2,15 @@ // Copyright (c) 2024 Matter Labs mod sgx { - use anyhow::Result; + use anyhow::{Context, Result}; use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; use std::time::{Duration, UNIX_EPOCH}; - use teepot::sgx::{verify_quote_with_collateral, QuoteVerificationResult}; + use teepot::quote::{verify_quote_with_collateral, QuoteVerificationResult, Report}; + use tracing_test::traced_test; fn check_quote( quote: &[u8], - collateral: &Collateral, + collateral: Option<&Collateral>, current_time: i64, expected_mrsigner: &[u8], expected_reportdata: &[u8], @@ -22,7 +23,7 @@ mod sgx { quote, advisories, tcb_level_date_tag, - } = verify_quote_with_collateral(quote, Some(collateral), current_time).unwrap(); + } = verify_quote_with_collateral(quote, collateral, current_time)?; if collateral_expired || result != sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK { print!("Attestation failed: "); @@ -67,12 +68,16 @@ mod sgx { println!("tcb_level_date_tag: {:?}", tcb_level_date_tag); assert_eq!(expected_result, result); - let expected_reportdata = hex::encode(expected_reportdata); - let expected_mrsigner = hex::encode(expected_mrsigner); - let actual_reportdata = hex::encode("e.report_body.reportdata[..]); - let actual_mrsigner = hex::encode("e.report_body.mrsigner[..]); - assert_eq!(expected_mrsigner, actual_mrsigner); - assert_eq!(expected_reportdata, actual_reportdata); + + if let Report::SgxEnclave(report_body) = quote.report { + let expected_reportdata = hex::encode(expected_reportdata); + let expected_mrsigner = hex::encode(expected_mrsigner); + let actual_reportdata = hex::encode(&report_body.report_data[..]); + let actual_mrsigner = hex::encode(&report_body.mr_signer[..]); + assert_eq!(expected_mrsigner, actual_mrsigner); + assert_eq!(expected_reportdata, actual_reportdata); + } + Ok(()) } @@ -1132,7 +1137,7 @@ mod sgx { check_quote( "e, - &collateral, + Some(&collateral), current_time, &mrsigner, &report_data, @@ -2203,7 +2208,7 @@ mod sgx { check_quote( "e, - &collateral, + Some(&collateral), current_time, &mrsigner, &report_data, @@ -2560,17 +2565,17 @@ mod sgx { ]; let collateral = Collateral { - major_version: 1, - minor_version: 0, - tee_type: 0, - pck_crl_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), - root_ca_crl: "-----BEGIN X509 CRL-----\nMIIBITCByAIBATAKBggqhkjOPQQDAjBoMRowGAYDVQQDDBFJbnRlbCBTR1ggUm9v\ndCBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRh\nIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTIzMDQwMzEwMjI1MVoX\nDTI0MDQwMjEwMjI1MVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFCJlDNZa\nnTSJ84O0lVK/UBs5JwasMAoGCCqGSM49BAMCA0gAMEUCIFFXfUfZ+6FXtl8etfRl\ne7xeVsyvc1oD8blj1wSAWrEYAiEAk5AV7BY25+r6X0JsHkAmR8ZzEytoUMq9aM72\nutdoKgM=\n-----END X509 CRL-----\n\0".as_bytes().into(), - pck_crl: "-----BEGIN X509 CRL-----\nMIIKYTCCCggCAQEwCgYIKoZIzj0EAwIwcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBD\nSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTIzMDUx\nMzIxMDAwM1oXDTIzMDYxMjIxMDAwM1owggk0MDMCFG/DTlAj5yiSNDXWGqS4PGGB\nZq01Fw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAO+ubpcV/KE7h+Mz\n6CYe1tmQqSatFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAP1ghkhi\nnLpzB4tNSS9LPqdBrQjNFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIV\nAIr5JBhOHVr93XPD1joS9ei1c35WFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMK\nAQEwNAIVALEleXjPqczdB1mr+MXKcvrjp4qbFw0yMzA1MTMyMTAwMDNaMAwwCgYD\nVR0VBAMKAQEwMwIUdP6mFKlyvg4oQ/IFmDWBHthy+bMXDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATA0AhUA+cTvVrOrSNV34Qi67fS/iAFCFLkXDTIzMDUxMzIx\nMDAwM1owDDAKBgNVHRUEAwoBATAzAhQHHeB3j55fxPKHjzDWsHyaMOazCxcNMjMw\nNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQDN4kJPlyzqlP8jmTf02AwlAp3W\nCxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFGwzGeUQm2RQfTzxEyzg\nA0nvUnMZFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAN8I11a2anSX\n9DtbtYraBNP096k3Fw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUKK9I\nW2z2fkCaOdXLWu5FmPeo+nsXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATA0\nAhUA+4strsCSytqKqbxP8vHCDQNGZowXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUE\nAwoBATA0AhUAzUhQrFK9zGmmpvBYyLxXu9C1+GQXDTIzMDUxMzIxMDAwM1owDDAK\nBgNVHRUEAwoBATA0AhUAmU3TZm9SdfuAX5XdAr1QyyZ52K0XDTIzMDUxMzIxMDAw\nM1owDDAKBgNVHRUEAwoBATAzAhQHAhNpACUidNkDXu31RXRi+tDvTBcNMjMwNTEz\nMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFGHyv3Pjm04EqifYAb1z0kMZtb+AFw0y\nMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUOZK+hRuWkC7/OJWebC7/GwZR\npLUXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhRjnxOaUED9z/GR6KT7\nG/CG7WA5cRcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCVnVM/kknc\nHlE1RM3IML8Zt/HzARcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFA/a\nQ6ALaOp5t8LerqwLSYvfsq+QFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEw\nNAIVAJ1ndTuB5HCQrqdj++xMRUm825kzFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0V\nBAMKAQEwMwIUNL+7eh2cVoFH4Ri2FPe3btPvaN8XDTIzMDUxMzIxMDAwM1owDDAK\nBgNVHRUEAwoBATA0AhUAhdPJOBt3p+BNEZyeWtZ0n/P/q4cXDTIzMDUxMzIxMDAw\nM1owDDAKBgNVHRUEAwoBATA0AhUAk4h8pEEeepI70f7SgZspSfIBtbQXDTIzMDUx\nMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhQkmNxig5MJlv2L8jo3rL4mo77UVxcN\nMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCKZvGnSUiGZ2icw5A6xUxm\nK3EucxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCvwTYQvdNst5hd\nEGSBqIDToB/aBxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQDv4Ess\nM9A2qslspnO/HppHtk1cuxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQC\nFQCD2ayNi7UJ0cbICa1xLoQwVZ7X8xcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQD\nCgEBMDMCFHkx/VC1Bxwbv8W3tt7YtFudi4UpFw0yMzA1MTMyMTAwMDNaMAwwCgYD\nVR0VBAMKAQEwMwIUH6IOKXC95dV/e43fgzlITh8dCCMXDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATAzAhQeh7LDsy2NI+QRzvNBl7la8Mit9RcNMjMwNTEzMjEw\nMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCa/S7pCkc1UKFn2ZaRFDfHUC0fCRcNMjMw\nNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFESBsPEXKKE7aW0+qcdwoLFexY3a\nFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAKeFn1eYLvDmfTe8jvLv\nWsg1/xqpFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUeuN3SKn5EvTG\nO6erB8WTzh0dEYEXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhQTiEsz\nJpk4wZWqFw/KddoXdTjfCxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMC\nFCw8xv6SedsVFtXOOfKomM2loXXhFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMK\nAQEwMwIUcXlIaHUJI0vpeeS33ObzG+9ktowXDTIzMDUxMzIxMDAwM1owDDAKBgNV\nHRUEAwoBATA0AhUAnXbvLDnBNuhli25zlrHXRFonYx8XDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATA0AhUAw+Al/KmV829ZtIRnk54+NOY2Gm8XDTIzMDUxMzIx\nMDAwM1owDDAKBgNVHRUEAwoBATA0AhUAjF9rMlfaBbF0KeLmG6ll1nMwYGoXDTIz\nMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATA0AhUAoXxRci7B4MMnj+i98FIFnL7E\n5kgXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQEw\nHwYDVR0jBBgwFoAUlW9dzb0b4elAScnU9DPOAVcL3lQwCgYIKoZIzj0EAwIDRwAw\nRAIgFCcExhc9muZCJybEgaDtgH1ZF5s739IHTjXl/JZTDR4CIG5WeLcFCg2nZozP\n5NqC0+MecmYxPN0eubPbpzhsF28z\n-----END X509 CRL-----\n\0".as_bytes().into(), - tcb_info_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0cAMEQCIB9C8wOAN/ImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj\nftbrNGsGU8YH211dRiYNoPPu19Zp/ze8JmhujB0oBw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), - tcb_info: "{\"tcbInfo\":{\"id\":\"SGX\",\"version\":3,\"issueDate\":\"2023-05-15T14:08:11Z\",\"nextUpdate\":\"2023-06-14T14:08:11Z\",\"fmspc\":\"00606a000000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":15,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":11,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":11,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":1},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":11,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":11,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":9,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":1},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2022-08-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":9,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2022-08-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]}]},\"signature\":\"5fee75684718bcb9191312cd3bf47096a4068f450d2ec9e05b8cd5a3a7cb61b292612a708c4c5a304836c82c3a7191447e3ba691e59287cc9c8943e821734d41\"}\0".as_bytes().into(), - qe_identity_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0cAMEQCIB9C8wOAN/ImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj\nftbrNGsGU8YH211dRiYNoPPu19Zp/ze8JmhujB0oBw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), - qe_identity: "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2023-05-15T14:48:40Z\",\"nextUpdate\":\"2023-06-14T14:48:40Z\",\"tcbEvaluationDataNumber\":15,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00202\",\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]}]},\"signature\":\"97ff8957975b40aa51a17765d734363b8cb7557e6657b04f63b67c05f2886be1b7cc14b9c1b889e03b85866e277a102eb9fb85029b7008b41754cdba014a5a8c\"}\0".as_bytes().into(), - }; + major_version: 1, + minor_version: 0, + tee_type: 0, + pck_crl_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), + root_ca_crl: "-----BEGIN X509 CRL-----\nMIIBITCByAIBATAKBggqhkjOPQQDAjBoMRowGAYDVQQDDBFJbnRlbCBTR1ggUm9v\ndCBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRh\nIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTIzMDQwMzEwMjI1MVoX\nDTI0MDQwMjEwMjI1MVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFCJlDNZa\nnTSJ84O0lVK/UBs5JwasMAoGCCqGSM49BAMCA0gAMEUCIFFXfUfZ+6FXtl8etfRl\ne7xeVsyvc1oD8blj1wSAWrEYAiEAk5AV7BY25+r6X0JsHkAmR8ZzEytoUMq9aM72\nutdoKgM=\n-----END X509 CRL-----\n\0".as_bytes().into(), + pck_crl: "-----BEGIN X509 CRL-----\nMIIKYTCCCggCAQEwCgYIKoZIzj0EAwIwcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBD\nSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTIzMDUx\nMzIxMDAwM1oXDTIzMDYxMjIxMDAwM1owggk0MDMCFG/DTlAj5yiSNDXWGqS4PGGB\nZq01Fw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAO+ubpcV/KE7h+Mz\n6CYe1tmQqSatFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAP1ghkhi\nnLpzB4tNSS9LPqdBrQjNFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIV\nAIr5JBhOHVr93XPD1joS9ei1c35WFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMK\nAQEwNAIVALEleXjPqczdB1mr+MXKcvrjp4qbFw0yMzA1MTMyMTAwMDNaMAwwCgYD\nVR0VBAMKAQEwMwIUdP6mFKlyvg4oQ/IFmDWBHthy+bMXDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATA0AhUA+cTvVrOrSNV34Qi67fS/iAFCFLkXDTIzMDUxMzIx\nMDAwM1owDDAKBgNVHRUEAwoBATAzAhQHHeB3j55fxPKHjzDWsHyaMOazCxcNMjMw\nNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQDN4kJPlyzqlP8jmTf02AwlAp3W\nCxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFGwzGeUQm2RQfTzxEyzg\nA0nvUnMZFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAN8I11a2anSX\n9DtbtYraBNP096k3Fw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUKK9I\nW2z2fkCaOdXLWu5FmPeo+nsXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATA0\nAhUA+4strsCSytqKqbxP8vHCDQNGZowXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUE\nAwoBATA0AhUAzUhQrFK9zGmmpvBYyLxXu9C1+GQXDTIzMDUxMzIxMDAwM1owDDAK\nBgNVHRUEAwoBATA0AhUAmU3TZm9SdfuAX5XdAr1QyyZ52K0XDTIzMDUxMzIxMDAw\nM1owDDAKBgNVHRUEAwoBATAzAhQHAhNpACUidNkDXu31RXRi+tDvTBcNMjMwNTEz\nMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFGHyv3Pjm04EqifYAb1z0kMZtb+AFw0y\nMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUOZK+hRuWkC7/OJWebC7/GwZR\npLUXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhRjnxOaUED9z/GR6KT7\nG/CG7WA5cRcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCVnVM/kknc\nHlE1RM3IML8Zt/HzARcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFA/a\nQ6ALaOp5t8LerqwLSYvfsq+QFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEw\nNAIVAJ1ndTuB5HCQrqdj++xMRUm825kzFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0V\nBAMKAQEwMwIUNL+7eh2cVoFH4Ri2FPe3btPvaN8XDTIzMDUxMzIxMDAwM1owDDAK\nBgNVHRUEAwoBATA0AhUAhdPJOBt3p+BNEZyeWtZ0n/P/q4cXDTIzMDUxMzIxMDAw\nM1owDDAKBgNVHRUEAwoBATA0AhUAk4h8pEEeepI70f7SgZspSfIBtbQXDTIzMDUx\nMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhQkmNxig5MJlv2L8jo3rL4mo77UVxcN\nMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCKZvGnSUiGZ2icw5A6xUxm\nK3EucxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCvwTYQvdNst5hd\nEGSBqIDToB/aBxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQDv4Ess\nM9A2qslspnO/HppHtk1cuxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQC\nFQCD2ayNi7UJ0cbICa1xLoQwVZ7X8xcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQD\nCgEBMDMCFHkx/VC1Bxwbv8W3tt7YtFudi4UpFw0yMzA1MTMyMTAwMDNaMAwwCgYD\nVR0VBAMKAQEwMwIUH6IOKXC95dV/e43fgzlITh8dCCMXDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATAzAhQeh7LDsy2NI+QRzvNBl7la8Mit9RcNMjMwNTEzMjEw\nMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCa/S7pCkc1UKFn2ZaRFDfHUC0fCRcNMjMw\nNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFESBsPEXKKE7aW0+qcdwoLFexY3a\nFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAKeFn1eYLvDmfTe8jvLv\nWsg1/xqpFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUeuN3SKn5EvTG\nO6erB8WTzh0dEYEXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhQTiEsz\nJpk4wZWqFw/KddoXdTjfCxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMC\nFCw8xv6SedsVFtXOOfKomM2loXXhFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMK\nAQEwMwIUcXlIaHUJI0vpeeS33ObzG+9ktowXDTIzMDUxMzIxMDAwM1owDDAKBgNV\nHRUEAwoBATA0AhUAnXbvLDnBNuhli25zlrHXRFonYx8XDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATA0AhUAw+Al/KmV829ZtIRnk54+NOY2Gm8XDTIzMDUxMzIx\nMDAwM1owDDAKBgNVHRUEAwoBATA0AhUAjF9rMlfaBbF0KeLmG6ll1nMwYGoXDTIz\nMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATA0AhUAoXxRci7B4MMnj+i98FIFnL7E\n5kgXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQEw\nHwYDVR0jBBgwFoAUlW9dzb0b4elAScnU9DPOAVcL3lQwCgYIKoZIzj0EAwIDRwAw\nRAIgFCcExhc9muZCJybEgaDtgH1ZF5s739IHTjXl/JZTDR4CIG5WeLcFCg2nZozP\n5NqC0+MecmYxPN0eubPbpzhsF28z\n-----END X509 CRL-----\n\0".as_bytes().into(), + tcb_info_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0cAMEQCIB9C8wOAN/ImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj\nftbrNGsGU8YH211dRiYNoPPu19Zp/ze8JmhujB0oBw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), + tcb_info: "{\"tcbInfo\":{\"id\":\"SGX\",\"version\":3,\"issueDate\":\"2023-05-15T14:08:11Z\",\"nextUpdate\":\"2023-06-14T14:08:11Z\",\"fmspc\":\"00606a000000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":15,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":11,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":11,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":1},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":11,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":11,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":9,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":1},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2022-08-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":9,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2022-08-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]}]},\"signature\":\"5fee75684718bcb9191312cd3bf47096a4068f450d2ec9e05b8cd5a3a7cb61b292612a708c4c5a304836c82c3a7191447e3ba691e59287cc9c8943e821734d41\"}\0".as_bytes().into(), + qe_identity_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0cAMEQCIB9C8wOAN/ImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj\nftbrNGsGU8YH211dRiYNoPPu19Zp/ze8JmhujB0oBw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), + qe_identity: "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2023-05-15T14:48:40Z\",\"nextUpdate\":\"2023-06-14T14:48:40Z\",\"tcbEvaluationDataNumber\":15,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00202\",\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]}]},\"signature\":\"97ff8957975b40aa51a17765d734363b8cb7557e6657b04f63b67c05f2886be1b7cc14b9c1b889e03b85866e277a102eb9fb85029b7008b41754cdba014a5a8c\"}\0".as_bytes().into(), + }; let current_time = 1684165303; @@ -2586,7 +2591,7 @@ mod sgx { check_quote( "e, - &collateral, + Some(&collateral), current_time, &mrsigner, &report_data, @@ -3669,7 +3674,7 @@ mod sgx { check_quote( "e, - &collateral, + Some(&collateral), current_time, &mrsigner, &report_data, @@ -3677,4 +3682,1133 @@ mod sgx { ) .unwrap(); } + + #[tokio::test] + #[traced_test] + async fn tdx_1() -> Result<()> { + let quote = [ + 4, 0, 2, 0, 129, 0, 0, 0, 0, 0, 0, 0, 147, 154, 114, 51, 247, 156, 76, 169, 148, 10, + 13, 179, 149, 127, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 112, 245, 193, 194, 193, 97, 11, 242, + 221, 173, 52, 138, 136, 235, 246, 165, 80, 37, 110, 148, 158, 82, 18, 44, 116, 61, 201, + 124, 222, 80, 204, 175, 173, 47, 197, 146, 125, 21, 15, 48, 127, 186, 59, 140, 162, 24, + 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 0, 0, 0, 0, 231, 0, 6, 0, 0, 0, 0, 0, 93, 86, 8, 14, 185, 239, 140, 224, + 187, 175, 107, 220, 218, 222, 235, 6, 231, 197, 176, 164, 209, 236, 22, 190, 134, 138, + 133, 169, 83, 186, 190, 12, 94, 84, 208, 28, 142, 5, 10, 84, 254, 28, 160, 120, 55, 37, + 48, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 66, 22, 233, 37, 247, 150, 244, 226, 130, 207, 166, 231, 45, 76, 119, 168, 5, 96, + 152, 122, 250, 41, 21, 90, 97, 253, 195, 58, 219, 128, 234, 176, 212, 17, 42, 189, 82, + 56, 126, 94, 37, 166, 13, 238, 251, 138, 82, 135, 117, 24, 106, 53, 86, 81, 215, 130, + 41, 226, 43, 72, 182, 103, 79, 0, 108, 212, 45, 139, 179, 112, 234, 46, 145, 248, 100, + 217, 148, 78, 7, 193, 13, 107, 37, 15, 181, 32, 72, 204, 252, 93, 110, 234, 107, 135, + 143, 164, 209, 17, 30, 60, 72, 25, 158, 84, 78, 146, 66, 178, 218, 227, 55, 134, 247, + 30, 251, 51, 88, 64, 181, 222, 201, 202, 60, 114, 188, 65, 7, 6, 17, 253, 30, 60, 185, + 130, 97, 201, 148, 120, 72, 216, 131, 106, 163, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 16, 0, 0, 173, 106, 32, 109, 219, 200, 128, + 152, 193, 7, 155, 122, 125, 105, 155, 215, 213, 138, 170, 109, 16, 164, 39, 124, 85, + 23, 81, 166, 93, 155, 21, 180, 75, 204, 181, 76, 63, 176, 74, 232, 187, 105, 12, 6, + 252, 251, 184, 232, 245, 64, 217, 15, 193, 251, 48, 39, 120, 210, 6, 165, 79, 192, 101, + 165, 146, 8, 244, 170, 53, 52, 105, 26, 27, 111, 7, 237, 192, 22, 93, 124, 74, 31, 173, + 205, 119, 80, 167, 54, 215, 90, 6, 0, 234, 108, 253, 234, 29, 165, 67, 157, 15, 111, + 174, 243, 248, 207, 172, 69, 217, 220, 251, 85, 85, 184, 153, 126, 192, 253, 143, 167, + 105, 23, 73, 81, 110, 247, 117, 96, 6, 0, 69, 16, 0, 0, 7, 7, 255, 27, 3, 255, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 229, + 163, 167, 181, 216, 48, 194, 149, 59, 152, 83, 76, 108, 89, 163, 163, 79, 220, 52, 233, + 51, 247, 245, 137, 143, 10, 133, 207, 8, 132, 107, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 158, 42, 124, + 111, 148, 143, 23, 71, 78, 52, 167, 252, 67, 237, 3, 15, 124, 21, 99, 241, 186, 189, + 223, 99, 64, 200, 46, 14, 84, 168, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, + 251, 252, 166, 90, 191, 174, 148, 208, 101, 246, 199, 76, 45, 11, 45, 3, 58, 105, 166, + 8, 54, 250, 244, 81, 54, 176, 166, 141, 248, 70, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 2, 162, 97, 38, 185, + 42, 4, 183, 177, 168, 67, 207, 162, 237, 225, 183, 89, 224, 19, 4, 86, 108, 202, 197, + 108, 151, 18, 255, 142, 246, 86, 143, 11, 27, 240, 45, 133, 132, 182, 25, 177, 123, + 186, 98, 132, 113, 180, 86, 63, 3, 10, 8, 152, 75, 152, 211, 9, 149, 235, 147, 51, 209, + 203, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 93, 14, 0, 0, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 69, 56, + 68, 67, 67, 66, 74, 97, 103, 65, 119, 73, 66, 65, 103, 73, 85, 89, 71, 99, 82, 76, 89, + 53, 43, 114, 99, 119, 67, 65, 88, 84, 72, 48, 71, 109, 83, 71, 98, 119, 115, 104, 113, + 119, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 99, + 68, 69, 105, 77, 67, 65, 71, 65, 49, 85, 69, 65, 119, 119, 90, 83, 87, 53, 48, 90, 87, + 119, 103, 85, 48, 100, 89, 73, 70, 66, 68, 83, 121, 66, 81, 98, 71, 70, 48, 90, 109, + 57, 121, 98, 83, 66, 68, 81, 84, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 67, 103, 119, + 82, 10, 83, 87, 53, 48, 90, 87, 119, 103, 81, 50, 57, 121, 99, 71, 57, 121, 89, 88, 82, + 112, 98, 50, 52, 120, 70, 68, 65, 83, 66, 103, 78, 86, 66, 65, 99, 77, 67, 49, 78, 104, + 98, 110, 82, 104, 73, 69, 78, 115, 89, 88, 74, 104, 77, 81, 115, 119, 67, 81, 89, 68, + 86, 81, 81, 73, 10, 68, 65, 74, 68, 81, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, + 66, 104, 77, 67, 86, 86, 77, 119, 72, 104, 99, 78, 77, 106, 81, 120, 77, 106, 65, 49, + 77, 68, 65, 120, 79, 68, 85, 122, 87, 104, 99, 78, 77, 122, 69, 120, 77, 106, 65, 49, + 77, 68, 65, 120, 79, 68, 85, 122, 10, 87, 106, 66, 119, 77, 83, 73, 119, 73, 65, 89, + 68, 86, 81, 81, 68, 68, 66, 108, 74, 98, 110, 82, 108, 98, 67, 66, 84, 82, 49, 103, + 103, 85, 69, 78, 76, 73, 69, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, + 108, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 10, 68, 66, 70, 74, 98, 110, 82, + 108, 98, 67, 66, 68, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, + 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, + 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 10, 66, 65, + 103, 77, 65, 107, 78, 66, 77, 81, 115, 119, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, + 74, 86, 85, 122, 66, 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, + 71, 67, 67, 113, 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 79, 122, 117, + 10, 122, 56, 66, 78, 78, 88, 71, 102, 48, 48, 85, 66, 100, 53, 52, 90, 97, 120, 85, + 113, 79, 110, 79, 81, 103, 53, 81, 109, 51, 54, 115, 105, 49, 74, 111, 112, 97, 110, + 88, 114, 80, 112, 117, 78, 86, 102, 73, 98, 50, 77, 114, 54, 104, 75, 68, 106, 107, 75, + 107, 100, 114, 82, 81, 103, 10, 55, 101, 117, 57, 84, 73, 76, 86, 57, 53, 82, 43, 55, + 80, 118, 90, 102, 120, 101, 106, 103, 103, 77, 77, 77, 73, 73, 68, 67, 68, 65, 102, 66, + 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 83, 86, 98, 49, 51, 78, 118, 82, + 118, 104, 54, 85, 66, 74, 121, 100, 84, 48, 10, 77, 56, 52, 66, 86, 119, 118, 101, 86, + 68, 66, 114, 66, 103, 78, 86, 72, 82, 56, 69, 90, 68, 66, 105, 77, 71, 67, 103, 88, + 113, 66, 99, 104, 108, 112, 111, 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 70, 119, + 97, 83, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 10, 100, 109, 108, + 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, 119, 117, 89, 50, 57, 116, 76, 51, 78, + 110, 101, 67, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 97, 87, 57, + 117, 76, 51, 89, 48, 76, 51, 66, 106, 97, 50, 78, 121, 98, 68, 57, 106, 89, 84, 49, + 119, 10, 98, 71, 70, 48, 90, 109, 57, 121, 98, 83, 90, 108, 98, 109, 78, 118, 90, 71, + 108, 117, 90, 122, 49, 107, 90, 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, + 89, 69, 70, 74, 97, 84, 121, 67, 67, 48, 49, 71, 76, 117, 52, 105, 65, 104, 100, 119, + 98, 111, 115, 84, 105, 112, 10, 75, 119, 90, 87, 77, 65, 52, 71, 65, 49, 85, 100, 68, + 119, 69, 66, 47, 119, 81, 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, + 82, 77, 66, 65, 102, 56, 69, 65, 106, 65, 65, 77, 73, 73, 67, 79, 81, 89, 74, 75, 111, + 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 10, 66, 73, 73, 67, 75, 106, 67, 67, 65, + 105, 89, 119, 72, 103, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, + 81, 81, 81, 78, 107, 122, 43, 57, 54, 111, 121, 99, 107, 71, 79, 47, 106, 70, 47, 56, + 72, 90, 56, 101, 84, 67, 67, 65, 87, 77, 71, 67, 105, 113, 71, 10, 83, 73, 98, 52, 84, + 81, 69, 78, 65, 81, 73, 119, 103, 103, 70, 84, 77, 66, 65, 71, 67, 121, 113, 71, 83, + 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 66, 65, 103, 69, 72, 77, 66, 65, 71, 67, 121, + 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 67, 65, 103, 69, 72, 10, 77, 66, + 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 68, 65, 103, 69, + 67, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 69, + 65, 103, 69, 67, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 10, + 65, 81, 73, 70, 65, 103, 69, 68, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, + 81, 69, 78, 65, 81, 73, 71, 65, 103, 69, 66, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, + 98, 52, 84, 81, 69, 78, 65, 81, 73, 72, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, + 71, 10, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 73, 65, 103, 69, 68, 77, 66, 65, + 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 74, 65, 103, 69, 65, + 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 75, 65, + 103, 69, 65, 10, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, + 81, 73, 76, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, + 69, 78, 65, 81, 73, 77, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, + 52, 84, 81, 69, 78, 10, 65, 81, 73, 78, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, + 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 79, 65, 103, 69, 65, 77, 66, 65, 71, + 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 80, 65, 103, 69, 65, 77, + 66, 65, 71, 67, 121, 113, 71, 10, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 81, 65, + 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, + 73, 82, 65, 103, 69, 76, 77, 66, 56, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, + 78, 65, 81, 73, 83, 66, 66, 65, 72, 10, 66, 119, 73, 67, 65, 119, 69, 65, 65, 119, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 77, 66, 65, 71, 67, 105, 113, 71, 83, 73, 98, 52, + 84, 81, 69, 78, 65, 81, 77, 69, 65, 103, 65, 65, 77, 66, 81, 71, 67, 105, 113, 71, 83, + 73, 98, 52, 84, 81, 69, 78, 65, 81, 81, 69, 10, 66, 103, 67, 65, 98, 119, 85, 65, 65, + 68, 65, 80, 66, 103, 111, 113, 104, 107, 105, 71, 43, 69, 48, 66, 68, 81, 69, 70, 67, + 103, 69, 66, 77, 66, 52, 71, 67, 105, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, + 89, 69, 69, 73, 89, 81, 78, 89, 69, 43, 108, 116, 89, 109, 10, 76, 85, 69, 101, 65, 74, + 83, 109, 67, 116, 65, 119, 82, 65, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, + 48, 66, 66, 122, 65, 50, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, + 78, 65, 81, 99, 66, 65, 81, 72, 47, 77, 66, 65, 71, 67, 121, 113, 71, 10, 83, 73, 98, + 52, 84, 81, 69, 78, 65, 81, 99, 67, 65, 81, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, + 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 99, 68, 65, 81, 72, 47, 77, 65, 111, 71, 67, + 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 65, 48, 103, 65, 77, 69, 85, 67, 10, 73, + 65, 74, 88, 103, 116, 73, 109, 88, 71, 51, 97, 104, 113, 81, 82, 122, 48, 90, 66, 43, + 66, 83, 107, 97, 70, 43, 88, 87, 110, 110, 119, 90, 49, 88, 102, 110, 106, 67, 79, 102, + 54, 115, 87, 65, 105, 69, 65, 115, 76, 57, 52, 110, 57, 53, 55, 86, 89, 65, 47, 118, + 109, 77, 119, 10, 103, 65, 56, 104, 78, 115, 112, 97, 66, 71, 80, 106, 99, 105, 50, 43, + 107, 104, 98, 120, 80, 112, 100, 43, 86, 100, 89, 61, 10, 45, 45, 45, 45, 45, 69, 78, + 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, + 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, + 45, 45, 10, 77, 73, 73, 67, 108, 106, 67, 67, 65, 106, 50, 103, 65, 119, 73, 66, 65, + 103, 73, 86, 65, 74, 86, 118, 88, 99, 50, 57, 71, 43, 72, 112, 81, 69, 110, 74, 49, 80, + 81, 122, 122, 103, 70, 88, 67, 57, 53, 85, 77, 65, 111, 71, 67, 67, 113, 71, 83, 77, + 52, 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, + 77, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 83, 98, 50, 57, + 48, 73, 69, 78, 66, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, + 98, 110, 82, 108, 98, 67, 66, 68, 10, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, + 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, + 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, + 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, + 81, 71, 69, 119, 74, 86, 85, 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, + 69, 120, 77, 68, 85, 119, 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, + 69, 120, 77, 68, 85, 119, 77, 84, 66, 97, 77, 72, 65, 120, 73, 106, 65, 103, 10, 66, + 103, 78, 86, 66, 65, 77, 77, 71, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, + 67, 66, 81, 81, 48, 115, 103, 85, 71, 120, 104, 100, 71, 90, 118, 99, 109, 48, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, + 71, 86, 115, 10, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, + 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, + 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, + 119, 67, 81, 48, 69, 120, 10, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 65, + 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, + 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 78, 83, + 66, 47, 55, 116, 50, 49, 108, 88, 83, 79, 10, 50, 67, 117, 122, 112, 120, 119, 55, 52, + 101, 74, 66, 55, 50, 69, 121, 68, 71, 103, 87, 53, 114, 88, 67, 116, 120, 50, 116, 86, + 84, 76, 113, 54, 104, 75, 107, 54, 122, 43, 85, 105, 82, 90, 67, 110, 113, 82, 55, 112, + 115, 79, 118, 103, 113, 70, 101, 83, 120, 108, 109, 84, 108, 74, 108, 10, 101, 84, 109, + 105, 50, 87, 89, 122, 51, 113, 79, 66, 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, + 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, + 105, 102, 79, 68, 116, 74, 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, + 10, 66, 103, 78, 86, 72, 82, 56, 69, 83, 122, 66, 74, 77, 69, 101, 103, 82, 97, 66, 68, + 104, 107, 70, 111, 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, + 112, 90, 109, 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, + 86, 107, 99, 50, 86, 121, 10, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, + 87, 119, 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, + 109, 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 108, 87, 57, 100, 10, 122, 98, 48, 98, 52, 101, 108, 65, + 83, 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 68, 103, 89, 68, 86, + 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, + 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 10, 65, 102, 56, 67, 65, 81, + 65, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 82, 119, + 65, 119, 82, 65, 73, 103, 88, 115, 86, 107, 105, 48, 119, 43, 105, 54, 86, 89, 71, 87, + 51, 85, 70, 47, 50, 50, 117, 97, 88, 101, 48, 89, 74, 68, 106, 49, 85, 101, 10, 110, + 65, 43, 84, 106, 68, 49, 97, 105, 53, 99, 67, 73, 67, 89, 98, 49, 83, 65, 109, 68, 53, + 120, 107, 102, 84, 86, 112, 118, 111, 52, 85, 111, 121, 105, 83, 89, 120, 114, 68, 87, + 76, 109, 85, 82, 52, 67, 73, 57, 78, 75, 121, 102, 80, 78, 43, 10, 45, 45, 45, 45, 45, + 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, + 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, + 45, 45, 45, 45, 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, + 66, 65, 103, 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, + 86, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, + 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, + 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, + 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, + 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, + 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, + 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, 66, + 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, + 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, 77, 84, 73, + 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, 97, 77, 66, 103, + 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, + 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, + 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, + 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, + 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, + 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, + 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, + 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, + 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, + 106, 47, 105, 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, + 82, 70, 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, + 106, 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, + 97, 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, + 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, + 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, + 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, + 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, + 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, 109, + 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, 116, 76, + 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, 69, 78, 66, 76, + 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, 70, 103, 81, 85, 73, + 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 10, 85, 114, 57, 81, + 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, + 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, + 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, + 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, + 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, + 117, 80, 82, 76, 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, + 84, 119, 103, 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, + 53, 111, 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, + 82, 81, 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, + 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + + let current_time = 1733406935; + + let collateral = Collateral { + major_version: 3, + minor_version: 0, + tee_type: 129, + pck_crl_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 108, 106, 67, 67, 65, 106, 50, 103, 65, + 119, 73, 66, 65, 103, 73, 86, 65, 74, 86, 118, 88, 99, 50, 57, 71, 43, 72, 112, 81, + 69, 110, 74, 49, 80, 81, 122, 122, 103, 70, 88, 67, 57, 53, 85, 77, 65, 111, 71, + 67, 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, 65, + 89, 66, 103, 78, 86, 66, 65, 77, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 70, + 78, 72, 87, 67, 66, 83, 98, 50, 57, 48, 73, 69, 78, 66, 77, 82, 111, 119, 71, 65, + 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 10, 98, + 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, + 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, + 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, + 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, 74, 86, 85, + 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, 69, 120, 77, 68, 85, 119, + 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, 69, 120, 77, 68, 85, + 119, 77, 84, 66, 97, 77, 72, 65, 120, 73, 106, 65, 103, 10, 66, 103, 78, 86, 66, + 65, 77, 77, 71, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 81, 81, + 48, 115, 103, 85, 71, 120, 104, 100, 71, 90, 118, 99, 109, 48, 103, 81, 48, 69, + 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, + 86, 115, 10, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, + 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, + 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, + 67, 65, 119, 67, 81, 48, 69, 120, 10, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, + 84, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, + 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, + 65, 69, 78, 83, 66, 47, 55, 116, 50, 49, 108, 88, 83, 79, 10, 50, 67, 117, 122, + 112, 120, 119, 55, 52, 101, 74, 66, 55, 50, 69, 121, 68, 71, 103, 87, 53, 114, 88, + 67, 116, 120, 50, 116, 86, 84, 76, 113, 54, 104, 75, 107, 54, 122, 43, 85, 105, 82, + 90, 67, 110, 113, 82, 55, 112, 115, 79, 118, 103, 113, 70, 101, 83, 120, 108, 109, + 84, 108, 74, 108, 10, 101, 84, 109, 105, 50, 87, 89, 122, 51, 113, 79, 66, 117, + 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, + 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, + 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 10, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, + 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, + 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, + 86, 121, 10, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, 119, 117, + 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, + 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, + 52, 69, 70, 103, 81, 85, 108, 87, 57, 100, 10, 122, 98, 48, 98, 52, 101, 108, 65, + 83, 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 68, 103, 89, 68, + 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, + 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 10, 65, 102, 56, + 67, 65, 81, 65, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, + 73, 68, 82, 119, 65, 119, 82, 65, 73, 103, 88, 115, 86, 107, 105, 48, 119, 43, 105, + 54, 86, 89, 71, 87, 51, 85, 70, 47, 50, 50, 117, 97, 88, 101, 48, 89, 74, 68, 106, + 49, 85, 101, 10, 110, 65, 43, 84, 106, 68, 49, 97, 105, 53, 99, 67, 73, 67, 89, 98, + 49, 83, 65, 109, 68, 53, 120, 107, 102, 84, 86, 112, 118, 111, 52, 85, 111, 121, + 105, 83, 89, 120, 114, 68, 87, 76, 109, 85, 82, 52, 67, 73, 57, 78, 75, 121, 102, + 80, 78, 43, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, + 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, + 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, + 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, 73, 85, 73, 109, 85, + 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, + 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, + 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 65, 119, + 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, + 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, + 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, 99, 109, + 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, + 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, + 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, 66, + 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, 77, + 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, 77, + 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, 97, + 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, + 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, + 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, + 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, 81, + 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, + 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, + 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, 108, + 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, + 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 67, + 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, 80, 87, 115, 67, 122, 97, + 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, 104, 87, 71, 106, 98, 110, + 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, 107, 68, 89, 89, 76, 48, + 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, 108, 84, 86, 89, 120, + 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, 117, 122, 67, 66, 117, + 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, 105, 90, + 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, 118, 49, 65, 98, + 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, 122, 66, 74, + 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, 99, 122, + 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, 108, + 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, 109, + 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, 116, + 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, 69, 78, + 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, 70, 103, + 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 10, + 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, 82, 48, + 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, 85, + 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, 81, 69, + 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 83, + 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, 67, + 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, 115, 87, 71, 102, 47, 89, + 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, 10, 65, 105, 69, 65, 52, + 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, 47, 115, 88, 54, 79, 57, + 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, 55, 99, 118, 113, 82, + 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, + 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + root_ca_crl: [ + 48, 130, 1, 34, 48, 129, 200, 2, 1, 1, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, + 48, 104, 49, 26, 48, 24, 6, 3, 85, 4, 3, 12, 17, 73, 110, 116, 101, 108, 32, 83, + 71, 88, 32, 82, 111, 111, 116, 32, 67, 65, 49, 26, 48, 24, 6, 3, 85, 4, 10, 12, 17, + 73, 110, 116, 101, 108, 32, 67, 111, 114, 112, 111, 114, 97, 116, 105, 111, 110, + 49, 20, 48, 18, 6, 3, 85, 4, 7, 12, 11, 83, 97, 110, 116, 97, 32, 67, 108, 97, 114, + 97, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 11, 48, 9, 6, 3, 85, 4, 6, + 19, 2, 85, 83, 23, 13, 50, 52, 48, 51, 50, 48, 49, 57, 49, 57, 51, 48, 90, 23, 13, + 50, 53, 48, 52, 48, 51, 49, 57, 49, 57, 51, 48, 90, 160, 47, 48, 45, 48, 10, 6, 3, + 85, 29, 20, 4, 3, 2, 1, 1, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 34, + 101, 12, 214, 90, 157, 52, 137, 243, 131, 180, 149, 82, 191, 80, 27, 57, 39, 6, + 172, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 73, 0, 48, 70, 2, 33, 0, 231, + 96, 111, 239, 45, 166, 135, 133, 160, 195, 155, 195, 74, 195, 68, 201, 226, 214, + 237, 75, 2, 35, 231, 154, 108, 98, 151, 212, 33, 183, 55, 132, 2, 33, 0, 252, 21, + 135, 174, 206, 66, 150, 213, 233, 55, 15, 214, 164, 68, 167, 45, 3, 197, 152, 203, + 33, 220, 129, 4, 197, 91, 18, 123, 118, 110, 168, 43, 0, + ] + .into(), + pck_crl: [ + 48, 130, 10, 98, 48, 130, 10, 8, 2, 1, 1, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, + 2, 48, 112, 49, 34, 48, 32, 6, 3, 85, 4, 3, 12, 25, 73, 110, 116, 101, 108, 32, 83, + 71, 88, 32, 80, 67, 75, 32, 80, 108, 97, 116, 102, 111, 114, 109, 32, 67, 65, 49, + 26, 48, 24, 6, 3, 85, 4, 10, 12, 17, 73, 110, 116, 101, 108, 32, 67, 111, 114, 112, + 111, 114, 97, 116, 105, 111, 110, 49, 20, 48, 18, 6, 3, 85, 4, 7, 12, 11, 83, 97, + 110, 116, 97, 32, 67, 108, 97, 114, 97, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, + 65, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 23, 13, 50, 52, 49, 49, 50, 56, + 49, 51, 50, 51, 48, 57, 90, 23, 13, 50, 52, 49, 50, 50, 56, 49, 51, 50, 51, 48, 57, + 90, 48, 130, 9, 52, 48, 51, 2, 20, 111, 195, 78, 80, 35, 231, 40, 146, 52, 53, 214, + 26, 164, 184, 60, 97, 129, 102, 173, 53, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, + 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, + 21, 0, 239, 174, 110, 151, 21, 252, 161, 59, 135, 227, 51, 232, 38, 30, 214, 217, + 144, 169, 38, 173, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 253, 96, 134, 72, + 98, 156, 186, 115, 7, 139, 77, 73, 47, 75, 62, 167, 65, 173, 8, 205, 23, 13, 50, + 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, + 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 138, 249, 36, 24, 78, 29, 90, 253, 221, 115, 195, + 214, 58, 18, 245, 232, 181, 115, 126, 86, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, + 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, + 21, 0, 177, 37, 121, 120, 207, 169, 204, 221, 7, 89, 171, 248, 197, 202, 114, 250, + 227, 167, 138, 155, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 116, 254, 166, 20, + 169, 114, 190, 14, 40, 67, 242, 5, 152, 53, 129, 30, 216, 114, 249, 179, 23, 13, + 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, + 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 249, 196, 239, 86, 179, 171, 72, 213, 119, + 225, 8, 186, 237, 244, 191, 136, 1, 66, 20, 185, 23, 13, 50, 52, 49, 49, 50, 56, + 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, + 51, 2, 20, 7, 29, 224, 119, 143, 158, 95, 196, 242, 135, 143, 48, 214, 176, 124, + 154, 48, 230, 179, 11, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, + 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 205, 226, 66, + 79, 151, 44, 234, 148, 255, 35, 153, 55, 244, 216, 12, 37, 2, 157, 214, 11, 23, 13, + 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, + 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 108, 51, 25, 229, 16, 155, 100, 80, 125, 60, + 241, 19, 44, 224, 3, 73, 239, 82, 115, 25, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, + 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, + 21, 0, 223, 8, 215, 86, 182, 106, 116, 151, 244, 59, 91, 181, 138, 218, 4, 211, + 244, 247, 169, 55, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 40, 175, 72, 91, 108, + 246, 126, 64, 154, 57, 213, 203, 90, 238, 69, 152, 247, 168, 250, 123, 23, 13, 50, + 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, + 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 251, 139, 45, 174, 192, 146, 202, 218, 138, 169, + 188, 79, 242, 241, 194, 13, 3, 70, 102, 140, 23, 13, 50, 52, 49, 49, 50, 56, 49, + 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, + 2, 21, 0, 205, 72, 80, 172, 82, 189, 204, 105, 166, 166, 240, 88, 200, 188, 87, + 187, 208, 181, 248, 100, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, + 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 153, 77, + 211, 102, 111, 82, 117, 251, 128, 95, 149, 221, 2, 189, 80, 203, 38, 121, 216, 173, + 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, + 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 7, 2, 19, 105, 0, 37, 34, 116, 217, 3, + 94, 237, 245, 69, 116, 98, 250, 208, 239, 76, 23, 13, 50, 52, 49, 49, 50, 56, 49, + 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, + 2, 20, 97, 242, 191, 115, 227, 155, 78, 4, 170, 39, 216, 1, 189, 115, 210, 67, 25, + 181, 191, 128, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, + 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 57, 146, 190, 133, 27, + 150, 144, 46, 255, 56, 149, 158, 108, 46, 255, 27, 6, 81, 164, 181, 23, 13, 50, 52, + 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 51, 2, 20, 99, 159, 19, 154, 80, 64, 253, 207, 241, 145, 232, 164, + 251, 27, 240, 134, 237, 96, 57, 113, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, + 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, + 149, 157, 83, 63, 146, 73, 220, 30, 81, 53, 68, 205, 200, 48, 191, 25, 183, 241, + 243, 1, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, + 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 15, 218, 67, 160, 11, 104, 234, + 121, 183, 194, 222, 174, 172, 11, 73, 139, 223, 178, 175, 144, 23, 13, 50, 52, 49, + 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, + 1, 1, 48, 52, 2, 21, 0, 157, 103, 117, 59, 129, 228, 112, 144, 174, 167, 99, 251, + 236, 76, 69, 73, 188, 219, 153, 51, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, + 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 52, + 191, 187, 122, 29, 156, 86, 129, 71, 225, 24, 182, 20, 247, 183, 110, 211, 239, + 104, 223, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, + 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 133, 211, 201, 56, 27, 119, + 167, 224, 77, 17, 156, 158, 90, 214, 116, 159, 243, 255, 171, 135, 23, 13, 50, 52, + 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 52, 2, 21, 0, 147, 136, 124, 164, 65, 30, 122, 146, 59, 209, 254, + 210, 129, 155, 41, 73, 242, 1, 181, 180, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, + 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, + 20, 36, 152, 220, 98, 131, 147, 9, 150, 253, 139, 242, 58, 55, 172, 190, 38, 163, + 190, 212, 87, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, + 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 138, 102, 241, 167, 73, + 72, 134, 103, 104, 156, 195, 144, 58, 197, 76, 102, 43, 113, 46, 115, 23, 13, 50, + 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, + 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 175, 193, 54, 16, 189, 211, 108, 183, 152, 93, + 16, 100, 129, 168, 128, 211, 160, 31, 218, 7, 23, 13, 50, 52, 49, 49, 50, 56, 49, + 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, + 2, 21, 0, 239, 224, 75, 44, 51, 208, 54, 170, 201, 108, 166, 115, 191, 30, 154, 71, + 182, 77, 92, 187, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 131, 217, 172, 141, + 139, 181, 9, 209, 198, 200, 9, 173, 113, 46, 132, 48, 85, 158, 215, 243, 23, 13, + 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, + 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 121, 49, 253, 80, 181, 7, 28, 27, 191, 197, 183, + 182, 222, 216, 180, 91, 157, 139, 133, 41, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, + 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, + 20, 31, 162, 14, 41, 112, 189, 229, 213, 127, 123, 141, 223, 131, 57, 72, 78, 31, + 29, 8, 35, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, + 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 30, 135, 178, 195, 179, 45, + 141, 35, 228, 17, 206, 243, 65, 151, 185, 90, 240, 200, 173, 245, 23, 13, 50, 52, + 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 52, 2, 21, 0, 154, 253, 46, 233, 10, 71, 53, 80, 161, 103, 217, 150, + 145, 20, 55, 199, 80, 45, 31, 9, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, + 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 68, + 129, 176, 241, 23, 40, 161, 59, 105, 109, 62, 169, 199, 112, 160, 177, 94, 197, + 141, 218, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, + 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 167, 133, 159, 87, 152, 46, + 240, 230, 125, 55, 188, 142, 242, 239, 90, 200, 53, 255, 26, 169, 23, 13, 50, 52, + 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 51, 2, 20, 122, 227, 119, 72, 169, 249, 18, 244, 198, 59, 167, 171, + 7, 197, 147, 206, 29, 29, 17, 129, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, + 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 19, + 136, 75, 51, 38, 153, 56, 193, 149, 170, 23, 15, 202, 117, 218, 23, 117, 56, 223, + 11, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, + 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 44, 60, 198, 254, 146, 121, 219, 21, + 22, 213, 206, 57, 242, 168, 152, 205, 165, 161, 117, 225, 23, 13, 50, 52, 49, 49, + 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, + 1, 48, 51, 2, 20, 113, 121, 72, 104, 117, 9, 35, 75, 233, 121, 228, 183, 220, 230, + 243, 27, 239, 100, 182, 140, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, + 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 157, + 118, 239, 44, 57, 193, 54, 232, 101, 139, 110, 115, 150, 177, 215, 68, 90, 39, 99, + 31, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, + 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 195, 224, 37, 252, 169, 149, 243, + 111, 89, 180, 132, 103, 147, 158, 62, 52, 230, 54, 26, 111, 23, 13, 50, 52, 49, 49, + 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, + 1, 48, 52, 2, 21, 0, 140, 95, 107, 50, 87, 218, 5, 177, 116, 41, 226, 230, 27, 169, + 101, 214, 115, 48, 96, 106, 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, + 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 161, 124, + 81, 114, 46, 193, 224, 195, 39, 143, 232, 189, 240, 82, 5, 156, 190, 196, 230, 72, + 23, 13, 50, 52, 49, 49, 50, 56, 49, 51, 50, 51, 48, 57, 90, 48, 12, 48, 10, 6, 3, + 85, 29, 21, 4, 3, 10, 1, 1, 160, 47, 48, 45, 48, 10, 6, 3, 85, 29, 20, 4, 3, 2, 1, + 1, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 149, 111, 93, 205, 189, 27, + 225, 233, 64, 73, 201, 212, 244, 51, 206, 1, 87, 11, 222, 84, 48, 10, 6, 8, 42, + 134, 72, 206, 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 32, 113, 129, 124, 253, 92, 251, + 24, 95, 180, 138, 106, 178, 57, 160, 79, 139, 90, 150, 233, 44, 243, 233, 219, 83, + 166, 120, 8, 167, 21, 168, 54, 112, 2, 33, 0, 241, 73, 163, 143, 77, 129, 88, 187, + 205, 46, 218, 183, 36, 140, 195, 164, 84, 101, 227, 217, 121, 192, 245, 25, 116, + 182, 208, 150, 186, 234, 175, 136, 0, + ] + .into(), + tcb_info_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + tcb_info: [ + 123, 34, 116, 99, 98, 73, 110, 102, 111, 34, 58, 123, 34, 105, 100, 34, 58, 34, 84, + 68, 88, 34, 44, 34, 118, 101, 114, 115, 105, 111, 110, 34, 58, 51, 44, 34, 105, + 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 52, 45, 49, 50, 45, + 48, 53, 84, 49, 50, 58, 49, 54, 58, 53, 50, 90, 34, 44, 34, 110, 101, 120, 116, 85, + 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, 53, 45, 48, 49, 45, 48, 52, 84, 49, + 50, 58, 49, 54, 58, 53, 50, 90, 34, 44, 34, 102, 109, 115, 112, 99, 34, 58, 34, 48, + 48, 56, 48, 54, 70, 48, 53, 48, 48, 48, 48, 34, 44, 34, 112, 99, 101, 73, 100, 34, + 58, 34, 48, 48, 48, 48, 34, 44, 34, 116, 99, 98, 84, 121, 112, 101, 34, 58, 48, 44, + 34, 116, 99, 98, 69, 118, 97, 108, 117, 97, 116, 105, 111, 110, 68, 97, 116, 97, + 78, 117, 109, 98, 101, 114, 34, 58, 49, 55, 44, 34, 116, 100, 120, 77, 111, 100, + 117, 108, 101, 34, 58, 123, 34, 109, 114, 115, 105, 103, 110, 101, 114, 34, 58, 34, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, + 98, 117, 116, 101, 115, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 77, 97, + 115, 107, 34, 58, 34, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 34, 125, 44, 34, 116, 100, 120, 77, 111, 100, 117, 108, 101, 73, 100, 101, 110, + 116, 105, 116, 105, 101, 115, 34, 58, 91, 123, 34, 105, 100, 34, 58, 34, 84, 68, + 88, 95, 48, 51, 34, 44, 34, 109, 114, 115, 105, 103, 110, 101, 114, 34, 58, 34, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, 98, + 117, 116, 101, 115, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 77, 97, + 115, 107, 34, 58, 34, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 34, 44, 34, 116, 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, 116, + 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 51, 125, 44, 34, + 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 52, 45, 48, 51, 45, 49, 51, + 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, + 117, 115, 34, 58, 34, 85, 112, 84, 111, 68, 97, 116, 101, 34, 125, 93, 125, 44, + 123, 34, 105, 100, 34, 58, 34, 84, 68, 88, 95, 48, 49, 34, 44, 34, 109, 114, 115, + 105, 103, 110, 101, 114, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 58, 34, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, + 114, 105, 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 58, 34, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 34, 44, 34, 116, 99, 98, 76, 101, 118, + 101, 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, + 115, 118, 110, 34, 58, 52, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, + 50, 48, 50, 52, 45, 48, 51, 45, 49, 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, + 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 85, 112, 84, 111, 68, + 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, + 115, 118, 110, 34, 58, 50, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, + 50, 48, 50, 51, 45, 48, 56, 45, 48, 57, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, + 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, + 68, 97, 116, 101, 34, 125, 93, 125, 93, 44, 34, 116, 99, 98, 76, 101, 118, 101, + 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, 34, 115, + 118, 110, 34, 58, 55, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, + 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, 114, 108, 121, 32, + 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 55, 44, 34, 99, 97, 116, 101, 103, 111, 114, + 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, + 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, + 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, + 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, + 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, 73, 84, 34, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 44, 34, 99, 97, 116, 101, 103, 111, + 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 49, 44, 34, 99, 97, 116, 101, 103, 111, + 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, + 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, + 34, 58, 34, 83, 69, 65, 77, 76, 68, 82, 32, 65, 67, 77, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 49, 44, 34, + 116, 100, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, + 58, 91, 123, 34, 115, 118, 110, 34, 58, 53, 44, 34, 99, 97, 116, 101, 103, 111, + 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, + 58, 34, 84, 68, 88, 32, 77, 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, + 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 77, + 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 55, 44, 34, + 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, + 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 76, 97, 116, 101, 32, 77, 105, + 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 93, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 52, 45, 48, 51, 45, 49, 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, + 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 85, 112, 84, 111, 68, 97, 116, + 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, 34, 115, 118, + 110, 34, 58, 54, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, + 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, 114, 108, 121, 32, 77, + 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 54, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, + 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 83, + 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, + 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 44, 34, + 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, + 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, 73, 84, 34, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 50, 44, 34, 99, 97, 116, 101, 103, 111, 114, + 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, + 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 49, 44, 34, 99, 97, 116, 101, 103, 111, 114, + 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, + 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, + 58, 34, 83, 69, 65, 77, 76, 68, 82, 32, 65, 67, 77, 34, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 49, 44, 34, 116, + 100, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, + 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, + 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, + 68, 88, 32, 77, 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 48, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, + 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 77, 111, 100, + 117, 108, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 54, 44, 34, 99, 97, + 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, + 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, + 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 93, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, + 56, 45, 48, 57, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, + 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, + 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, + 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 57, 54, 48, 34, 44, 34, 73, 78, 84, 69, 76, + 45, 83, 65, 45, 48, 48, 57, 56, 50, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, + 48, 48, 57, 56, 54, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, + 123, 34, 115, 118, 110, 34, 58, 53, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, + 34, 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, + 114, 108, 121, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, + 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 53, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, + 112, 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, + 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 50, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, + 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, + 78, 73, 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, + 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 49, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, + 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, + 121, 112, 101, 34, 58, 34, 83, 69, 65, 77, 76, 68, 82, 32, 65, 67, 77, 34, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, + 49, 49, 44, 34, 116, 100, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, + 116, 115, 34, 58, 91, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, + 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, + 101, 34, 58, 34, 84, 68, 88, 32, 77, 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 48, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, + 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, + 32, 77, 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 53, + 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, + 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 76, 97, 116, 101, 32, + 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 93, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, + 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, + 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, + 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, 115, 34, + 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 56, 51, 55, 34, 44, 34, 73, + 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 57, 54, 48, 34, 44, 34, 73, 78, 84, 69, 76, + 45, 83, 65, 45, 48, 48, 57, 56, 50, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, + 48, 48, 57, 56, 54, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, + 123, 34, 115, 118, 110, 34, 58, 53, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, + 34, 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, + 114, 108, 121, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, + 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 53, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, + 112, 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, + 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 50, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, + 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, + 78, 73, 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, + 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 49, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, + 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, + 121, 112, 101, 34, 58, 34, 83, 69, 65, 77, 76, 68, 82, 32, 65, 67, 77, 34, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, + 53, 44, 34, 116, 100, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, + 115, 34, 58, 91, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, + 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, + 34, 58, 34, 84, 68, 88, 32, 77, 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, + 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 77, + 111, 100, 117, 108, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 53, 44, 34, + 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, + 34, 116, 121, 112, 101, 34, 58, 34, 84, 68, 88, 32, 76, 97, 116, 101, 32, 77, 105, + 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 93, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, + 56, 45, 48, 49, 45, 48, 52, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, + 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, + 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, 115, 34, 58, + 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 49, 48, 54, 34, 44, 34, 73, 78, + 84, 69, 76, 45, 83, 65, 45, 48, 48, 49, 49, 53, 34, 44, 34, 73, 78, 84, 69, 76, 45, + 83, 65, 45, 48, 48, 49, 51, 53, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 50, 48, 51, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 50, 48, + 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 51, 51, 34, 44, 34, 73, + 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 55, 48, 34, 44, 34, 73, 78, 84, 69, 76, + 45, 83, 65, 45, 48, 48, 50, 57, 51, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, + 48, 48, 51, 50, 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 50, + 57, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 56, 49, 34, 44, 34, + 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 56, 57, 34, 44, 34, 73, 78, 84, 69, + 76, 45, 83, 65, 45, 48, 48, 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, + 45, 48, 48, 56, 51, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 57, + 54, 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 57, 56, 50, 34, 44, + 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 57, 56, 54, 34, 93, 125, 93, 125, + 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, 34, 48, 54, 99, 52, 54, + 48, 56, 54, 55, 56, 56, 50, 100, 99, 99, 100, 100, 97, 49, 55, 48, 48, 52, 98, 97, + 54, 48, 102, 53, 52, 99, 50, 50, 101, 102, 56, 53, 52, 100, 53, 57, 98, 53, 50, 52, + 100, 50, 54, 49, 98, 55, 97, 98, 97, 50, 50, 57, 101, 101, 97, 101, 50, 99, 56, 48, + 48, 51, 56, 53, 101, 55, 51, 48, 56, 51, 50, 53, 98, 56, 97, 48, 49, 48, 53, 48, + 54, 49, 54, 48, 48, 98, 50, 50, 55, 98, 56, 55, 50, 56, 100, 55, 102, 49, 101, 53, + 52, 53, 57, 52, 100, 99, 101, 98, 50, 100, 102, 48, 102, 53, 54, 102, 51, 97, 54, + 100, 102, 102, 99, 34, 125, 0, + ] + .into(), + qe_identity_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + qe_identity: [ + 123, 34, 101, 110, 99, 108, 97, 118, 101, 73, 100, 101, 110, 116, 105, 116, 121, + 34, 58, 123, 34, 105, 100, 34, 58, 34, 84, 68, 95, 81, 69, 34, 44, 34, 118, 101, + 114, 115, 105, 111, 110, 34, 58, 50, 44, 34, 105, 115, 115, 117, 101, 68, 97, 116, + 101, 34, 58, 34, 50, 48, 50, 52, 45, 49, 50, 45, 48, 53, 84, 49, 49, 58, 52, 54, + 58, 49, 50, 90, 34, 44, 34, 110, 101, 120, 116, 85, 112, 100, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 53, 45, 48, 49, 45, 48, 52, 84, 49, 49, 58, 52, 54, 58, 49, 50, 90, + 34, 44, 34, 116, 99, 98, 69, 118, 97, 108, 117, 97, 116, 105, 111, 110, 68, 97, + 116, 97, 78, 117, 109, 98, 101, 114, 34, 58, 49, 55, 44, 34, 109, 105, 115, 99, + 115, 101, 108, 101, 99, 116, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, + 34, 109, 105, 115, 99, 115, 101, 108, 101, 99, 116, 77, 97, 115, 107, 34, 58, 34, + 70, 70, 70, 70, 70, 70, 70, 70, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, + 101, 115, 34, 58, 34, 49, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, + 116, 116, 114, 105, 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 58, 34, 70, 66, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 109, 114, 115, 105, 103, 110, 101, + 114, 34, 58, 34, 68, 67, 57, 69, 50, 65, 55, 67, 54, 70, 57, 52, 56, 70, 49, 55, + 52, 55, 52, 69, 51, 52, 65, 55, 70, 67, 52, 51, 69, 68, 48, 51, 48, 70, 55, 67, 49, + 53, 54, 51, 70, 49, 66, 65, 66, 68, 68, 70, 54, 51, 52, 48, 67, 56, 50, 69, 48, 69, + 53, 52, 65, 56, 67, 53, 34, 44, 34, 105, 115, 118, 112, 114, 111, 100, 105, 100, + 34, 58, 50, 44, 34, 116, 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, + 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 52, 125, 44, + 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 52, 45, 48, 51, 45, 49, + 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, + 116, 117, 115, 34, 58, 34, 85, 112, 84, 111, 68, 97, 116, 101, 34, 125, 93, 125, + 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, 34, 55, 55, 53, 57, 54, + 101, 102, 102, 51, 101, 101, 101, 56, 99, 100, 51, 101, 52, 101, 54, 50, 48, 48, + 56, 102, 57, 97, 102, 97, 100, 100, 51, 51, 51, 101, 57, 102, 56, 100, 99, 56, 51, + 55, 102, 101, 54, 51, 50, 50, 53, 54, 56, 49, 52, 55, 100, 97, 57, 56, 99, 56, 99, + 57, 55, 99, 53, 99, 102, 54, 50, 54, 52, 102, 51, 98, 48, 100, 52, 55, 99, 99, 97, + 97, 54, 49, 98, 49, 98, 53, 97, 49, 101, 56, 99, 53, 53, 51, 97, 49, 54, 51, 50, + 50, 50, 51, 55, 99, 99, 57, 48, 48, 49, 102, 50, 100, 97, 100, 49, 56, 51, 52, 52, + 57, 54, 53, 52, 49, 49, 34, 125, 0, + ] + .into(), + }; + + let report_data = hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + + let mrsigner = + hex::decode("3b909bb3658ff42a1e877b8806fdab857f70dfc90244270c12ec2459c98d191a") + .unwrap(); + + check_quote( + "e, + Some(&collateral), + current_time as i64, + &mrsigner, + &report_data, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK, + ) + .context("check_quote")?; + Ok(()) + } } diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index fbc280f..a8f64a0 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -1,10 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.buildPackage ( +{ lib, pkgs, makeWrapper, teepotCrate }: teepotCrate.craneLib.buildPackage ( teepotCrate.commonArgs // { pname = "teepot"; inherit (teepotCrate) cargoArtifacts; + nativeBuildInputs = teepotCrate.commonArgs.nativeBuildInputs ++ [ makeWrapper ]; + passthru = { inherit (teepotCrate) rustPlatform rustVersion @@ -28,6 +30,7 @@ "verify_attestation" "verify_era_proof_attestation" ]; + postInstall = '' removeReferencesToVendoredSources "$out" "$cargoVendorDir" removeReferencesToVendoredSources "$out" "${teepotCrate.rustVersion}/lib/rustlib/" @@ -38,6 +41,11 @@ echo -n "''${!i} " >> $out/nix-support/propagated-user-env-packages binname=''${i//_/-} mv "$out/bin/$binname" "''${!i}/bin/" + + makeWrapper "''${!i}/bin/$binname" "''${!i}/bin/$binname-dcap" \ + --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ pkgs.nixsgx.sgx-dcap.quote_verify pkgs.nixsgx.sgx-dcap.default_qpl pkgs.curl ]}" \ + --set-default QCNL_CONF_PATH "${pkgs.nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf" + done rmdir "$out/bin" ''; From 0b67a14cd15aa14dfbb87f882322bd1a9b747fce Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 11:27:04 +0100 Subject: [PATCH 019/114] chore: cargo update Signed-off-by: Harald Hoyer --- Cargo.lock | 1187 ++++++++++++++---------- Cargo.toml | 8 +- bin/tee-vault-admin/src/main.rs | 2 +- bin/tee-vault-unseal/src/main.rs | 2 +- bin/vault-admin/src/main.rs | 34 +- crates/teepot/src/client/mod.rs | 2 +- crates/teepot/src/client/vault.rs | 2 +- crates/teepot/src/server/signatures.rs | 4 +- deny.toml | 1 + 9 files changed, 740 insertions(+), 502 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 355096c..e46dde7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -133,12 +133,12 @@ dependencies = [ "actix-utils", "futures-core", "http 0.2.12", - "http 1.1.0", + "http 1.2.0", "impl-more", "pin-project-lite", "rustls-pki-types", "tokio", - "tokio-rustls 0.25.0", + "tokio-rustls", "tokio-util", "tracing", "webpki-roots", @@ -206,14 +206,14 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -259,6 +259,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "aes-kw" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69fa2b352dcefb5f7f3a5fb840e02665d311d878955380515e4fd50095dd3d8c" +dependencies = [ + "aes", +] + [[package]] name = "ahash" version = "0.8.11" @@ -322,15 +331,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "argon2" @@ -342,6 +351,7 @@ dependencies = [ "blake2", "cpufeatures", "password-hash", + "zeroize", ] [[package]] @@ -352,13 +362,13 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -373,16 +383,16 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "awc" @@ -411,7 +421,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand", - "rustls 0.22.4", + "rustls", "serde", "serde_json", "serde_urlencoded", @@ -420,23 +430,22 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.9.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f95446d919226d587817a7d21379e6eb099b97b45110a7f272a444ca5c54070" +checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" dependencies = [ "aws-lc-sys", - "mirai-annotations", "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.21.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234314bd569802ec87011d653d6815c6d7b9ffb969e9fee5b8b20ef860e8dce9" +checksum = "8478a5c29ead3f3be14aff8a202ad965cf7da6856860041bfca271becf8ba48b" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -458,7 +467,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.32", "itoa", "matchit", "memchr", @@ -597,15 +606,15 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.77", + "syn 2.0.90", "which", ] [[package]] name = "bindgen" -version = "0.69.4" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "bitflags 2.6.0", "cexpr", @@ -620,7 +629,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.77", + "syn 2.0.90", "which", ] @@ -720,9 +729,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" dependencies = [ "memchr", "serde", @@ -751,22 +760,22 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -777,15 +786,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "bytestring" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" dependencies = [ "bytes", ] @@ -811,9 +820,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.19" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "jobserver", "libc", @@ -858,9 +867,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -909,9 +918,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.17" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -919,9 +928,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.17" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstyle", "clap_lex", @@ -930,21 +939,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cmac" @@ -959,9 +968,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ "cc", ] @@ -1023,9 +1032,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1047,18 +1056,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -1073,7 +1082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1085,7 +1094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1097,7 +1106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -1130,7 +1139,7 @@ dependencies = [ "cpufeatures", "curve25519-dalek-derive", "digest", - "fiat-crypto", + "fiat-crypto 0.2.9", "rustc_version", "subtle", "zeroize", @@ -1144,7 +1153,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1192,7 +1201,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1214,7 +1223,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1267,7 +1276,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1282,33 +1291,33 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "derive_builder_macro" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1321,7 +1330,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1341,7 +1350,7 @@ checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", "unicode-xid", ] @@ -1366,6 +1375,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "dsa" version = "0.6.3" @@ -1457,6 +1477,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed448-goldilocks" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b5fa9e9e3dd5fe1369f380acd3dcdfa766dbd0a1cd5b048fb40e38a6a78e79" +dependencies = [ + "fiat-crypto 0.1.20", + "hex", + "subtle", +] + [[package]] name = "either" version = "1.13.0" @@ -1477,7 +1508,7 @@ dependencies = [ "generic-array", "group 0.12.1", "pkcs8 0.9.0", - "rand_core", + "rand_core 0.6.4", "sec1 0.3.0", "subtle", "zeroize", @@ -1498,7 +1529,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8 0.10.2", - "rand_core", + "rand_core 0.6.4", "sec1 0.7.3", "subtle", "zeroize", @@ -1515,9 +1546,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -1541,7 +1572,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1574,12 +1605,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1628,9 +1659,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" @@ -1638,7 +1669,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1648,10 +1679,16 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1696,9 +1733,9 @@ checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1748,9 +1785,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1763,9 +1800,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1773,15 +1810,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1790,32 +1827,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -1829,9 +1866,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1879,9 +1916,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1942,7 +1979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1953,7 +1990,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1969,7 +2006,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.5.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -1978,17 +2015,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.5.0", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2003,9 +2040,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -2028,12 +2065,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -2060,11 +2091,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2091,9 +2122,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -2118,7 +2149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -2129,16 +2160,16 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2154,9 +2185,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -2178,15 +2209,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "httparse", "itoa", @@ -2198,19 +2229,19 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.4.1", + "http 1.2.0", + "hyper 1.5.2", "hyper-util", "log", - "rustls 0.23.13", + "rustls", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tower-service", ] @@ -2220,7 +2251,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.30", + "hyper 0.14.32", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2233,7 +2264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.32", "native-tls", "tokio", "tokio-native-tls", @@ -2247,7 +2278,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.2", "hyper-util", "native-tls", "tokio", @@ -2257,29 +2288,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.2", "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2298,6 +2328,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "idea" version = "0.5.1" @@ -2315,12 +2463,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -2334,9 +2493,9 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" +checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" [[package]] name = "impl-rlp" @@ -2358,13 +2517,13 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -2380,12 +2539,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "serde", ] @@ -2409,9 +2568,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "iter-read" @@ -2439,9 +2598,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -2474,10 +2633,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2507,16 +2667,16 @@ dependencies = [ "futures-channel", "futures-util", "gloo-net", - "http 1.1.0", + "http 1.2.0", "jsonrpsee-core", "pin-project", - "rustls 0.23.13", + "rustls", "rustls-pki-types", "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls 0.26.0", + "tokio-rustls", "tokio-util", "tracing", "url", @@ -2534,7 +2694,7 @@ dependencies = [ "bytes", "futures-timer", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "jsonrpsee-types", @@ -2558,12 +2718,12 @@ dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.2", "hyper-rustls", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.13", + "rustls", "rustls-platform-verifier", "serde", "serde_json", @@ -2584,7 +2744,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2594,7 +2754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" dependencies = [ "beef", - "http 1.1.0", + "http 1.2.0", "serde", "serde_json", "thiserror", @@ -2617,7 +2777,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" dependencies = [ - "http 1.1.0", + "http 1.2.0", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -2638,9 +2798,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa 0.16.9", @@ -2682,15 +2842,15 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2698,28 +2858,28 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linkme" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c943daedff228392b791b33bba32e75737756e80a613e32e246c6ce9cbab20a" +checksum = "566336154b9e58a4f055f6dd4cbab62c7dc0826ce3c0a04e63b2d2ecd784cdae" dependencies = [ "linkme-impl", ] [[package]] name = "linkme-impl" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26336e6dc7cc76e7927d2c9e7e3bb376d7af65a6f56a0b16c47d18a9b1abc5" +checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2728,6 +2888,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "local-channel" version = "0.1.5" @@ -2781,7 +2947,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2850,7 +3016,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2867,32 +3033,25 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "log", "wasi", "windows-sys 0.52.0", ] -[[package]] -name = "mirai-annotations" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" - [[package]] name = "multimap" version = "0.10.0" @@ -2901,9 +3060,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "mutually_exclusive_features" -version = "0.0.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d02c0b00610773bb7fc61d85e13d86c7858cbdf00e1a120bfc41bc055dbaa0e" +checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" [[package]] name = "native-tls" @@ -3082,7 +3241,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -3094,14 +3253,14 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -3120,9 +3279,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -3132,9 +3291,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3153,7 +3312,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -3164,9 +3323,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -3298,9 +3457,9 @@ dependencies = [ [[package]] name = "os_info" -version = "3.8.2" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +checksum = "e5ca711d8b83edbb00b44d504503cd247c9c0bd8b0fa2694f2a1a3d8165379ce" dependencies = [ "log", "serde", @@ -3347,7 +3506,7 @@ dependencies = [ "ecdsa 0.16.9", "elliptic-curve 0.13.8", "primeorder", - "rand_core", + "rand_core 0.6.4", "sha2", ] @@ -3407,7 +3566,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -3445,17 +3604,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.7.0", ] [[package]] name = "pgp" -version = "0.13.2" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6c842436d5fa2b59eac1e9b3d142b50bfff99c1744c816b1f4c2ac55a20754" +checksum = "1877a97fd422433220ad272eb008ec55691944b1200e9eb204e3cb2cb69d34e9" dependencies = [ "aes", "aes-gcm", + "aes-kw", "argon2", "base64 0.22.1", "bitfield", @@ -3473,6 +3633,7 @@ dependencies = [ "crc24", "curve25519-dalek", "derive_builder", + "derive_more 1.0.0-beta.6", "des", "digest", "dsa", @@ -3486,7 +3647,7 @@ dependencies = [ "hkdf", "idea", "iter-read", - "k256 0.13.3", + "k256 0.13.4", "log", "md-5", "nom", @@ -3509,34 +3670,35 @@ dependencies = [ "thiserror", "twofish", "x25519-dalek", + "x448", "zeroize", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -3577,9 +3739,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polyval" @@ -3610,12 +3772,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -3656,14 +3818,14 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -3688,7 +3850,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -3728,7 +3890,7 @@ dependencies = [ "prost 0.12.6", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.90", "tempfile", ] @@ -3755,7 +3917,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -3842,7 +4004,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -3852,9 +4014,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + [[package]] name = "rand_core" version = "0.6.4" @@ -3866,23 +4034,23 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -3896,13 +4064,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -3919,9 +4087,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -3937,7 +4105,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.32", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -3965,9 +4133,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -3975,11 +4143,11 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.6", - "http 1.1.0", + "h2 0.4.7", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.2", "hyper-rustls", "hyper-tls 0.6.0", "hyper-util", @@ -3991,11 +4159,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "system-configuration 0.6.1", "tokio", "tokio-native-tls", @@ -4064,9 +4232,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid", "digest", @@ -4075,7 +4243,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8 0.10.2", - "rand_core", + "rand_core 0.6.4", "sha2", "signature 2.2.0", "spki 0.7.3", @@ -4112,36 +4280,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls" -version = "0.23.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "aws-lc-rs", "log", @@ -4160,7 +4314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -4177,19 +4331,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" [[package]] name = "rustls-platform-verifier" @@ -4202,7 +4355,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.13", + "rustls", "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", @@ -4232,9 +4385,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -4253,9 +4406,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -4356,9 +4509,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" dependencies = [ "core-foundation-sys", "libc", @@ -4366,9 +4519,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "send_wrapper" @@ -4486,9 +4639,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -4505,20 +4658,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -4550,19 +4703,19 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.5.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", - "serde_with_macros 3.9.0", + "serde_with_macros 3.11.0", "time", ] @@ -4580,14 +4733,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -4596,7 +4749,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.7.0", "itoa", "ryu", "serde", @@ -4622,6 +4775,7 @@ checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" dependencies = [ "digest", "sha1", + "zeroize", ] [[package]] @@ -4697,7 +4851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -4707,7 +4861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -4727,9 +4881,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4737,9 +4891,9 @@ dependencies = [ [[package]] name = "soketto" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ "base64 0.22.1", "bytes", @@ -4847,9 +5001,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -4864,13 +5018,24 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -4940,7 +5105,7 @@ name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.17", + "clap 4.5.23", "rand", "secp256k1 0.29.1", "teepot", @@ -4954,7 +5119,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.17", + "clap 4.5.23", "rsa", "teepot", "tracing", @@ -4982,7 +5147,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.17", + "clap 4.5.23", "serde", "teepot", "tracing", @@ -4998,9 +5163,9 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap 4.5.17", + "clap 4.5.23", "hex", - "rustls 0.22.4", + "rustls", "serde_json", "sha2", "teepot", @@ -5017,8 +5182,8 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.17", - "rustls 0.22.4", + "clap 4.5.23", + "rustls", "serde_json", "teepot", "tracing", @@ -5037,7 +5202,7 @@ dependencies = [ "base64 0.22.1", "bytemuck", "bytes", - "clap 4.5.17", + "clap 4.5.23", "const-oid", "enumset", "futures-core", @@ -5050,10 +5215,10 @@ dependencies = [ "pkcs8 0.10.2", "rand", "rsa", - "rustls 0.22.4", + "rustls", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "sha2", "signature 2.2.0", "tdx-attest-rs", @@ -5077,7 +5242,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.17", + "clap 4.5.23", "serde_json", "teepot", "tracing", @@ -5100,7 +5265,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.17", + "clap 4.5.23", "serde_json", "teepot", "tracing", @@ -5110,9 +5275,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -5132,12 +5297,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -5157,22 +5322,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5187,9 +5352,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -5208,9 +5373,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -5226,20 +5391,15 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tls_codec" version = "0.4.1" @@ -5258,14 +5418,14 @@ checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "tokio" -version = "1.40.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -5297,7 +5457,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5312,31 +5472,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.22.4", - "rustls-pki-types", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" -dependencies = [ - "rustls 0.23.13", - "rustls-pki-types", + "rustls", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -5345,9 +5493,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -5369,20 +5517,20 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.7.0", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.7.0", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] @@ -5400,7 +5548,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.32", "hyper-timeout", "percent-encoding", "pin-project", @@ -5447,9 +5595,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -5459,9 +5607,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.12" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284586dc201db407be8c9d721abad1b3a6dacbbce5cccecd4fd15a37db95ab0d" +checksum = "54a9f5c1aca50ebebf074ee665b9f99f2e84906dcf6b993a0d0090edb835166d" dependencies = [ "actix-web", "mutually_exclusive_features", @@ -5472,20 +5620,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -5531,9 +5679,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -5541,9 +5689,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -5579,7 +5727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5624,38 +5772,23 @@ dependencies = [ "libc", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -5681,9 +5814,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.10.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" dependencies = [ "base64 0.22.1", "log", @@ -5694,9 +5827,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5711,10 +5844,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] -name = "uuid" -version = "1.10.0" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", "serde", @@ -5733,7 +5878,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.17", + "clap 4.5.23", "hex", "pgp", "serde_json", @@ -5750,7 +5895,7 @@ dependencies = [ "actix-web", "anyhow", "base64 0.22.1", - "clap 4.5.17", + "clap 4.5.23", "serde_json", "teepot", "tracing", @@ -5775,7 +5920,7 @@ name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.17", + "clap 4.5.23", "hex", "secp256k1 0.29.1", "teepot", @@ -5787,14 +5932,14 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.17", + "clap 4.5.23", "ctrlc", "hex", "jsonrpsee-types", - "reqwest 0.12.7", + "reqwest 0.12.9", "secp256k1 0.29.1", "serde", - "serde_with 3.9.0", + "serde_with 3.11.0", "teepot", "tokio", "tracing", @@ -5832,7 +5977,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23981b18d697026f5430249ab01ba739ef2edc463e400042394331cb2bb63494" dependencies = [ - "hyper 0.14.30", + "hyper 0.14.32", "once_cell", "tokio", "tracing", @@ -5847,7 +5992,7 @@ checksum = "8bb19c33cd5f04dcf4e767635e058a998edbc2b7fca32ade0a4a1cea0f8e9b34" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5877,9 +6022,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -5888,36 +6033,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5925,28 +6070,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -5954,9 +6099,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.5" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -6202,9 +6347,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6219,6 +6364,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -6235,11 +6392,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] +[[package]] +name = "x448" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd07d4fae29e07089dbcacf7077cd52dce7760125ca9a4dd5a35ca603ffebb" +dependencies = [ + "ed448-goldilocks", + "hex", + "rand_core 0.5.1", +] + [[package]] name = "x509-cert" version = "0.2.5" @@ -6254,6 +6422,30 @@ dependencies = [ "tls_codec", ] +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -6272,7 +6464,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", ] [[package]] @@ -6293,7 +6506,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -6488,7 +6723,7 @@ dependencies = [ "prost-reflect", "protox", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -6550,7 +6785,7 @@ dependencies = [ "itertools 0.10.5", "num", "once_cell", - "reqwest 0.12.7", + "reqwest 0.12.9", "serde", "serde_json", "thiserror", @@ -6595,7 +6830,7 @@ dependencies = [ "jsonrpsee", "pin-project-lite", "rlp", - "rustls 0.23.13", + "rustls", "serde", "serde_json", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index d36677f..113ab1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,9 @@ homepage = "https://github.com/matter-labs/teepot" [workspace.dependencies] actix-http = "3" -actix-web = { version = "4.5", features = ["rustls-0_22"] } +actix-web = { version = "4.5", features = ["rustls-0_23"] } anyhow = "1.0.82" -awc = { version = "3.4", features = ["rustls-0_22-webpki-roots"] } +awc = { version = "3.4", features = ["rustls-0_23-webpki-roots"] } base64 = "0.22.0" bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "extern_crate_std"] } bytes = "1" @@ -36,12 +36,12 @@ jsonrpsee-types = { version = "0.23", default-features = false } num-integer = "0.1.46" num-traits = "0.2.18" p256 = "0.13.2" -pgp = "0.13" +pgp = "0.14.2" pkcs8 = { version = "0.10" } rand = "0.8" reqwest = { version = "0.12", features = ["json"] } rsa = { version = "0.9.6", features = ["sha2", "pem"] } -rustls = { version = "0.22" } +rustls = { version = "0.23.20" } secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] } serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" diff --git a/bin/tee-vault-admin/src/main.rs b/bin/tee-vault-admin/src/main.rs index 9cd54f8..6972217 100644 --- a/bin/tee-vault-admin/src/main.rs +++ b/bin/tee-vault-admin/src/main.rs @@ -95,7 +95,7 @@ async fn main() -> Result<()> { .service(web::resource(SignRequest::URL).route(web::post().to(post_sign))) .service(web::resource(DIGEST_URL).route(web::get().to(get_digest))) }) - .bind_rustls_0_22((Ipv6Addr::UNSPECIFIED, args.port), config) + .bind_rustls_0_23((Ipv6Addr::UNSPECIFIED, args.port), config) { Ok(c) => c, Err(e) => { diff --git a/bin/tee-vault-unseal/src/main.rs b/bin/tee-vault-unseal/src/main.rs index b30b977..b3db5c4 100644 --- a/bin/tee-vault-unseal/src/main.rs +++ b/bin/tee-vault-unseal/src/main.rs @@ -186,7 +186,7 @@ async fn main() -> Result<()> { .service(web::resource(Init::URL).route(web::post().to(post_init))) .service(web::resource(Unseal::URL).route(web::post().to(post_unseal))) }) - .bind_rustls_0_22((Ipv6Addr::UNSPECIFIED, args.port), config) + .bind_rustls_0_23((Ipv6Addr::UNSPECIFIED, args.port), config) { Ok(c) => c, Err(e) => { diff --git a/bin/vault-admin/src/main.rs b/bin/vault-admin/src/main.rs index f37bc8e..eb123ef 100644 --- a/bin/vault-admin/src/main.rs +++ b/bin/vault-admin/src/main.rs @@ -3,23 +3,25 @@ use anyhow::{anyhow, bail, Context, Result}; use clap::{Args, Parser, Subcommand}; -use pgp::types::KeyTrait; -use pgp::{Deserializable, SignedPublicKey}; +use pgp::{types::PublicKeyTrait, Deserializable, SignedPublicKey}; use serde_json::Value; -use std::default::Default; -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; -use teepot::client::{AttestationArgs, TeeConnection}; -use teepot::json::http::{ - SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands, - VaultCommandsResponse, DIGEST_URL, +use std::{ + default::Default, + fs::{File, OpenOptions}, + io::{Read, Write}, + path::{Path, PathBuf}, }; -use teepot::log::{setup_logging, LogLevelParser}; -use teepot::server::signatures::verify_sig; -use teepot::sgx::sign::Signature; -use tracing::level_filters::LevelFilter; -use tracing::{error, info}; +use teepot::{ + client::{AttestationArgs, TeeConnection}, + json::http::{ + SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands, + VaultCommandsResponse, DIGEST_URL, + }, + log::{setup_logging, LogLevelParser}, + server::signatures::verify_sig, + sgx::sign::Signature, +}; +use tracing::{error, info, level_filters::LevelFilter}; #[derive(Args, Debug)] struct SendArgs { @@ -190,7 +192,7 @@ fn verify( let ident_pos = verify_sig(&sig, &cmd_buf, &idents)?; println!( "Verified signature for `{}`", - hex::encode_upper(idents.get(ident_pos).unwrap().fingerprint()) + hex::encode_upper(idents.get(ident_pos).unwrap().fingerprint().as_bytes()) ); // Remove the identity from the list of identities to verify idents.remove(ident_pos); diff --git a/crates/teepot/src/client/mod.rs b/crates/teepot/src/client/mod.rs index 284468d..ea59e8c 100644 --- a/crates/teepot/src/client/mod.rs +++ b/crates/teepot/src/client/mod.rs @@ -73,7 +73,7 @@ impl TeeConnection { let agent = Client::builder() .add_default_header((header::USER_AGENT, "teepot/1.0")) // a "connector" wraps the stream into an encrypted connection - .connector(Connector::new().rustls_0_22(tls_config)) + .connector(Connector::new().rustls_0_23(tls_config)) .timeout(Duration::from_secs(12000)) .finish(); diff --git a/crates/teepot/src/client/vault.rs b/crates/teepot/src/client/vault.rs index fd25d4b..2f54cc4 100644 --- a/crates/teepot/src/client/vault.rs +++ b/crates/teepot/src/client/vault.rs @@ -107,7 +107,7 @@ impl VaultConnection { let client = Client::builder() .add_default_header((header::USER_AGENT, "teepot/1.0")) // a "connector" wraps the stream into an encrypted connection - .connector(Connector::new().rustls_0_22(tls_config)) + .connector(Connector::new().rustls_0_23(tls_config)) .timeout(time::Duration::from_secs(12000)) .finish(); diff --git a/crates/teepot/src/server/signatures.rs b/crates/teepot/src/server/signatures.rs index e91aa93..785a68c 100644 --- a/crates/teepot/src/server/signatures.rs +++ b/crates/teepot/src/server/signatures.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2024 Matter Labs //! Signature checking utilities @@ -7,7 +7,7 @@ use crate::json::secrets::AdminConfig; use crate::server::{HttpResponseError, Status as _}; use actix_web::http::StatusCode; use anyhow::{anyhow, bail, Context, Result}; -use pgp::types::KeyTrait; +use pgp::types::PublicKeyTrait; use pgp::{Deserializable, SignedPublicKey, StandaloneSignature}; use tracing::debug; diff --git a/deny.toml b/deny.toml index ec551a1..608ba27 100644 --- a/deny.toml +++ b/deny.toml @@ -29,6 +29,7 @@ allow = [ "Unlicense", "MPL-2.0", "Unicode-DFS-2016", + "Unicode-3.0", "BSD-2-Clause", "BSD-3-Clause", "OpenSSL", From 5d323969663857736b78caae62b2ae06a65c58a7 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 17 Dec 2024 13:18:10 +0100 Subject: [PATCH 020/114] feat: add tdx-extend, sha384-extend and rtmr-calc This enables pre-calculating the TDX rtmr[1,2,3] values for an attested boot process. Signed-off-by: Harald Hoyer --- Cargo.lock | 112 +++++++++++++++- Cargo.toml | 2 + bin/rtmr-calc/Cargo.toml | 18 +++ bin/rtmr-calc/src/main.rs | 237 ++++++++++++++++++++++++++++++++++ bin/sha384-extend/Cargo.toml | 14 ++ bin/sha384-extend/src/main.rs | 39 ++++++ bin/tdx-extend/Cargo.toml | 16 +++ bin/tdx-extend/src/main.rs | 60 +++++++++ crates/teepot/src/lib.rs | 12 ++ crates/teepot/src/tdx/mod.rs | 2 + crates/teepot/src/tdx/rtmr.rs | 90 +++++++++++++ packages/teepot/default.nix | 3 + 12 files changed, 603 insertions(+), 2 deletions(-) create mode 100644 bin/rtmr-calc/Cargo.toml create mode 100644 bin/rtmr-calc/src/main.rs create mode 100644 bin/sha384-extend/Cargo.toml create mode 100644 bin/sha384-extend/src/main.rs create mode 100644 bin/tdx-extend/Cargo.toml create mode 100644 bin/tdx-extend/src/main.rs create mode 100644 crates/teepot/src/tdx/rtmr.rs diff --git a/Cargo.lock b/Cargo.lock index e46dde7..c447712 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -975,6 +975,18 @@ dependencies = [ "cc", ] +[[package]] +name = "cms" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" +dependencies = [ + "const-oid", + "der 0.7.9", + "spki 0.7.3", + "x509-cert", +] + [[package]] name = "combine" version = "4.6.7" @@ -1039,6 +1051,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc24" version = "0.1.6" @@ -1264,7 +1291,7 @@ dependencies = [ "const-oid", "der_derive", "flagset", - "pem-rfc7468", + "pem-rfc7468 0.7.0", "zeroize", ] @@ -1527,7 +1554,7 @@ dependencies = [ "generic-array", "group 0.13.0", "hkdf", - "pem-rfc7468", + "pem-rfc7468 0.7.0", "pkcs8 0.10.2", "rand_core 0.6.4", "sec1 0.7.3", @@ -1972,6 +1999,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gpt" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffa5448a0d9d541f1840c0e1b5fe513360861ca83c4b920619f54efe277f9254" +dependencies = [ + "bitflags 2.6.0", + "crc", + "simple-bytes", + "uuid", +] + [[package]] name = "group" version = "0.12.1" @@ -3576,6 +3615,25 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pe-sign" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04c052a5cf901a229d69fb8804b04c8017c143712529c6e8277aac243fc2989" +dependencies = [ + "chrono", + "cms", + "der 0.7.9", + "digest", + "num-traits", + "pem-rfc7468 1.0.0-rc.2", + "reqwest 0.12.9", + "rsa", + "sha1", + "sha2", + "x509-cert", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -3591,6 +3649,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "1.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dfbfa5c6f0906884269722c5478e72fd4d6c0e24fe600332c6d62359567ce1" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -4251,6 +4318,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rtmr-calc" +version = "0.3.0" +dependencies = [ + "anyhow", + "clap 4.5.23", + "gpt", + "hex", + "pe-sign", + "sha2", + "teepot", + "tracing", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4810,6 +4891,16 @@ dependencies = [ "keccak", ] +[[package]] +name = "sha384-extend" +version = "0.3.0" +dependencies = [ + "anyhow", + "clap 4.5.23", + "hex", + "sha2", +] + [[package]] name = "sha3_ce" version = "0.10.6" @@ -4864,6 +4955,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simple-bytes" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11532d9d241904f095185f35dcdaf930b1427a94d5b01d7002d74ba19b44cc4" + [[package]] name = "slab" version = "0.4.9" @@ -5100,6 +5197,17 @@ dependencies = [ "bindgen 0.59.2", ] +[[package]] +name = "tdx-extend" +version = "0.3.0" +dependencies = [ + "anyhow", + "clap 4.5.23", + "hex", + "teepot", + "tracing", +] + [[package]] name = "tee-key-preexec" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 113ab1e..31bbed1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ ctrlc = "3.4" enumset = { version = "1.1", features = ["serde"] } futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } getrandom = "0.2.14" +gpt = "4.0.0" 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.3.0" } intel-tee-quote-verification-sys = { version = "0.2.1" } @@ -36,6 +37,7 @@ jsonrpsee-types = { version = "0.23", default-features = false } num-integer = "0.1.46" num-traits = "0.2.18" p256 = "0.13.2" +pe-sign = "0.1.10" pgp = "0.14.2" pkcs8 = { version = "0.10" } rand = "0.8" diff --git a/bin/rtmr-calc/Cargo.toml b/bin/rtmr-calc/Cargo.toml new file mode 100644 index 0000000..aeb7e96 --- /dev/null +++ b/bin/rtmr-calc/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "rtmr-calc" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +[dependencies] +anyhow.workspace = true +clap.workspace = true +gpt.workspace = true +hex.workspace = true +pe-sign.workspace = true +sha2.workspace = true +teepot.workspace = true +tracing.workspace = true diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs new file mode 100644 index 0000000..97b4cf4 --- /dev/null +++ b/bin/rtmr-calc/src/main.rs @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +use anyhow::{anyhow, Result}; +use clap::Parser; +use pesign::PE; +use sha2::{Digest, Sha384}; +use std::{ + fmt::{Display, Formatter}, + io::{Error, ErrorKind, Read, Seek, SeekFrom}, + path::PathBuf, +}; +use teepot::log::{setup_logging, LogLevelParser}; +use tracing::{debug, info, level_filters::LevelFilter}; + +/// Precalculate rtmr1 and rtmr2 values. +/// +/// Currently tested with the Google confidential compute engines. +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// disk image to measure the GPT table from + #[arg(long)] + image: PathBuf, + /// path to the used UKI EFI binary + #[arg(long)] + bootefi: PathBuf, + /// path to the used linux kernel EFI binary (contained in the UKI) + #[arg(long)] + kernel: PathBuf, + /// Log level for the log output. + /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` + #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] + pub log_level: LevelFilter, +} + +struct Rtmr { + state: Vec, +} + +impl Rtmr { + pub fn extend(&mut self, hash: &[u8]) -> &[u8] { + self.state.extend(hash); + let bytes = Sha384::digest(&self.state); + self.state.resize(48, 0); + self.state.copy_from_slice(&bytes); + &self.state + } +} + +impl Default for Rtmr { + fn default() -> Self { + Self { + state: [0u8; 48].to_vec(), + } + } +} + +impl Display for Rtmr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(&self.state)) + } +} + +fn main() -> Result<()> { + let args = Arguments::parse(); + tracing::subscriber::set_global_default(setup_logging( + env!("CARGO_CRATE_NAME"), + &args.log_level, + )?)?; + + let mut rtmr1 = Rtmr::default(); + let mut rtmr2 = Rtmr::default(); + + /* + - pcr_index: 1 + event: efiaction + digests: + - method: sha384 + digest: 77a0dab2312b4e1e57a84d865a21e5b2ee8d677a21012ada819d0a98988078d3d740f6346bfe0abaa938ca20439a8d71 + digest_verification_status: verified + data: Q2FsbGluZyBFRkkgQXBwbGljYXRpb24gZnJvbSBCb290IE9wdGlvbg== + parsed_data: + Ok: + text: Calling EFI Application from Boot Option + */ + rtmr1.extend(&hex::decode("77a0dab2312b4e1e57a84d865a21e5b2ee8d677a21012ada819d0a98988078d3d740f6346bfe0abaa938ca20439a8d71")?); + + /* + - pcr_index: 1 + event: separator + digests: + - method: sha384 + digest: 394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0 + digest_verification_status: verified + data: AAAAAA== + parsed_data: + Ok: + validseparator: UEFI + */ + rtmr1.extend(&hex::decode("394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0")?); + + // Open disk image. + let cfg = gpt::GptConfig::new().writable(false); + let disk = cfg.open(args.image)?; + + // Print GPT layout. + info!("Disk (primary) header: {:#?}", disk.primary_header()); + info!("Partition layout: {:#?}", disk.partitions()); + + let header = disk.primary_header()?; + let mut msr = Vec::::new(); + let lb_size = disk.logical_block_size(); + let mut device = disk.device_ref(); + device.seek(SeekFrom::Start(lb_size.as_u64()))?; + let mut buf = [0u8; 92]; + device.read_exact(&mut buf)?; + msr.extend_from_slice(&buf); + + let pstart = header + .part_start + .checked_mul(lb_size.as_u64()) + .ok_or_else(|| Error::new(ErrorKind::Other, "partition overflow - start offset"))?; + let _ = device.seek(SeekFrom::Start(pstart))?; + + assert_eq!(header.part_size, 128); + assert!(header.num_parts < u8::MAX as _); + + let empty_bytes = [0u8; 128]; + + msr.extend_from_slice(&disk.partitions().len().to_le_bytes()); + + for _ in 0..header.num_parts { + let mut bytes = empty_bytes; + + device.read_exact(&mut bytes)?; + if bytes.eq(&empty_bytes) { + continue; + } + msr.extend_from_slice(&bytes); + } + + let mut hasher = Sha384::new(); + hasher.update(&msr); + let result = hasher.finalize(); + info!("GPT hash: {:x}", result); + + rtmr1.extend(&result); + + let mut pe = PE::from_path(&args.bootefi)?; + + let hash = pe.calc_authenticode(pesign::cert::Algorithm::Sha384)?; + info!("hash of {:?}: {hash}", args.bootefi); + rtmr1.extend(&hex::decode(&hash)?); + + let section_table = pe.get_section_table()?; + + for section in section_table.iter() { + debug!(section_name = ?section.name()?); + } + + for sect in [".linux", ".osrel", ".cmdline", ".initrd", ".uname", ".sbat"] { + let mut hasher = Sha384::new(); + hasher.update(sect.as_bytes()); + hasher.update([0u8]); + let out = hasher.finalize(); + debug!(sect, "name: {out:x}"); + rtmr2.extend(&out); + + let s = section_table + .iter() + .find(|s| s.name().unwrap().eq(sect)) + .ok_or(anyhow!("Failed to find section `{sect}`"))?; + + let mut start = s.pointer_to_raw_data as u64; + let end = start + s.virtual_size as u64; + + debug!(sect, start, end, len = (s.virtual_size)); + + let mut hasher = Sha384::new(); + + const CHUNK_SIZE: u64 = 1024 * 128; + loop { + if start >= end { + break; + } + + let mut buf = vec![0; CHUNK_SIZE.min(end - start) as _]; + pe.read_exact_at(start, buf.as_mut_slice())?; + hasher.update(buf.as_slice()); + + start += CHUNK_SIZE; + } + let digest = hasher.finalize(); + debug!(sect, "binary: {digest:x}"); + rtmr2.extend(&digest); + } + + let hash = PE::from_path(&args.kernel)?.calc_authenticode(pesign::cert::Algorithm::Sha384)?; + info!("hash of {:?}: {hash}", args.kernel); + rtmr1.extend(&hex::decode(&hash)?); + + /* + - pcr_index: 1 + event: efiaction + digests: + - method: sha384 + digest: 214b0bef1379756011344877743fdc2a5382bac6e70362d624ccf3f654407c1b4badf7d8f9295dd3dabdef65b27677e0 + digest_verification_status: verified + data: RXhpdCBCb290IFNlcnZpY2VzIEludm9jYXRpb24= + parsed_data: + Ok: + text: Exit Boot Services Invocation + */ + rtmr1.extend(&hex::decode("214b0bef1379756011344877743fdc2a5382bac6e70362d624ccf3f654407c1b4badf7d8f9295dd3dabdef65b27677e0")?); + + /* + - pcr_index: 1 + event: efiaction + digests: + - method: sha384 + digest: 0a2e01c85deae718a530ad8c6d20a84009babe6c8989269e950d8cf440c6e997695e64d455c4174a652cd080f6230b74 + digest_verification_status: verified + data: RXhpdCBCb290IFNlcnZpY2VzIFJldHVybmVkIHdpdGggU3VjY2Vzcw== + parsed_data: + Ok: + text: Exit Boot Services Returned with Success + */ + rtmr1.extend(&hex::decode("0a2e01c85deae718a530ad8c6d20a84009babe6c8989269e950d8cf440c6e997695e64d455c4174a652cd080f6230b74")?); + + println!("{{"); + println!("\t\"rtmr1\": \"{rtmr1}\","); + println!("\t\"rtmr2\": \"{rtmr2}\""); + println!("}}"); + + Ok(()) +} diff --git a/bin/sha384-extend/Cargo.toml b/bin/sha384-extend/Cargo.toml new file mode 100644 index 0000000..f9c58e6 --- /dev/null +++ b/bin/sha384-extend/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sha384-extend" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +[dependencies] +anyhow.workspace = true +clap.workspace = true +hex.workspace = true +sha2.workspace = true diff --git a/bin/sha384-extend/src/main.rs b/bin/sha384-extend/src/main.rs new file mode 100644 index 0000000..2835a3e --- /dev/null +++ b/bin/sha384-extend/src/main.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +//! Extend the TDX measurement + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use anyhow::{Context, Result}; +use clap::Parser; +use sha2::Digest; + +/// Calculate a TDX rtmr or TPM pcr sha384 value by extending it +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// digest in hex to extend with + #[arg(long)] + extend: String, + /// initial digest in hex + #[arg(long)] + digest: String, +} + +fn main() -> Result<()> { + let args = Arguments::parse(); + + // Parse the digest string as a hex array + let extend_bytes = hex::decode(&args.extend).context("Invalid digest format")?; + let mut digest_bytes = hex::decode(&args.digest).context("Invalid digest format")?; + + digest_bytes.extend(extend_bytes); + + let bytes = sha2::Sha384::digest(&digest_bytes); + let hex = hex::encode(bytes); + + println!("{hex}"); + Ok(()) +} diff --git a/bin/tdx-extend/Cargo.toml b/bin/tdx-extend/Cargo.toml new file mode 100644 index 0000000..a34e597 --- /dev/null +++ b/bin/tdx-extend/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "tdx-extend" +publish = false +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +[dependencies] +anyhow.workspace = true +clap.workspace = true +hex.workspace = true +teepot.workspace = true +tracing.workspace = true diff --git a/bin/tdx-extend/src/main.rs b/bin/tdx-extend/src/main.rs new file mode 100644 index 0000000..1a4056c --- /dev/null +++ b/bin/tdx-extend/src/main.rs @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +//! Extend the TDX measurement + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use anyhow::{Context, Result}; +use clap::Parser; +use teepot::{ + log::{setup_logging, LogLevelParser}, + pad, + tdx::rtmr::TdxRtmrEvent, +}; +use tracing::{error, level_filters::LevelFilter}; + +/// Extend a TDX rtmr with a hash digest for measured boot. +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// digest in hex to extend the rtmr with + #[arg(long)] + digest: String, + /// the number or the rtmr + #[arg(long, default_value = "2")] + rtmr: u64, + /// Log level for the log output. + /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` + #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] + pub log_level: LevelFilter, +} + +fn main_with_error() -> Result<()> { + let args = Arguments::parse(); + tracing::subscriber::set_global_default(setup_logging( + env!("CARGO_CRATE_NAME"), + &args.log_level, + )?)?; + + // Parse the digest string as a hex array + let digest_bytes = hex::decode(&args.digest).context("Invalid digest format")?; + let extend_data: [u8; 48] = pad(&digest_bytes); + + // Extend the TDX measurement with the extend data + TdxRtmrEvent::default() + .with_extend_data(extend_data) + .with_rtmr_index(args.rtmr) + .extend()?; + + Ok(()) +} + +fn main() -> Result<()> { + let ret = main_with_error(); + if let Err(e) = &ret { + error!(error = %e, "Execution failed"); + } + ret +} diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 293ef83..2d9f7cc 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -13,3 +13,15 @@ pub mod quote; pub mod server; pub mod sgx; pub mod tdx; + +/// pad a byte slice to a fixed sized array +pub fn pad(input: &[u8]) -> [u8; T] { + let mut output = [0; T]; + let len = input.len(); + if len > T { + output.copy_from_slice(&input[..T]); + } else { + output[..len].copy_from_slice(input); + } + output +} diff --git a/crates/teepot/src/tdx/mod.rs b/crates/teepot/src/tdx/mod.rs index 37c03de..09d6e4c 100644 --- a/crates/teepot/src/tdx/mod.rs +++ b/crates/teepot/src/tdx/mod.rs @@ -3,6 +3,8 @@ //! Intel TDX helper functions. +pub mod rtmr; + pub use crate::sgx::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; use crate::sgx::QuoteError; pub use intel_tee_quote_verification_rs::Collateral; diff --git a/crates/teepot/src/tdx/rtmr.rs b/crates/teepot/src/tdx/rtmr.rs new file mode 100644 index 0000000..bbe478e --- /dev/null +++ b/crates/teepot/src/tdx/rtmr.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +//! rtmr event data + +use crate::sgx::QuoteError; + +/// The actual rtmr event data handled in DCAP +#[repr(C, packed)] +pub struct TdxRtmrEvent { + /// Always 1 + version: u32, + + /// The RTMR that will be extended. As defined in + /// https://github.com/confidential-containers/td-shim/blob/main/doc/tdshim_spec.md#td-measurement + /// we will use RTMR 3 for guest application code and configuration. + rtmr_index: u64, + + /// Data that will be used to extend RTMR + extend_data: [u8; 48usize], + + /// Not used in DCAP + event_type: u32, + + /// Always 0 + event_data_size: u32, + + /// Not used in DCAP + event_data: Vec, +} + +impl Default for TdxRtmrEvent { + fn default() -> Self { + Self { + extend_data: [0; 48], + version: 1, + rtmr_index: 3, + event_type: 0, + event_data_size: 0, + event_data: Vec::new(), + } + } +} + +impl TdxRtmrEvent { + /// use the extend data + pub fn with_extend_data(mut self, extend_data: [u8; 48]) -> Self { + self.extend_data = extend_data; + self + } + + /// extend the rtmr index + pub fn with_rtmr_index(mut self, rtmr_index: u64) -> Self { + self.rtmr_index = rtmr_index; + self + } + + /// extending the index, consuming self + pub fn extend(self) -> Result<(), QuoteError> { + let event: Vec = self.into(); + + match tdx_attest_rs::tdx_att_extend(&event) { + tdx_attest_rs::tdx_attest_error_t::TDX_ATTEST_SUCCESS => Ok(()), + error_code => Err(error_code.into()), + } + } +} + +impl From for Vec { + fn from(val: TdxRtmrEvent) -> Self { + let event_ptr = &val as *const TdxRtmrEvent as *const u8; + let event_data_size = std::mem::size_of::() * val.event_data_size as usize; + let res_size = std::mem::size_of::() * 3 + + std::mem::size_of::() + + std::mem::size_of::<[u8; 48]>() + + event_data_size; + let mut res = vec![0; res_size]; + unsafe { + for (i, chunk) in res.iter_mut().enumerate().take(res_size - event_data_size) { + *chunk = *event_ptr.add(i); + } + } + let event_data = val.event_data; + for i in 0..event_data_size { + res[i + res_size - event_data_size] = event_data[i]; + } + + res + } +} diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index a8f64a0..0879e7e 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -17,6 +17,9 @@ outputs = [ "out" + "rtmr_calc" + "sha384_extend" + "tdx_extend" "tee_key_preexec" "tee_ratls_preexec" "tee_self_attestation_test" From c5373dfd8f27894308b9338c2685add86b30547e Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 14:28:19 +0100 Subject: [PATCH 021/114] chore(flake): update nixsgx flake input Signed-off-by: Harald Hoyer --- flake.lock | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 3074bcb..643b08f 100644 --- a/flake.lock +++ b/flake.lock @@ -142,16 +142,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728740863, - "narHash": "sha256-u+rxA79a0lyhG+u+oPBRtTDtzz8kvkc9a6SWSt9ekVc=", + "lastModified": 1733550349, + "narHash": "sha256-NcGumB4Lr6KSDq+nIqXtNA8QwAQKDSZT7N9OTGWbTrs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a3f9ad65a0bf298ed5847629a57808b97e6e8077", + "rev": "e2605d0744c2417b09f8bf850dfca42fcf537d34", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-24.05", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } @@ -178,11 +178,11 @@ "snowfall-lib": "snowfall-lib" }, "locked": { - "lastModified": 1732034035, - "narHash": "sha256-VMIIgtuBNksCRvcHxFtkzveEYz2w7lO+ltuC23QpBD8=", + "lastModified": 1733824290, + "narHash": "sha256-8MKgW3pFW+IxsM/iGfHio91Gym89gh9uNQ3JO4+D8QY=", "owner": "matter-labs", "repo": "nixsgx", - "rev": "b6b4571d43616ffc7719941daafa350a453a9d44", + "rev": "788ff5233053a52421c9f8fa626a936785dda511", "type": "github" }, "original": { @@ -266,6 +266,7 @@ }, "original": { "owner": "snowfallorg", + "ref": "c6238c83de101729c5de3a29586ba166a9a65622", "repo": "lib", "type": "github" } From d11f63701fe0f7c3e2fccb2ce16e0708ff22590a Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 20 Dec 2024 15:32:55 +0100 Subject: [PATCH 022/114] chore: fix deny.toml see https://github.com/EmbarkStudios/cargo-deny/pull/611 Signed-off-by: Harald Hoyer --- deny.toml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/deny.toml b/deny.toml index 608ba27..2fc391c 100644 --- a/deny.toml +++ b/deny.toml @@ -1,15 +1,15 @@ +[graph] targets = [] all-features = false no-default-features = false + +[output] feature-depth = 1 [advisories] db-path = "~/.cargo/advisory-db" db-urls = ["https://github.com/rustsec/advisory-db"] -vulnerability = "deny" -unmaintained = "warn" yanked = "warn" -notice = "warn" ignore = [ # Sidechannel attack to get the private key https://rustsec.org/advisories/RUSTSEC-2023-0071 # currently no rsa private key is used in the codebase, @@ -20,8 +20,6 @@ ignore = [ ] [licenses] -unlicensed = "deny" -copyleft = "deny" allow = [ "MIT", "Apache-2.0", @@ -35,9 +33,6 @@ allow = [ "OpenSSL", "CC0-1.0", ] -deny = [] -allow-osi-fsf-free = "neither" -default = "deny" confidence-threshold = 0.8 exceptions = [] From 102f73b1eb6e95596fe1d16c3910692747a4eac0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:13:47 +0000 Subject: [PATCH 023/114] chore(deps): update cachix/install-nix-action action to v30 --- .github/workflows/lint.yml | 2 +- .github/workflows/nix.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index dd9157b..7a2e26f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,5 +28,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - - uses: cachix/install-nix-action@v27 + - uses: cachix/install-nix-action@v30 - run: nix run nixpkgs#taplo -- fmt --check diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 20d9047..53bd89b 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - - uses: cachix/install-nix-action@v27 + - uses: cachix/install-nix-action@v30 with: extra_nix_config: | access-tokens = github.com=${{ github.token }} @@ -37,7 +37,7 @@ jobs: runs-on: [ matterlabs-default-infra-runners ] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - - uses: cachix/install-nix-action@v27 + - uses: cachix/install-nix-action@v30 with: extra_nix_config: | access-tokens = github.com=${{ github.token }} @@ -75,7 +75,7 @@ jobs: - { nixpackage: 'container-verify-era-proof-attestation-sgx' } steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v27 + - uses: cachix/install-nix-action@v30 with: extra_nix_config: | access-tokens = github.com=${{ github.token }} From 584223dc9382f544dd8892c83296662c8390915a Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 13 Jan 2025 10:20:27 +0100 Subject: [PATCH 024/114] fix(teepot-tee-quote-verification-rs): memory leak Signed-off-by: Harald Hoyer --- .../src/lib.rs | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/crates/teepot-tee-quote-verification-rs/src/lib.rs b/crates/teepot-tee-quote-verification-rs/src/lib.rs index d337924..81c1b8e 100644 --- a/crates/teepot-tee-quote-verification-rs/src/lib.rs +++ b/crates/teepot-tee-quote-verification-rs/src/lib.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs // SPDX-License-Identifier: BSD-3-Clause /* @@ -39,22 +39,14 @@ //! This is a safe wrapper for **sgx-dcap-quoteverify-sys**. use serde::{Deserialize, Serialize}; -use std::marker::PhantomData; -use std::mem; -use std::ops::Deref; -use std::slice; +use std::{marker::PhantomData, mem, ops::Deref, slice}; use intel_tee_quote_verification_sys as qvl_sys; - -pub use qvl_sys::quote3_error_t; -pub use qvl_sys::sgx_ql_qe_report_info_t; -pub use qvl_sys::sgx_ql_qv_result_t; -pub use qvl_sys::sgx_ql_qv_supplemental_t; -pub use qvl_sys::sgx_ql_qve_collateral_t; -pub use qvl_sys::sgx_ql_request_policy_t; -pub use qvl_sys::sgx_qv_path_type_t; -pub use qvl_sys::tdx_ql_qve_collateral_t; -pub use qvl_sys::tee_supp_data_descriptor_t; +pub use qvl_sys::{ + quote3_error_t, sgx_ql_qe_report_info_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, + sgx_ql_qve_collateral_t, sgx_ql_request_policy_t, sgx_qv_path_type_t, tdx_ql_qve_collateral_t, + tee_qv_free_collateral, tee_supp_data_descriptor_t, +}; /// When the Quoting Verification Library is linked to a process, it needs to know the proper enclave loading policy. /// The library may be linked with a long lived process, such as a service, where it can load the enclaves and leave @@ -447,7 +439,13 @@ pub fn tee_qv_get_collateral(quote: &[u8]) -> Result ); // SAFETY: buf is not null, buf_len is not zero, and buf is aligned. let orig_collateral = &unsafe { *(buf as *const sgx_ql_qve_collateral_t) }; - Collateral::try_from(orig_collateral).map_err(|_| quote3_error_t::SGX_QL_ERROR_MAX) + let collateral = + Collateral::try_from(orig_collateral).map_err(|_| quote3_error_t::SGX_QL_ERROR_MAX); + + match unsafe { tee_qv_free_collateral(buf) } { + quote3_error_t::SGX_QL_SUCCESS => collateral, + error_code => Err(error_code), + } } error_code => Err(error_code), } From dc9263911fb3f32e81ac257d5d63eb29ab26da8e Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 13 Jan 2025 11:09:52 +0100 Subject: [PATCH 025/114] fix(teepot-tee-quote-verification-rs): free collateral on ffi error Free the FFI collateral on rust checks anyway to prevent memory leaks. Also remove the `TryFrom<&sgx_ql_qve_collateral_t>` as it is unsafe. Signed-off-by: Harald Hoyer --- .../src/lib.rs | 99 ++++++++++--------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/crates/teepot-tee-quote-verification-rs/src/lib.rs b/crates/teepot-tee-quote-verification-rs/src/lib.rs index 81c1b8e..c19b292 100644 --- a/crates/teepot-tee-quote-verification-rs/src/lib.rs +++ b/crates/teepot-tee-quote-verification-rs/src/lib.rs @@ -39,7 +39,7 @@ //! This is a safe wrapper for **sgx-dcap-quoteverify-sys**. use serde::{Deserialize, Serialize}; -use std::{marker::PhantomData, mem, ops::Deref, slice}; +use std::{marker::PhantomData, ops::Deref, slice}; use intel_tee_quote_verification_sys as qvl_sys; pub use qvl_sys::{ @@ -320,43 +320,6 @@ pub struct Collateral { pub qe_identity: Box<[u8]>, } -impl TryFrom<&sgx_ql_qve_collateral_t> for Collateral { - type Error = (); - - fn try_from(value: &sgx_ql_qve_collateral_t) -> Result { - fn to_boxed_slice(p: *mut ::std::os::raw::c_char, size: u32) -> Result, ()> { - if p.is_null() { - return Err(()); - } - Ok(Box::from(unsafe { - slice::from_raw_parts(p as _, size as _) - })) - } - - Ok(Collateral { - major_version: unsafe { value.__bindgen_anon_1.__bindgen_anon_1.major_version }, - minor_version: unsafe { value.__bindgen_anon_1.__bindgen_anon_1.minor_version }, - tee_type: value.tee_type, - pck_crl_issuer_chain: to_boxed_slice( - value.pck_crl_issuer_chain, - value.pck_crl_issuer_chain_size, - )?, - root_ca_crl: to_boxed_slice(value.root_ca_crl, value.root_ca_crl_size)?, - pck_crl: to_boxed_slice(value.pck_crl, value.pck_crl_size)?, - tcb_info_issuer_chain: to_boxed_slice( - value.tcb_info_issuer_chain, - value.tcb_info_issuer_chain_size, - )?, - tcb_info: to_boxed_slice(value.tcb_info, value.tcb_info_size)?, - qe_identity_issuer_chain: to_boxed_slice( - value.qe_identity_issuer_chain, - value.qe_identity_issuer_chain_size, - )?, - qe_identity: to_boxed_slice(value.qe_identity, value.qe_identity_size)?, - }) - } -} - // referential struct struct SgxQlQveCollateralT<'a> { inner: sgx_ql_qve_collateral_t, @@ -424,6 +387,55 @@ impl Deref for SgxQlQveCollateralT<'_> { /// - *SGX_QL_ERROR_UNEXPECTED* /// pub fn tee_qv_get_collateral(quote: &[u8]) -> Result { + fn try_into_collateral( + buf: *const sgx_ql_qve_collateral_t, + buf_len: u32, + ) -> Result { + fn try_into_boxed_slice( + p: *mut ::std::os::raw::c_char, + size: u32, + ) -> Result, quote3_error_t> { + if p.is_null() || !p.is_aligned() { + return Err(quote3_error_t::SGX_QL_ERROR_MAX); + } + Ok(Box::from(unsafe { + slice::from_raw_parts(p as _, size as _) + })) + } + + if buf.is_null() + || (buf_len as usize) < size_of::() + || !buf.is_aligned() + { + return Err(quote3_error_t::SGX_QL_ERROR_MAX); + } + + // SAFETY: buf is not null, buf_len is not zero, and buf is aligned. + let collateral = unsafe { *buf }; + + Ok(Collateral { + major_version: unsafe { collateral.__bindgen_anon_1.__bindgen_anon_1.major_version }, + minor_version: unsafe { collateral.__bindgen_anon_1.__bindgen_anon_1.minor_version }, + tee_type: collateral.tee_type, + pck_crl_issuer_chain: try_into_boxed_slice( + collateral.pck_crl_issuer_chain, + collateral.pck_crl_issuer_chain_size, + )?, + root_ca_crl: try_into_boxed_slice(collateral.root_ca_crl, collateral.root_ca_crl_size)?, + pck_crl: try_into_boxed_slice(collateral.pck_crl, collateral.pck_crl_size)?, + tcb_info_issuer_chain: try_into_boxed_slice( + collateral.tcb_info_issuer_chain, + collateral.tcb_info_issuer_chain_size, + )?, + tcb_info: try_into_boxed_slice(collateral.tcb_info, collateral.tcb_info_size)?, + qe_identity_issuer_chain: try_into_boxed_slice( + collateral.qe_identity_issuer_chain, + collateral.qe_identity_issuer_chain_size, + )?, + qe_identity: try_into_boxed_slice(collateral.qe_identity, collateral.qe_identity_size)?, + }) + } + let mut buf = std::ptr::null_mut(); let mut buf_len = 0u32; @@ -431,16 +443,7 @@ pub fn tee_qv_get_collateral(quote: &[u8]) -> Result qvl_sys::tee_qv_get_collateral(quote.as_ptr(), quote.len() as u32, &mut buf, &mut buf_len) } { quote3_error_t::SGX_QL_SUCCESS => { - assert!(!buf.is_null()); - assert!(buf_len > 0); - assert_eq!( - (buf as usize) % mem::align_of::(), - 0 - ); - // SAFETY: buf is not null, buf_len is not zero, and buf is aligned. - let orig_collateral = &unsafe { *(buf as *const sgx_ql_qve_collateral_t) }; - let collateral = - Collateral::try_from(orig_collateral).map_err(|_| quote3_error_t::SGX_QL_ERROR_MAX); + let collateral = try_into_collateral(buf as _, buf_len); match unsafe { tee_qv_free_collateral(buf) } { quote3_error_t::SGX_QL_SUCCESS => collateral, From dc1e756ec66f3960d045a05c36548aa2fee74060 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 8 Jan 2025 08:59:23 +0100 Subject: [PATCH 026/114] feat(tdx): add nix build for TDX google VMs Signed-off-by: Harald Hoyer --- README.md | 26 +++- assets/gcloud-deploy.sh | 45 ++++++ flake.nix | 4 +- lib/default.nix | 3 + lib/nixos-generate.nix | 33 +++++ packages/tdx_google/configuration.nix | 180 +++++++++++++++++++++++ packages/tdx_google/default.nix | 15 ++ packages/tdx_google/google.nix | 33 +++++ packages/tdx_google/verity.nix | 127 ++++++++++++++++ shells/teepot/default.nix | 16 +- systems/x86_64-linux/tdxtest/default.nix | 172 ++++++++++++++++++++++ 11 files changed, 638 insertions(+), 16 deletions(-) create mode 100755 assets/gcloud-deploy.sh create mode 100644 lib/default.nix create mode 100644 lib/nixos-generate.nix create mode 100644 packages/tdx_google/configuration.nix create mode 100644 packages/tdx_google/default.nix create mode 100644 packages/tdx_google/google.nix create mode 100644 packages/tdx_google/verity.nix create mode 100644 systems/x86_64-linux/tdxtest/default.nix diff --git a/README.md b/README.md index b1b5319..8c18eb5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,5 @@ # teepot -Key Value store in a TEE with Remote Attestation for Authentication - -## Introduction - -This project is a key-value store that runs in a Trusted Execution Environment (TEE) and uses Remote Attestation for -Authentication. -The key-value store is implemented using Hashicorp Vault running in an Intel SGX enclave via the Gramine runtime. - ## Parts of this project - `teepot`: The main rust crate that abstracts TEEs and key-value stores. @@ -22,6 +14,18 @@ The key-value store is implemented using Hashicorp Vault running in an Intel SGX - `verify-attestation`: A client utility that verifies the attestation of an enclave. - `tee-key-preexec`: A pre-exec utility that generates a p256 secret key and passes it as an environment variable to the enclave along with the attestation quote containing the hash of the public key. +- `tdx_google`: A base VM running on Google Cloud TDX. It receives a container URL via the instance metadata, + measures the sha384 of the URL to RTMR3 and launches the container. +- `tdx-extend`: A utility to extend an RTMR register with a hash value. +- `rtmr-calc`: A utility to calculate RTMR1 and RTMR2 from a GPT disk, the linux kernel, the linux initrd + and a UKI (unified kernel image). +- `sha384-extend`: A utility to calculate RTMR registers after extending them with a digest. + +## Vault + +Part of this project is a key-value store that runs in a Trusted Execution Environment (TEE) and uses Remote Attestation +for Authentication. The key-value store is implemented using Hashicorp Vault running in an Intel SGX enclave via the +Gramine runtime. ## Development @@ -96,3 +100,9 @@ Attributes: isv_svn: 0 debug_enclave: False ``` + +### TDX VM testing + +```shell +nixos-rebuild -L --flake .#tdxtest build-vm && ./result/bin/run-tdxtest-vm +``` diff --git a/assets/gcloud-deploy.sh b/assets/gcloud-deploy.sh new file mode 100755 index 0000000..b2f8a22 --- /dev/null +++ b/assets/gcloud-deploy.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Matter Labs +# + +set -ex + +NO=${NO:-1} + +nix build -L .#tdx_google + +gsutil cp result/tdx_base_1.vmdk gs://tdx_vms/ + +gcloud migration vms image-imports create \ + --location=us-central1 \ + --target-project=tdx-pilot \ + --project=tdx-pilot \ + --skip-os-adaptation \ + --source-file=gs://tdx_vms/tdx_base_1.vmdk \ + tdx-img-pre-"${NO}" + +gcloud compute instances stop tdx-pilot --zone us-central1-c --project tdx-pilot || : +gcloud compute instances delete tdx-pilot --zone us-central1-c --project tdx-pilot || : + +while gcloud migration vms image-imports list --location=us-central1 --project=tdx-pilot | grep -F RUNNING; do + sleep 1 +done + +gcloud compute images create \ + --project tdx-pilot \ + --guest-os-features=UEFI_COMPATIBLE,TDX_CAPABLE,GVNIC,VIRTIO_SCSI_MULTIQUEUE \ + --storage-location=us-central1 \ + --source-image=tdx-img-pre-"${NO}" \ + tdx-img-f-"${NO}" + +gcloud compute instances create tdx-pilot \ + --machine-type c3-standard-4 --zone us-central1-c \ + --confidential-compute-type=TDX \ + --maintenance-policy=TERMINATE \ + --image-project=tdx-pilot \ + --project tdx-pilot \ + --metadata=container_hub="docker.io",container_image="amd64/hello-world@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57" \ + --image tdx-img-f-"${NO}" diff --git a/flake.nix b/flake.nix index dfff539..0512524 100644 --- a/flake.nix +++ b/flake.nix @@ -25,7 +25,9 @@ }; outputs = inputs: - let src = ./.; in + let + src = ./.; + in inputs.snowfall-lib.mkFlake { inherit inputs; inherit src; diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..6ebd543 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,3 @@ +{ ... }: { + nixosGenerate = import ./nixos-generate.nix; +} diff --git a/lib/nixos-generate.nix b/lib/nixos-generate.nix new file mode 100644 index 0000000..7b4806c --- /dev/null +++ b/lib/nixos-generate.nix @@ -0,0 +1,33 @@ +{ pkgs +, nixosSystem +, formatModule +, system +, specialArgs ? { } +, modules ? [ ] +}: +let + image = nixosSystem { + inherit pkgs specialArgs; + modules = + [ + formatModule + ( + { lib, ... }: { + options = { + fileExtension = lib.mkOption { + type = lib.types.str; + description = "Declare the path of the wanted file in the output directory"; + default = ""; + }; + formatAttr = lib.mkOption { + type = lib.types.str; + description = "Declare the default attribute to build"; + }; + }; + } + ) + ] + ++ modules; + }; +in +image.config.system.build.${image.config.formatAttr} diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix new file mode 100644 index 0000000..c25618c --- /dev/null +++ b/packages/tdx_google/configuration.nix @@ -0,0 +1,180 @@ +{ lib +, modulesPath +, pkgs +, ... +}: { + imports = [ + "${toString modulesPath}/profiles/minimal.nix" + "${toString modulesPath}/profiles/qemu-guest.nix" + ]; + + /* + # SSH login for debugging + services.sshd.enable = true; + networking.firewall.allowedTCPPorts = [ 22 ]; + services.openssh.settings.PermitRootLogin = lib.mkOverride 999 "yes"; + users.users.root.openssh.authorizedKeys.keys = [ + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIDsb/Tr69YN5MQLweWPuJaRGm+h2kOyxfD6sqKEDTIwoAAAABHNzaDo=" + "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBACLgT81iB1iWWVuXq6PdQ5GAAGhaZhSKnveQCvcNnAOZ5WKH80bZShKHyAYzrzbp8IGwLWJcZQ7TqRK+qZdfagAAAAEc3NoOg==" + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAYbUTKpy4QR3s944/hjJ1UK05asFEs/SmWeUbtS0cdA660sT4xHnRfals73FicOoz+uIucJCwn/SCM804j+wtM=" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNsmP15vH8BVKo7bdvIiiEjiQboPGcRPqJK0+bH4jKD" + ]; + */ + + # the container might want to listen on ports + networking.firewall.enable = true; + networking.firewall.allowedTCPPortRanges = [{ from = 1024; to = 65535; }]; + networking.firewall.allowedUDPPortRanges = [{ from = 1024; to = 65535; }]; + + networking.useNetworkd = lib.mkDefault true; + + # don't fill up the logs + networking.firewall.logRefusedConnections = false; + + virtualisation.docker.enable = true; + + systemd.services.docker_start_container = { + description = "The main application container"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "docker.service" ]; + requires = [ "network-online.target" "docker.service" ]; + serviceConfig = { + Type = "exec"; + User = "root"; + }; + path = [ pkgs.curl pkgs.docker pkgs.teepot.teepot.tdx_extend pkgs.coreutils ]; + script = '' + set -eu -o pipefail + : "''${CONTAINER_IMAGE:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_image" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_HUB:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_hub" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_USER:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_user" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_TOKEN:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_token" -H "Metadata-Flavor: Google")}" + + : "''${CONTAINER_IMAGE:?Error: Missing CONTAINER_IMAGE}" + : "''${CONTAINER_HUB:?Error: Missing CONTAINER_HUB}" + + if [[ $CONTAINER_USER ]] && [[ $CONTAINER_TOKEN ]]; then + docker login -u "$CONTAINER_USER" -p "$CONTAINER_TOKEN" "$CONTAINER_HUB" + fi + + docker pull "''${CONTAINER_HUB}/''${CONTAINER_IMAGE}" + DIGEST=$(docker inspect --format '{{.Id}}' "''${CONTAINER_HUB}/''${CONTAINER_IMAGE}") + DIGEST=''${DIGEST#sha256:} + echo "Measuring $DIGEST" >&2 + test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 + exec docker run --init --privileged "sha256:$DIGEST" + ''; + + postStop = lib.mkDefault '' + shutdown --reboot +5 + ''; + }; + + services.prometheus.exporters.node = { + enable = true; + port = 9100; + enabledCollectors = [ + "logind" + "systemd" + ]; + disabledCollectors = [ + "textfile" + ]; + #openFirewall = true; + #firewallFilter = "-i br0 -p tcp -m tcp --dport 9100"; + }; + + environment.systemPackages = with pkgs; [ + teepot.teepot + ]; + + # /var is on tmpfs anyway + services.journald.storage = "volatile"; + + # we can't rely on/trust the hypervisor + services.timesyncd.enable = false; + services.chrony = { + enable = true; + enableNTS = true; + servers = [ + "time.cloudflare.com" + "ntppool1.time.nl" + "ntppool2.time.nl" + ]; + }; + systemd.services."chronyd".after = [ "network-online.target" ]; + + boot.kernelPackages = lib.mkForce pkgs.linuxPackages_6_12; + boot.kernelPatches = [ + { + name = "tdx-rtmr"; + patch = pkgs.fetchurl { + url = "https://github.com/haraldh/linux/commit/12d08008a5c94175e7a7dfcee40dff33431d9033.patch"; + hash = "sha256-sVDhvC3qnXpL5FRxWiQotH7Nl/oqRBQGjJGyhsKeBTA="; + }; + } + ]; + + boot.kernelParams = [ + "console=ttyS0,115200n8" + "random.trust_cpu=on" + ]; + + boot.consoleLogLevel = 7; + + boot.initrd.includeDefaultModules = false; + boot.initrd.availableKernelModules = [ + "tdx_guest" + "nvme" + "sd_mod" + "dm_mod" + "ata_piix" + ]; + + boot.initrd.systemd.enable = lib.mkDefault true; + + services.logind.extraConfig = '' + NAutoVTs=0 + ReserveVT=0 + ''; + + services.dbus.implementation = "broker"; + + boot.initrd.systemd.tpm2.enable = lib.mkForce false; + systemd.tpm2.enable = lib.mkForce false; + + nix.enable = false; # it's a read-only nix store anyway + + security.pam.services.su.forwardXAuth = lib.mkForce false; + + users.mutableUsers = false; + users.allowNoPasswordLogin = true; + + system.stateVersion = lib.version; + system.switch.enable = lib.mkForce false; + + documentation.info.enable = lib.mkForce false; + documentation.nixos.enable = lib.mkForce false; + documentation.man.enable = lib.mkForce false; + documentation.enable = lib.mkForce false; + + services.udisks2.enable = false; # udisks has become too bloated to have in a headless system + + # Get rid of the perl ecosystem to minimize the TCB and disk size + + # Remove perl from activation + system.etc.overlay.enable = lib.mkDefault true; + services.userborn.enable = lib.mkDefault true; + + # Random perl remnants + system.disableInstallerTools = lib.mkForce true; + programs.less.lessopen = lib.mkDefault null; + programs.command-not-found.enable = lib.mkDefault false; + boot.enableContainers = lib.mkForce false; + boot.loader.grub.enable = lib.mkDefault false; + environment.defaultPackages = lib.mkDefault [ ]; + + # Check that the system does not contain a Nix store path that contains the + # string "perl". + system.forbiddenDependenciesRegexes = [ "perl" ]; +} diff --git a/packages/tdx_google/default.nix b/packages/tdx_google/default.nix new file mode 100644 index 0000000..5044fd7 --- /dev/null +++ b/packages/tdx_google/default.nix @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ lib +, pkgs +, system +, ... +}: lib.teepot.nixosGenerate { + inherit (lib) nixosSystem; + inherit system pkgs; + modules = [ + ./configuration.nix + ./google.nix + ]; + formatModule = ./verity.nix; +} diff --git a/packages/tdx_google/google.nix b/packages/tdx_google/google.nix new file mode 100644 index 0000000..2684704 --- /dev/null +++ b/packages/tdx_google/google.nix @@ -0,0 +1,33 @@ +{ lib +, pkgs +, modulesPath +, ... +}: { + imports = [ + "${toString modulesPath}/profiles/headless.nix" + ]; + + system.image.id = "tdx_base"; + + boot.initrd.kernelModules = [ "virtio_scsi" ]; + boot.kernelModules = [ "virtio_pci" "virtio_net" ]; + + # Force getting the hostname from Google Compute. + networking.hostName = lib.mkForce ""; + + # Configure default metadata hostnames + networking.extraHosts = '' + 169.254.169.254 metadata.google.internal metadata + ''; + + networking.timeServers = [ "metadata.google.internal" ]; + + environment.etc."sysctl.d/60-gce-network-security.conf".source = "${pkgs.google-guest-configs}/etc/sysctl.d/60-gce-network-security.conf"; + + networking.usePredictableInterfaceNames = false; + + # GC has 1460 MTU + networking.interfaces.eth0.mtu = 1460; + + boot.extraModprobeConfig = lib.readFile "${pkgs.google-guest-configs}/etc/modprobe.d/gce-blacklist.conf"; +} diff --git a/packages/tdx_google/verity.nix b/packages/tdx_google/verity.nix new file mode 100644 index 0000000..316fbb7 --- /dev/null +++ b/packages/tdx_google/verity.nix @@ -0,0 +1,127 @@ +{ config +, pkgs +, lib +, modulesPath +, ... +}: +let + inherit (config.image.repart.verityStore) partitionIds; +in +{ + imports = [ + "${toString modulesPath}/image/repart.nix" + ]; + + fileSystems = { + "/" = { + fsType = "tmpfs"; + options = [ "mode=0755" "noexec" ]; + }; + + "/dev/shm" = { + fsType = "tmpfs"; + options = [ "defaults" "nosuid" "noexec" "nodev" "size=2G" ]; + }; + + "/run" = { + fsType = "tmpfs"; + options = [ "defaults" "mode=0755" "nosuid" "noexec" "nodev" "size=512M" ]; + }; + + "/usr" = { + device = "/dev/mapper/usr"; + # explicitly mount it read-only otherwise systemd-remount-fs will fail + options = [ "ro" ]; + fsType = config.image.repart.partitions.${partitionIds.store}.repartConfig.Format; + }; + + # bind-mount the store + "/nix/store" = { + device = "/usr/nix/store"; + options = [ "bind" ]; + }; + }; + + image.repart = { + verityStore = { + enable = true; + ukiPath = "/EFI/BOOT/BOOTx64.EFI"; + }; + + partitions = { + ${partitionIds.esp} = { + # the UKI is injected into this partition by the verityStore module + repartConfig = { + Type = "esp"; + Format = "vfat"; + SizeMinBytes = "64M"; + }; + }; + ${partitionIds.store-verity}.repartConfig = { + Minimize = "best"; + }; + ${partitionIds.store}.repartConfig = { + Minimize = "best"; + Format = "squashfs"; + }; + }; + }; + + boot = { + loader.grub.enable = false; + initrd.systemd.enable = true; + }; + + system.image = { + id = lib.mkDefault "nixos-appliance"; + version = "1"; + }; + + # don't create /usr/bin/env + # this would require some extra work on read-only /usr + # and it is not a strict necessity + system.activationScripts.usrbinenv = lib.mkForce ""; + + boot.kernelParams = [ + "systemd.verity_usr_options=panic-on-corruption" + "panic=30" + "boot.panic_on_fail" # reboot the machine upon fatal boot issues + "lockdown=1" + ]; + + system.build.vmdk_verity = + config.system.build.finalImage.overrideAttrs + ( + finalAttrs: previousAttrs: + let + kernel = config.boot.uki.settings.UKI.Linux; + ukifile = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; + in + { + nativeBuildInputs = + previousAttrs.nativeBuildInputs + ++ [ + pkgs.qemu + pkgs.teepot.teepot.rtmr_calc + ]; + + postInstall = '' + qemu-img convert -f raw -O vmdk \ + $out/${config.image.repart.imageFileBasename}.raw \ + $out/${config.image.repart.imageFileBasename}.vmdk + qemu-img info \ + $out/${config.image.repart.imageFileBasename}.vmdk + echo "kernel: ${kernel}" + echo "uki: ${ukifile}" + rtmr-calc \ + --image $out/${config.image.repart.imageFileBasename}.raw \ + --bootefi "${ukifile}" \ + --kernel "${kernel}" | tee $out/${config.image.repart.imageFileBasename}_rtmr.json + rm -vf $out/${config.image.repart.imageFileBasename}.raw + ''; + } + ); + + formatAttr = lib.mkForce "vmdk_verity"; + fileExtension = lib.mkForce ".raw"; +} diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index effb413..67bedf6 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -1,16 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs { lib +, pkgs , mkShell , teepot -, dive -, taplo -, vault -, cargo-release , nixsgx , stdenv , teepotCrate -, pkg-config }: let toolchain_with_src = (teepotCrate.rustVersion.override { @@ -20,20 +16,26 @@ in mkShell { inputsFrom = [ teepot.teepot ]; - nativeBuildInputs = [ + nativeBuildInputs = with pkgs; [ toolchain_with_src pkg-config teepotCrate.rustPlatform.bindgenHook ]; - packages = [ + packages = with pkgs; [ dive taplo vault cargo-release + google-cloud-sdk-gce + azure-cli + kubectl + kubectx + k9s ]; TEE_LD_LIBRARY_PATH = lib.makeLibraryPath [ + pkgs.curl nixsgx.sgx-dcap nixsgx.sgx-dcap.quote_verify nixsgx.sgx-dcap.default_qpl diff --git a/systems/x86_64-linux/tdxtest/default.nix b/systems/x86_64-linux/tdxtest/default.nix new file mode 100644 index 0000000..d95dce5 --- /dev/null +++ b/systems/x86_64-linux/tdxtest/default.nix @@ -0,0 +1,172 @@ +{ config +, pkgs +, lib +, ... +}: { + imports = [ + ./../../../packages/tdx_google/configuration.nix + ]; + + systemd.services.docker_start_container = { + environment = { + CONTAINER_IMAGE = "amd64/hello-world@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57"; + CONTAINER_HUB = "docker.io"; + CONTAINER_USER = ""; + CONTAINER_TOKEN = ""; + }; + + postStop = '' + : + ''; + }; + + console.enable = true; + + services.getty.autologinUser = lib.mkOverride 999 "root"; + + networking.firewall.allowedTCPPorts = [ 22 ]; + services.sshd.enable = true; + services.openssh.settings.PermitRootLogin = lib.mkOverride 999 "yes"; + users.users.root.openssh.authorizedKeys.keys = [ + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIDsb/Tr69YN5MQLweWPuJaRGm+h2kOyxfD6sqKEDTIwoAAAABHNzaDo=" + "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBACLgT81iB1iWWVuXq6PdQ5GAAGhaZhSKnveQCvcNnAOZ5WKH80bZShKHyAYzrzbp8IGwLWJcZQ7TqRK+qZdfagAAAAEc3NoOg==" + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAYbUTKpy4QR3s944/hjJ1UK05asFEs/SmWeUbtS0cdA660sT4xHnRfals73FicOoz+uIucJCwn/SCM804j+wtM=" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNsmP15vH8BVKo7bdvIiiEjiQboPGcRPqJK0+bH4jKD" + ]; + + + fileSystems = { + "/" = { + fsType = "ext4"; + device = "/dev/disk/by-id/test"; + options = [ "mode=0755" ]; + }; + }; + + boot = { + loader.grub.enable = false; + initrd.systemd.enable = true; + }; + + virtualisation.vmVariant = { + # following configuration is added only when building VM with build-vm + virtualisation = { + memorySize = 2048; # Use 2048MiB memory. + cores = 4; + }; + }; + + /* + services.loki = { + enable = true; + configuration = { + server.http_listen_port = 3030; + auth_enabled = false; + analytics.reporting_enabled = false; + + ingester = { + lifecycler = { + address = "127.0.0.1"; + ring = { + kvstore = { + store = "inmemory"; + }; + replication_factor = 1; + }; + }; + chunk_idle_period = "1h"; + max_chunk_age = "1h"; + chunk_target_size = 999999; + chunk_retain_period = "30s"; + }; + + schema_config = { + configs = [ + { + from = "2024-04-25"; + store = "tsdb"; + object_store = "filesystem"; + schema = "v13"; + index = { + prefix = "index_"; + period = "24h"; + }; + } + ]; + }; + + storage_config = { + tsdb_shipper = { + active_index_directory = "/var/lib/loki/tsdb-shipper-active"; + cache_location = "/var/lib/loki/tsdb-shipper-cache"; + cache_ttl = "24h"; + }; + + filesystem = { + directory = "/var/lib/loki/chunks"; + }; + }; + + limits_config = { + reject_old_samples = true; + reject_old_samples_max_age = "168h"; + volume_enabled = true; + }; + + + table_manager = { + retention_deletes_enabled = false; + retention_period = "0s"; + }; + + compactor = { + working_directory = "/var/lib/loki"; + compactor_ring = { + kvstore = { + store = "inmemory"; + }; + }; + }; + }; + }; + + services.promtail = { + enable = true; + configuration = { + server = { + http_listen_port = 3031; + grpc_listen_port = 0; + }; + clients = [ + { + url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push"; + } + ]; + scrape_configs = [{ + job_name = "journal"; + journal = { + max_age = "12h"; + labels = { + job = "systemd-journal"; + }; + }; + relabel_configs = [ + { + source_labels = [ "__journal__systemd_unit" ]; + target_label = "systemd_unit"; + } + { + source_labels = [ "__journal__hostname" ]; + target_label = "nodename"; + } + { + source_labels = [ "__journal_container_id" ]; + target_label = "container_id"; + } + ]; + }]; + }; + # extraFlags + }; + */ +} From 99037ceb6c05a3ad3773ec41f883e4e6a761dfa8 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 15 Jan 2025 15:48:21 +0100 Subject: [PATCH 027/114] feat(tee-key-preexec): add test container for tee-key-preexec Signed-off-by: Harald Hoyer --- .../default.nix | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/container-tee-key-preexec-dcap/default.nix diff --git a/packages/container-tee-key-preexec-dcap/default.nix b/packages/container-tee-key-preexec-dcap/default.nix new file mode 100644 index 0000000..b49ff69 --- /dev/null +++ b/packages/container-tee-key-preexec-dcap/default.nix @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ teepot +, pkgs +, bash +, coreutils +, container-name ? "teepot-key-preexec-dcap" +, tag ? null +}: let + entrypoint = "${bash}/bin/bash"; +in +pkgs.lib.tee.sgxGramineContainer { + name = container-name; + inherit tag entrypoint; + + packages = [ teepot.teepot.tee_key_preexec coreutils bash ]; + + manifest = { + loader = { + argv = [ + entrypoint + "-c" + ("${teepot.teepot.tee_key_preexec}/bin/tee-key-preexec -- bash -c " + + "'echo \"SIGNING_KEY=$SIGNING_KEY\"; echo \"TEE_TYPE=$TEE_TYPE\";exec base64 \"$ATTESTATION_QUOTE_FILE_PATH\";'") + ]; + + log_level = "error"; + env = { + RUST_BACKTRACE = "1"; + RUST_LOG = "trace"; + }; + }; + sgx = { + edmm_enable = true; + max_threads = 2; + }; + }; +} From 2d04ba050893c7490676d4f8bb25474d2bd91b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20B=C4=99za?= Date: Fri, 20 Dec 2024 12:19:19 +0100 Subject: [PATCH 028/114] feat(tee-key-preexec): add support for Solidity-compatible pubkey in report_data This PR is part of the effort to implement on-chain TEE proof verification. This PR goes hand in hand with https://github.com/matter-labs/zksync-era/pull/3414. --- Cargo.lock | 5 + Cargo.toml | 1 + bin/tee-key-preexec/Cargo.toml | 1 + bin/tee-key-preexec/src/main.rs | 39 +- bin/verify-attestation/Cargo.toml | 1 + bin/verify-attestation/src/main.rs | 32 +- .../src/verification.rs | 78 ++-- crates/teepot/Cargo.toml | 4 +- crates/teepot/src/ethereum/mod.rs | 86 ++++ crates/teepot/src/lib.rs | 2 + crates/teepot/src/prover/mod.rs | 6 + crates/teepot/src/prover/reportdata.rs | 232 +++++++++++ crates/teepot/tests/sgx_quote_verification.rs | 384 +++++++++++++++++- 13 files changed, 828 insertions(+), 43 deletions(-) create mode 100644 crates/teepot/src/ethereum/mod.rs create mode 100644 crates/teepot/src/prover/mod.rs create mode 100644 crates/teepot/src/prover/reportdata.rs diff --git a/Cargo.lock b/Cargo.lock index c447712..b770552 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5214,6 +5214,7 @@ version = "0.3.0" dependencies = [ "anyhow", "clap 4.5.23", + "hex", "rand", "secp256k1 0.29.1", "teepot", @@ -5324,10 +5325,12 @@ dependencies = [ "rand", "rsa", "rustls", + "secp256k1 0.29.1", "serde", "serde_json", "serde_with 3.11.0", "sha2", + "sha3", "signature 2.2.0", "tdx-attest-rs", "teepot-tee-quote-verification-rs", @@ -5341,6 +5344,7 @@ dependencies = [ "webpki-roots", "x509-cert", "zeroize", + "zksync_basic_types", ] [[package]] @@ -6031,6 +6035,7 @@ dependencies = [ "clap 4.5.23", "hex", "secp256k1 0.29.1", + "sha3", "teepot", "zksync_basic_types", ] diff --git a/Cargo.toml b/Cargo.toml index 31bbed1..54564d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" serde_with = { version = "3.8", features = ["base64", "hex"] } sha2 = "0.10.8" +sha3 = "0.10.8" signature = "2.2.0" tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } teepot = { path = "crates/teepot" } diff --git a/bin/tee-key-preexec/Cargo.toml b/bin/tee-key-preexec/Cargo.toml index e5a62cc..20d3e37 100644 --- a/bin/tee-key-preexec/Cargo.toml +++ b/bin/tee-key-preexec/Cargo.toml @@ -12,6 +12,7 @@ repository.workspace = true [dependencies] anyhow.workspace = true clap.workspace = true +hex.workspace = true rand.workspace = true secp256k1.workspace = true teepot.workspace = true diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 70be9c4..02b0cc2 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -8,9 +8,12 @@ use anyhow::{Context, Result}; use clap::Parser; -use secp256k1::{rand, Keypair, PublicKey, Secp256k1, SecretKey}; +use core::convert::AsRef; +use secp256k1::{rand, Secp256k1}; use std::{ffi::OsString, os::unix::process::CommandExt, process::Command}; -use teepot::quote::get_quote; +use teepot::{ + ethereum::public_key_to_ethereum_address, prover::reportdata::ReportDataV1, quote::get_quote, +}; use tracing::error; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; @@ -37,14 +40,13 @@ fn main_with_error() -> Result<()> { tracing::subscriber::set_global_default(subscriber).context("Failed to set logger")?; let args = Args::parse(); - let mut rng = rand::thread_rng(); let secp = Secp256k1::new(); - let keypair = Keypair::new(&secp, &mut rng); - let signing_key = SecretKey::from_keypair(&keypair); - let verifying_key = PublicKey::from_keypair(&keypair); - let verifying_key_bytes = verifying_key.serialize(); - let tee_type = match get_quote(verifying_key_bytes.as_ref()) { + let (signing_key, verifying_key) = secp.generate_keypair(&mut rng); + let ethereum_address = public_key_to_ethereum_address(&verifying_key); + let report_data = ReportDataV1 { ethereum_address }; + let report_data_bytes: [u8; 64] = report_data.into(); + let tee_type = match get_quote(report_data_bytes.as_ref()) { Ok((tee_type, quote)) => { // save quote to file std::fs::write(TEE_QUOTE_FILE, quote)?; @@ -85,3 +87,24 @@ fn main() -> Result<()> { } ret } + +#[cfg(test)] +mod tests { + use secp256k1::{PublicKey, Secp256k1, SecretKey}; + + use super::*; + + #[test] + fn test_public_key_to_address() { + let secp = Secp256k1::new(); + let secret_key_bytes = + hex::decode("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3") + .unwrap(); + let secret_key = SecretKey::from_slice(&secret_key_bytes).unwrap(); + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + let expected_address = hex::decode("627306090abaB3A6e1400e9345bC60c78a8BEf57").unwrap(); + let address = public_key_to_ethereum_address(&public_key); + + assert_eq!(address, expected_address.as_slice()); + } +} diff --git a/bin/verify-attestation/Cargo.toml b/bin/verify-attestation/Cargo.toml index ff473d9..5a7c276 100644 --- a/bin/verify-attestation/Cargo.toml +++ b/bin/verify-attestation/Cargo.toml @@ -12,5 +12,6 @@ anyhow.workspace = true clap.workspace = true hex.workspace = true secp256k1.workspace = true +sha3.workspace = true teepot.workspace = true zksync_basic_types.workspace = true diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index d799462..8ba0c2b 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -5,10 +5,13 @@ use anyhow::{Context, Result}; use clap::{Args, Parser, Subcommand}; -use secp256k1::{ecdsa::Signature, Message, PublicKey}; +use core::convert::TryInto; +use hex::encode; +use secp256k1::{Message, PublicKey}; use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; use teepot::{ client::TcbLevel, + ethereum::recover_signer, quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, }; use zksync_basic_types::H256; @@ -87,14 +90,25 @@ fn verify_signature( let reportdata = "e_verification_result.quote.get_report_data(); 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"); - } + let signature_bytes: &[u8] = &fs::read(&signature_args.signature_file)?; + let ethereum_address_from_quote = "e_verification_result.quote.get_report_data()[..20]; + let root_hash_bytes = signature_args.root_hash.as_bytes(); + let root_hash_msg = Message::from_digest_slice(root_hash_bytes)?; + let ethereum_address_from_signature = + recover_signer(&signature_bytes.try_into()?, &root_hash_msg)?; + let verification_successful = ethereum_address_from_signature == ethereum_address_from_quote; + + println!( + "Signature '{}' {}. Ethereum address from attestation quote: {}. Ethereum address from signature: {}.", + encode(signature_bytes), + if verification_successful { + "verified successfully" + } else { + "verification failed" + }, + encode(ethereum_address_from_quote), + encode(ethereum_address_from_signature) + ); Ok(()) } diff --git a/bin/verify-era-proof-attestation/src/verification.rs b/bin/verify-era-proof-attestation/src/verification.rs index b389500..3c46fe6 100644 --- a/bin/verify-era-proof-attestation/src/verification.rs +++ b/bin/verify-era-proof-attestation/src/verification.rs @@ -2,11 +2,13 @@ // Copyright (c) 2023-2024 Matter Labs use crate::{args::AttestationPolicyArgs, client::JsonRpcClient}; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use hex::encode; -use secp256k1::{constants::PUBLIC_KEY_SIZE, ecdsa::Signature, Message, PublicKey}; +use secp256k1::{ecdsa::Signature, Message}; use teepot::{ client::TcbLevel, + ethereum::recover_signer, + prover::reportdata::ReportData, quote::{ error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult, Report, @@ -15,6 +17,51 @@ use teepot::{ use tracing::{debug, info, warn}; use zksync_basic_types::{L1BatchNumber, H256}; +struct TeeProof { + report: ReportData, + root_hash: H256, + signature: Vec, +} + +impl TeeProof { + pub fn new(report: ReportData, root_hash: H256, signature: Vec) -> Self { + Self { + report, + root_hash, + signature, + } + } + + pub fn verify(&self) -> Result { + match &self.report { + ReportData::V0(report) => { + let signature = Signature::from_compact(&self.signature)?; + let root_hash_msg = Message::from_digest_slice(&self.root_hash.0)?; + Ok(signature.verify(&root_hash_msg, &report.pubkey).is_ok()) + } + ReportData::V1(report) => { + let ethereum_address_from_report = report.ethereum_address; + let root_hash_msg = Message::from_digest_slice(self.root_hash.as_bytes())?; + let signature_bytes: [u8; 65] = self + .signature + .clone() + .try_into() + .map_err(|e| anyhow!("{:?}", e))?; + let ethereum_address_from_signature = + recover_signer(&signature_bytes, &root_hash_msg)?; + debug!( + "Root hash: {}. Ethereum address from the attestation quote: {}. Ethereum address from the signature: {}.", + self.root_hash, + encode(ethereum_address_from_report), + encode(ethereum_address_from_signature), + ); + Ok(ethereum_address_from_signature == ethereum_address_from_report) + } + ReportData::Unknown(_) => Ok(false), + } + } +} + pub async fn verify_batch_proof( quote_verification_result: &QuoteVerificationResult, attestation_policy: &AttestationPolicyArgs, @@ -26,23 +73,12 @@ pub async fn verify_batch_proof( return Ok(false); } - let batch_no = batch_number.0; - - let public_key = PublicKey::from_slice( - "e_verification_result.quote.get_report_data()[..PUBLIC_KEY_SIZE], - )?; - debug!(batch_no, "public key: {}", public_key); - let root_hash = node_client.get_root_hash(batch_number).await?; - debug!(batch_no, "root hash: {}", root_hash); - - let is_verified = verify_signature(signature, public_key, root_hash)?; - if is_verified { - info!(batch_no, signature = %encode(signature), "Signature verified successfully."); - } else { - warn!(batch_no, signature = %encode(signature), "Failed to verify signature!"); - } - Ok(is_verified) + let report_data_bytes = quote_verification_result.quote.get_report_data(); + let report_data = ReportData::try_from(report_data_bytes)?; + let tee_proof = TeeProof::new(report_data, root_hash, signature.to_vec()); + let verification_successful = tee_proof.verify().is_ok(); + Ok(verification_successful) } pub fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { @@ -85,12 +121,6 @@ pub fn log_quote_verification_summary(quote_verification_result: &QuoteVerificat ); } -fn verify_signature(signature: &[u8], public_key: PublicKey, root_hash: H256) -> Result { - let signature = Signature::from_compact(signature)?; - let root_hash_msg = Message::from_digest_slice(&root_hash.0)?; - Ok(signature.verify(&root_hash_msg, &public_key).is_ok()) -} - fn is_quote_matching_policy( attestation_policy: &AttestationPolicyArgs, quote_verification_result: &QuoteVerificationResult, diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index df20004..3b3b6b8 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -32,10 +32,12 @@ pkcs8.workspace = true rand.workspace = true rsa.workspace = true rustls.workspace = true +secp256k1 = { workspace = true, features = ["recovery"] } serde.workspace = true serde_json.workspace = true serde_with.workspace = true sha2.workspace = true +sha3.workspace = true signature.workspace = true tdx-attest-rs.workspace = true thiserror.workspace = true @@ -47,8 +49,8 @@ x509-cert.workspace = true zeroize.workspace = true [dev-dependencies] -anyhow.workspace = true base64.workspace = true testaso.workspace = true tokio.workspace = true tracing-test.workspace = true +zksync_basic_types.workspace = true diff --git a/crates/teepot/src/ethereum/mod.rs b/crates/teepot/src/ethereum/mod.rs new file mode 100644 index 0000000..a8ab878 --- /dev/null +++ b/crates/teepot/src/ethereum/mod.rs @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2024 Matter Labs + +//! Ethereum-specific helper functions for on-chain verification of Intel SGX attestation. + +use anyhow::Result; +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId}, + Message, PublicKey, SECP256K1, +}; +use sha3::{Digest, Keccak256}; + +/// Equivalent to the ecrecover precompile, ensuring that the signatures we produce off-chain +/// can be recovered on-chain. +pub fn recover_signer(sig: &[u8; 65], root_hash: &Message) -> Result<[u8; 20]> { + let sig = RecoverableSignature::from_compact( + &sig[0..64], + RecoveryId::from_i32(sig[64] as i32 - 27)?, + )?; + let public = SECP256K1.recover_ecdsa(root_hash, &sig)?; + Ok(public_key_to_ethereum_address(&public)) +} + +/// Converts a public key into an Ethereum address by hashing the encoded public key with Keccak256. +pub fn public_key_to_ethereum_address(public: &PublicKey) -> [u8; 20] { + let public_key_bytes = public.serialize_uncompressed(); + + // Skip the first byte (0x04) which indicates uncompressed key + let hash: [u8; 32] = Keccak256::digest(&public_key_bytes[1..]).into(); + + // Take the last 20 bytes of the hash to get the Ethereum address + let mut address = [0u8; 20]; + address.copy_from_slice(&hash[12..]); + address +} + +#[cfg(test)] +mod tests { + use secp256k1::{Secp256k1, SecretKey}; + use zksync_basic_types::H256; + + use super::*; + + /// Signs the message in Ethereum-compatible format for on-chain verification. + fn sign_message(sec: &SecretKey, message: Message) -> Result<[u8; 65]> { + let s = SECP256K1.sign_ecdsa_recoverable(&message, sec); + let (rec_id, data) = s.serialize_compact(); + + let mut signature = [0u8; 65]; + signature[..64].copy_from_slice(&data); + // as defined in the Ethereum Yellow Paper (Appendix F) + // https://ethereum.github.io/yellowpaper/paper.pdf + signature[64] = 27 + rec_id.to_i32() as u8; + + Ok(signature) + } + + #[test] + fn recover() { + // Decode the sample secret key, generate the public key, and derive the Ethereum address + // from the public key + let secp = Secp256k1::new(); + let secret_key_bytes = + hex::decode("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3") + .unwrap(); + let secret_key = SecretKey::from_slice(&secret_key_bytes).unwrap(); + let public_key = PublicKey::from_secret_key(&secp, &secret_key); + let expected_address = hex::decode("627306090abaB3A6e1400e9345bC60c78a8BEf57").unwrap(); + let address = public_key_to_ethereum_address(&public_key); + + assert_eq!(address, expected_address.as_slice()); + + // Generate a random root hash, create a message from the hash, and sign the message using + // the secret key + let root_hash = H256::random(); + let root_hash_bytes = root_hash.as_bytes(); + let msg_to_sign = Message::from_digest_slice(root_hash_bytes).unwrap(); + let signature = sign_message(&secret_key, msg_to_sign).unwrap(); + + // Recover the signer's Ethereum address from the signature and the message, and verify it + // matches the expected address + let proof_addr = recover_signer(&signature, &msg_to_sign).unwrap(); + + assert_eq!(proof_addr, expected_address.as_slice()); + } +} diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 2d9f7cc..8f73489 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -7,8 +7,10 @@ #![deny(clippy::all)] pub mod client; +pub mod ethereum; pub mod json; pub mod log; +pub mod prover; pub mod quote; pub mod server; pub mod sgx; diff --git a/crates/teepot/src/prover/mod.rs b/crates/teepot/src/prover/mod.rs new file mode 100644 index 0000000..d7b3e63 --- /dev/null +++ b/crates/teepot/src/prover/mod.rs @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Common functionality for TEE provers and verifiers. + +pub mod reportdata; diff --git a/crates/teepot/src/prover/reportdata.rs b/crates/teepot/src/prover/reportdata.rs new file mode 100644 index 0000000..d9665a4 --- /dev/null +++ b/crates/teepot/src/prover/reportdata.rs @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024 Matter Labs + +//! Versioning of Intel SGX/TDX quote's report data for TEE prover and verifier. + +use core::convert::Into; + +use anyhow::{anyhow, Result}; +use secp256k1::{constants::PUBLIC_KEY_SIZE, PublicKey}; + +/// Report data length for Intel SGX/TDX. +const REPORT_DATA_LENGTH: usize = 64; + +/// Ethereum address length. +const ETHEREUM_ADDR_LENGTH: usize = 20; + +/// Report data version. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ReportData { + /// Legacy version of report data that was initially not intended to be versioned. + /// The report_data was on-chain incompatible and consisted of a compressed ECDSA public key. + /// + /// +-------------------------------------+--------------------------------+------------------+ + /// | compressed ECDSA pubkey (33 bytes) | zeroes (30 bytes) | version (1 byte) | + /// +-------------------------------------+--------------------------------+------------------+ + V0(ReportDataV0), + /// Latest version of report data compatible with on-chain verification. + /// + /// +--------------------------+-------------------------------------------+------------------+ + /// | Ethereum addr (20 bytes) | zeros (43 bytes) | version (1 byte) | + /// +--------------------------+-------------------------------------------+------------------+ + V1(ReportDataV1), + /// Unknown version of report data. + Unknown(Vec), +} + +fn report_data_to_bytes(data: &[u8], version: u8) -> [u8; REPORT_DATA_LENGTH] { + let mut bytes = [0u8; REPORT_DATA_LENGTH]; + bytes[..data.len()].copy_from_slice(data); + bytes[REPORT_DATA_LENGTH - 1] = version; + bytes +} + +fn invalid_length_error() -> anyhow::Error { + anyhow!( + "Invalid report data length, expected {} bytes", + REPORT_DATA_LENGTH + ) +} + +impl TryFrom<&[u8]> for ReportData { + type Error = anyhow::Error; + + fn try_from(report_data: &[u8]) -> Result { + if report_data.len() != REPORT_DATA_LENGTH { + return Err(invalid_length_error()); + } + + let version = report_data[REPORT_DATA_LENGTH - 1]; + match version { + 0 => Ok(Self::V0(ReportDataV0::try_from(report_data)?)), + 1 => Ok(Self::V1(ReportDataV1::try_from(report_data)?)), + _ => Ok(Self::Unknown(report_data.into())), + } + } +} + +impl From for [u8; REPORT_DATA_LENGTH] { + fn from(report_data: ReportData) -> Self { + match report_data { + ReportData::V0(data) => data.into(), + ReportData::V1(data) => data.into(), + ReportData::Unknown(data) => { + let mut bytes = [0u8; REPORT_DATA_LENGTH]; + bytes.copy_from_slice(&data); + bytes + } + } + } +} + +trait ReportDataVersion { + fn version(&self) -> u8; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[allow(missing_docs)] +pub struct ReportDataV0 { + pub pubkey: PublicKey, +} + +impl ReportDataVersion for ReportDataV0 { + fn version(&self) -> u8 { + 0 + } +} + +impl TryFrom<&[u8]> for ReportDataV0 { + type Error = anyhow::Error; + + fn try_from(report_data: &[u8]) -> Result { + if report_data.len() != REPORT_DATA_LENGTH { + return Err(invalid_length_error()); + } + let pubkey = PublicKey::from_slice(&report_data[..PUBLIC_KEY_SIZE])?; + Ok(Self { pubkey }) + } +} + +impl From for [u8; REPORT_DATA_LENGTH] { + fn from(report_data: ReportDataV0) -> Self { + report_data_to_bytes(&report_data.pubkey.serialize(), report_data.version()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[allow(missing_docs)] +pub struct ReportDataV1 { + pub ethereum_address: [u8; ETHEREUM_ADDR_LENGTH], +} + +impl ReportDataVersion for ReportDataV1 { + fn version(&self) -> u8 { + 1 + } +} + +impl TryFrom<&[u8]> for ReportDataV1 { + type Error = anyhow::Error; + + fn try_from(report_data: &[u8]) -> Result { + if report_data.len() != REPORT_DATA_LENGTH { + return Err(invalid_length_error()); + } + let mut ethereum_address = [0u8; ETHEREUM_ADDR_LENGTH]; + ethereum_address.copy_from_slice(&report_data[..ETHEREUM_ADDR_LENGTH]); + Ok(Self { ethereum_address }) + } +} + +impl From for [u8; REPORT_DATA_LENGTH] { + fn from(report_data: ReportDataV1) -> Self { + report_data_to_bytes(&report_data.ethereum_address, report_data.version()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use hex; + use secp256k1::{Secp256k1, SecretKey}; + + const ETHEREUM_ADDR: [u8; ETHEREUM_ADDR_LENGTH] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, + ]; + + fn generate_test_report_data(version_byte: u8) -> [u8; REPORT_DATA_LENGTH] { + let mut data = [0u8; REPORT_DATA_LENGTH]; + data[..ETHEREUM_ADDR.len()].copy_from_slice(ÐEREUM_ADDR); + data[REPORT_DATA_LENGTH - 1] = version_byte; + data + } + + fn generate_test_pubkey() -> PublicKey { + let secp = Secp256k1::new(); + let secret_key_bytes = + hex::decode("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3") + .unwrap(); + let secret_key = SecretKey::from_slice(&secret_key_bytes).unwrap(); + PublicKey::from_secret_key(&secp, &secret_key) + } + + fn generate_test_report_data_v0(pubkey: PublicKey) -> [u8; REPORT_DATA_LENGTH] { + let pubkey_bytes = pubkey.serialize(); + let mut report_data = [0u8; REPORT_DATA_LENGTH]; + report_data[..PUBLIC_KEY_SIZE].copy_from_slice(&pubkey_bytes); + report_data + } + + #[test] + fn test_from_bytes_v0() { + let pubkey = generate_test_pubkey(); + let report_data = generate_test_report_data_v0(pubkey); + let report_data = ReportData::try_from(report_data.as_ref()).unwrap(); + assert_eq!(report_data, ReportData::V0(ReportDataV0 { pubkey })); + } + + #[test] + fn report_data_from_bytes_v1() { + let data = generate_test_report_data(1); + let report_data = ReportData::try_from(data.as_ref()).unwrap(); + assert_eq!( + report_data, + ReportData::V1(ReportDataV1 { + ethereum_address: ETHEREUM_ADDR + }) + ); + } + + #[test] + fn report_data_from_bytes_unknown() { + let report_data_bytes = generate_test_report_data(99); + let report_data = ReportData::try_from(report_data_bytes.as_ref()).unwrap(); + assert_eq!(report_data, ReportData::Unknown(report_data_bytes.into())); + } + + #[test] + fn report_data_to_bytes_v0() { + let pubkey = generate_test_pubkey(); + let report_data = ReportDataV0 { pubkey }; + let report_data: [u8; REPORT_DATA_LENGTH] = report_data.into(); + assert_eq!(&report_data[..PUBLIC_KEY_SIZE], pubkey.serialize().as_ref()); + assert_eq!(report_data[REPORT_DATA_LENGTH - 1], 0); + assert!(report_data[PUBLIC_KEY_SIZE..REPORT_DATA_LENGTH - 1] + .iter() + .all(|&byte| byte == 0)); + } + + #[test] + fn report_data_to_bytes_v1() { + let report_data = ReportDataV1 { + ethereum_address: ETHEREUM_ADDR, + }; + let report_data: [u8; REPORT_DATA_LENGTH] = report_data.into(); + assert_eq!(&report_data[..ETHEREUM_ADDR_LENGTH], ÐEREUM_ADDR); + assert_eq!(report_data[REPORT_DATA_LENGTH - 1], 1); + assert!(report_data[ETHEREUM_ADDR_LENGTH..REPORT_DATA_LENGTH - 1] + .iter() + .all(|&byte| byte == 0)); + } +} diff --git a/crates/teepot/tests/sgx_quote_verification.rs b/crates/teepot/tests/sgx_quote_verification.rs index 27a3d41..08c8198 100644 --- a/crates/teepot/tests/sgx_quote_verification.rs +++ b/crates/teepot/tests/sgx_quote_verification.rs @@ -5,7 +5,10 @@ mod sgx { use anyhow::{Context, Result}; use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; use std::time::{Duration, UNIX_EPOCH}; - use teepot::quote::{verify_quote_with_collateral, QuoteVerificationResult, Report}; + use teepot::{ + prover::reportdata::{ReportData, ReportDataV1}, + quote::{verify_quote_with_collateral, Quote, QuoteVerificationResult, Report}, + }; use tracing_test::traced_test; fn check_quote( @@ -4811,4 +4814,383 @@ mod sgx { .context("check_quote")?; Ok(()) } + + #[test] + fn get_ethereum_address_from_sgx_quote() { + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x10, 0x00, 0x93, 0x9A, + 0x72, 0x33, 0xF7, 0x9C, 0x4C, 0xA9, 0x94, 0x0A, 0x0D, 0xB3, 0x95, 0x7F, 0x06, 0x07, + 0x63, 0xFB, 0x1C, 0xB9, 0x34, 0xDF, 0x64, 0xBC, 0xB4, 0x6D, 0x49, 0x47, 0x5F, 0x80, + 0xD8, 0x28, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x16, 0x18, 0x03, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC3, 0xAB, 0xFB, 0x19, 0x58, 0x23, 0xD9, 0x2F, 0x4D, 0xFD, 0x12, 0xD9, 0x2D, 0xA6, + 0x1C, 0x3F, 0xA7, 0x1D, 0xD6, 0x96, 0xE6, 0x49, 0x3A, 0xD7, 0x1C, 0x0A, 0x64, 0x25, + 0x55, 0x16, 0x6A, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x59, 0x1A, 0x72, 0xB8, 0xB8, + 0x6E, 0x0D, 0x88, 0x14, 0xD6, 0xE8, 0x75, 0x0E, 0x3E, 0xFE, 0x66, 0xAE, 0xA2, 0xD1, + 0x02, 0xB8, 0xBA, 0x24, 0x05, 0x36, 0x55, 0x59, 0xB8, 0x58, 0x69, 0x7D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x62, 0x73, 0x06, 0x09, 0x0A, 0xBA, 0xB3, 0xA6, 0xE1, 0x40, + 0x0E, 0x93, 0x45, 0xBC, 0x60, 0xC7, 0x8A, 0x8B, 0xEF, 0x57, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xCA, 0x10, + 0x00, 0x00, 0x9F, 0x22, 0x82, 0x4E, 0xFB, 0x91, 0x5E, 0x6F, 0x13, 0x99, 0xD9, 0xE2, + 0x90, 0x5D, 0xDC, 0x85, 0x9B, 0x06, 0x8F, 0x15, 0x98, 0x7D, 0xE7, 0xF8, 0xE7, 0xCB, + 0x71, 0x21, 0x4A, 0x69, 0xCC, 0xB4, 0x8A, 0x39, 0x47, 0x82, 0x1A, 0x34, 0x22, 0x7A, + 0xC1, 0x2C, 0x7D, 0x17, 0x33, 0x16, 0xF7, 0x24, 0x6B, 0x5F, 0x49, 0xE3, 0x60, 0x93, + 0xA7, 0xB8, 0x96, 0xBB, 0xDC, 0xDA, 0x69, 0xA3, 0x31, 0x2E, 0x14, 0xB6, 0xEC, 0x06, + 0x93, 0x48, 0x84, 0x61, 0x02, 0x92, 0x87, 0x4C, 0x0B, 0x4F, 0x94, 0xA3, 0x6B, 0xDA, + 0x56, 0x88, 0xD7, 0xF9, 0x30, 0xEC, 0x1B, 0x25, 0x5D, 0x79, 0x16, 0x82, 0x3C, 0x10, + 0xA1, 0x36, 0x99, 0xDD, 0x61, 0xD9, 0xB0, 0xAE, 0xD0, 0x9E, 0xAA, 0x8D, 0x0F, 0xAB, + 0x1F, 0x4C, 0x1F, 0x01, 0xA3, 0xF9, 0x9D, 0xFA, 0x96, 0xF1, 0xA3, 0x5D, 0x93, 0xBC, + 0x5A, 0x70, 0xB1, 0x7D, 0x06, 0x06, 0x16, 0x18, 0x03, 0xFF, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFE, + 0x8C, 0xFD, 0x01, 0x09, 0x5A, 0x0F, 0x10, 0x8A, 0xFF, 0x5C, 0x40, 0x62, 0x4B, 0x93, + 0x61, 0x2D, 0x6C, 0x28, 0xB7, 0x3E, 0x1A, 0x8D, 0x28, 0x17, 0x9C, 0x9D, 0xDF, 0x0E, + 0x06, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x4F, 0x57, 0x75, 0xD7, 0x96, 0x50, 0x3E, + 0x96, 0x13, 0x7F, 0x77, 0xC6, 0x8A, 0x82, 0x9A, 0x00, 0x56, 0xAC, 0x8D, 0xED, 0x70, + 0x14, 0x0B, 0x08, 0x1B, 0x09, 0x44, 0x90, 0xC5, 0x7B, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0xAA, 0x8C, 0x9D, 0xAE, 0x4E, 0xAC, 0x24, 0xE9, 0xAE, 0x7B, 0xD3, + 0x41, 0x7F, 0xE8, 0xB0, 0x63, 0xA8, 0x06, 0x2E, 0xE2, 0xE5, 0xCA, 0x7A, 0xEF, 0xBC, + 0x81, 0xFB, 0xFD, 0x13, 0x6A, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x72, 0xE4, 0xAF, + 0xAE, 0xEF, 0x52, 0x85, 0xF2, 0xA3, 0x1A, 0x9A, 0x90, 0x77, 0x36, 0xA9, 0xEF, 0x3C, + 0xB3, 0xA7, 0xE4, 0x5E, 0x9D, 0x70, 0xD8, 0xF6, 0x74, 0x6A, 0x67, 0x6B, 0x80, 0xD9, + 0x49, 0xCE, 0xD8, 0x84, 0x6C, 0x1F, 0x01, 0x79, 0xDF, 0xC6, 0xFF, 0xD6, 0xD1, 0x8F, + 0x15, 0xE0, 0xBB, 0xEE, 0x88, 0x81, 0x99, 0x2A, 0xDD, 0xA2, 0x41, 0xB4, 0xD2, 0x38, + 0xBD, 0x7B, 0x07, 0x42, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x05, 0x00, 0x62, 0x0E, + 0x00, 0x00, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x0A, 0x4D, 0x49, 0x49, 0x45, 0x38, 0x6A, 0x43, 0x43, 0x42, 0x4A, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4D, 0x44, 0x2F, 0x34, 0x41, + 0x31, 0x70, 0x30, 0x52, 0x4B, 0x2B, 0x4F, 0x56, 0x56, 0x31, 0x57, 0x69, 0x48, 0x54, + 0x48, 0x59, 0x44, 0x42, 0x4E, 0x38, 0x63, 0x66, 0x4D, 0x41, 0x6F, 0x47, 0x43, 0x43, + 0x71, 0x47, 0x53, 0x4D, 0x34, 0x39, 0x42, 0x41, 0x4D, 0x43, 0x0A, 0x4D, 0x48, 0x41, + 0x78, 0x49, 0x6A, 0x41, 0x67, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x4D, 0x4D, 0x47, + 0x55, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4E, 0x48, 0x57, 0x43, 0x42, + 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, 0x64, 0x47, 0x5A, 0x76, 0x63, + 0x6D, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6A, 0x41, 0x59, 0x42, 0x67, 0x4E, + 0x56, 0x42, 0x41, 0x6F, 0x4D, 0x0A, 0x45, 0x55, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, + 0x49, 0x45, 0x4E, 0x76, 0x63, 0x6E, 0x42, 0x76, 0x63, 0x6D, 0x46, 0x30, 0x61, 0x57, + 0x39, 0x75, 0x4D, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, + 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, + 0x46, 0x79, 0x59, 0x54, 0x45, 0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0A, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7A, 0x41, 0x4A, 0x42, + 0x67, 0x4E, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6C, 0x56, 0x54, 0x4D, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x49, 0x31, 0x4D, 0x44, 0x45, 0x78, 0x4E, 0x6A, 0x45, 0x35, 0x4D, + 0x54, 0x45, 0x79, 0x4D, 0x31, 0x6F, 0x58, 0x44, 0x54, 0x4D, 0x79, 0x4D, 0x44, 0x45, + 0x78, 0x4E, 0x6A, 0x45, 0x35, 0x4D, 0x54, 0x45, 0x79, 0x0A, 0x4D, 0x31, 0x6F, 0x77, + 0x63, 0x44, 0x45, 0x69, 0x4D, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x5A, 0x53, 0x57, 0x35, 0x30, 0x5A, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x42, 0x44, 0x53, 0x79, 0x42, 0x44, 0x5A, 0x58, 0x4A, 0x30, 0x61, 0x57, + 0x5A, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5A, 0x54, 0x45, 0x61, 0x4D, 0x42, 0x67, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x0A, 0x43, 0x67, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5A, + 0x57, 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, + 0x70, 0x62, 0x32, 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4E, 0x56, 0x42, + 0x41, 0x63, 0x4D, 0x43, 0x31, 0x4E, 0x68, 0x62, 0x6E, 0x52, 0x68, 0x49, 0x45, 0x4E, + 0x73, 0x59, 0x58, 0x4A, 0x68, 0x4D, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0A, + 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x4A, 0x44, 0x51, 0x54, 0x45, 0x4C, 0x4D, 0x41, + 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4D, 0x43, 0x56, 0x56, 0x4D, 0x77, + 0x57, 0x54, 0x41, 0x54, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, + 0x49, 0x42, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, + 0x42, 0x77, 0x4E, 0x43, 0x41, 0x41, 0x54, 0x55, 0x0A, 0x46, 0x4E, 0x61, 0x4A, 0x4F, + 0x50, 0x2B, 0x36, 0x56, 0x46, 0x65, 0x39, 0x68, 0x49, 0x48, 0x6A, 0x47, 0x42, 0x59, + 0x73, 0x2F, 0x43, 0x42, 0x6C, 0x61, 0x31, 0x65, 0x47, 0x70, 0x4D, 0x4E, 0x39, 0x71, + 0x71, 0x6F, 0x6D, 0x72, 0x33, 0x31, 0x78, 0x57, 0x46, 0x68, 0x33, 0x4B, 0x4F, 0x2F, + 0x65, 0x34, 0x38, 0x6B, 0x4A, 0x53, 0x55, 0x64, 0x31, 0x45, 0x37, 0x7A, 0x47, 0x79, + 0x50, 0x61, 0x44, 0x0A, 0x58, 0x35, 0x4D, 0x48, 0x49, 0x72, 0x71, 0x5A, 0x51, 0x6A, + 0x41, 0x4C, 0x6D, 0x66, 0x54, 0x70, 0x6B, 0x34, 0x66, 0x51, 0x6F, 0x34, 0x49, 0x44, + 0x44, 0x54, 0x43, 0x43, 0x41, 0x77, 0x6B, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x6A, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6F, 0x41, 0x55, 0x6C, 0x57, 0x39, 0x64, + 0x7A, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6C, 0x41, 0x53, 0x63, 0x6E, 0x55, 0x0A, 0x39, + 0x44, 0x50, 0x4F, 0x41, 0x56, 0x63, 0x4C, 0x33, 0x6C, 0x51, 0x77, 0x61, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x47, 0x51, 0x77, 0x59, 0x6A, 0x42, 0x67, 0x6F, + 0x46, 0x36, 0x67, 0x58, 0x49, 0x5A, 0x61, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4D, + 0x36, 0x4C, 0x79, 0x39, 0x68, 0x63, 0x47, 0x6B, 0x75, 0x64, 0x48, 0x4A, 0x31, 0x63, + 0x33, 0x52, 0x6C, 0x5A, 0x48, 0x4E, 0x6C, 0x0A, 0x63, 0x6E, 0x5A, 0x70, 0x59, 0x32, + 0x56, 0x7A, 0x4C, 0x6D, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x4C, 0x6D, 0x4E, 0x76, + 0x62, 0x53, 0x39, 0x7A, 0x5A, 0x33, 0x67, 0x76, 0x59, 0x32, 0x56, 0x79, 0x64, 0x47, + 0x6C, 0x6D, 0x61, 0x57, 0x4E, 0x68, 0x64, 0x47, 0x6C, 0x76, 0x62, 0x69, 0x39, 0x32, + 0x4E, 0x43, 0x39, 0x77, 0x59, 0x32, 0x74, 0x6A, 0x63, 0x6D, 0x77, 0x2F, 0x59, 0x32, + 0x45, 0x39, 0x0A, 0x63, 0x47, 0x78, 0x68, 0x64, 0x47, 0x5A, 0x76, 0x63, 0x6D, 0x30, + 0x6D, 0x5A, 0x57, 0x35, 0x6A, 0x62, 0x32, 0x52, 0x70, 0x62, 0x6D, 0x63, 0x39, 0x5A, + 0x47, 0x56, 0x79, 0x4D, 0x42, 0x30, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x67, 0x51, + 0x57, 0x42, 0x42, 0x51, 0x52, 0x49, 0x68, 0x6F, 0x4D, 0x41, 0x36, 0x7A, 0x4D, 0x48, + 0x4D, 0x43, 0x75, 0x39, 0x78, 0x6B, 0x53, 0x50, 0x31, 0x42, 0x46, 0x0A, 0x33, 0x35, + 0x54, 0x70, 0x69, 0x7A, 0x41, 0x4F, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x51, 0x38, 0x42, + 0x41, 0x66, 0x38, 0x45, 0x42, 0x41, 0x4D, 0x43, 0x42, 0x73, 0x41, 0x77, 0x44, 0x41, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x54, 0x41, 0x51, 0x48, 0x2F, 0x42, 0x41, 0x49, 0x77, + 0x41, 0x44, 0x43, 0x43, 0x41, 0x6A, 0x6F, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x34, 0x54, 0x51, 0x45, 0x4E, 0x0A, 0x41, 0x51, 0x53, 0x43, 0x41, 0x69, 0x73, + 0x77, 0x67, 0x67, 0x49, 0x6E, 0x4D, 0x42, 0x34, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, + 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4E, 0x41, 0x51, 0x45, 0x45, 0x45, 0x4A, 0x6B, + 0x55, 0x39, 0x50, 0x62, 0x45, 0x49, 0x73, 0x2B, 0x68, 0x37, 0x6F, 0x35, 0x68, 0x4D, + 0x31, 0x35, 0x64, 0x64, 0x75, 0x51, 0x77, 0x67, 0x67, 0x46, 0x6B, 0x42, 0x67, 0x6F, + 0x71, 0x0A, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, + 0x4D, 0x49, 0x49, 0x42, 0x56, 0x44, 0x41, 0x51, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6B, + 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x41, 0x51, 0x49, 0x42, + 0x42, 0x6A, 0x41, 0x51, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, + 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x41, 0x67, 0x49, 0x42, 0x0A, 0x42, 0x6A, 0x41, + 0x51, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, + 0x51, 0x45, 0x43, 0x41, 0x77, 0x49, 0x42, 0x41, 0x6A, 0x41, 0x51, 0x42, 0x67, 0x73, + 0x71, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x42, + 0x41, 0x49, 0x42, 0x41, 0x6A, 0x41, 0x51, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6B, 0x69, + 0x47, 0x2B, 0x45, 0x30, 0x42, 0x0A, 0x44, 0x51, 0x45, 0x43, 0x42, 0x51, 0x49, 0x42, + 0x41, 0x7A, 0x41, 0x51, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, + 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x42, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x51, + 0x42, 0x67, 0x73, 0x71, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, 0x51, + 0x45, 0x43, 0x42, 0x77, 0x49, 0x42, 0x41, 0x44, 0x41, 0x52, 0x42, 0x67, 0x73, 0x71, + 0x0A, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x43, + 0x41, 0x49, 0x43, 0x41, 0x50, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, + 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6B, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, + 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6F, 0x43, 0x0A, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4C, + 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, + 0x68, 0x76, 0x68, 0x4E, 0x0A, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, + 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x0A, + 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, + 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x73, 0x77, 0x48, 0x77, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0A, 0x45, 0x41, 0x59, 0x47, 0x41, + 0x67, 0x49, 0x44, 0x41, 0x51, 0x44, 0x2F, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4B, 0x4B, 0x6F, 0x5A, 0x49, 0x68, + 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4B, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, + 0x51, 0x30, 0x42, 0x0A, 0x42, 0x41, 0x51, 0x47, 0x6B, 0x49, 0x42, 0x76, 0x41, 0x41, + 0x41, 0x41, 0x4D, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4E, 0x41, 0x51, 0x55, 0x4B, 0x41, 0x51, 0x45, 0x77, 0x48, 0x67, + 0x59, 0x4B, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, + 0x42, 0x67, 0x51, 0x51, 0x6A, 0x52, 0x32, 0x30, 0x65, 0x42, 0x69, 0x76, 0x0A, 0x6C, + 0x30, 0x42, 0x45, 0x79, 0x4F, 0x31, 0x71, 0x66, 0x7A, 0x57, 0x78, 0x53, 0x7A, 0x42, + 0x45, 0x42, 0x67, 0x6F, 0x71, 0x68, 0x6B, 0x69, 0x47, 0x2B, 0x45, 0x30, 0x42, 0x44, + 0x51, 0x45, 0x48, 0x4D, 0x44, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, + 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x45, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4C, 0x0A, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, + 0x68, 0x4E, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x49, 0x42, 0x41, 0x66, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4C, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x68, 0x4E, 0x41, 0x51, + 0x30, 0x42, 0x42, 0x77, 0x4D, 0x42, 0x41, 0x66, 0x38, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x41, + 0x41, 0x77, 0x0A, 0x52, 0x51, 0x49, 0x67, 0x54, 0x30, 0x4B, 0x32, 0x44, 0x70, 0x64, + 0x77, 0x58, 0x58, 0x77, 0x78, 0x2B, 0x67, 0x6B, 0x38, 0x4D, 0x6E, 0x6F, 0x50, 0x56, + 0x49, 0x6A, 0x58, 0x46, 0x71, 0x4E, 0x58, 0x45, 0x2F, 0x32, 0x39, 0x4D, 0x58, 0x68, + 0x4D, 0x57, 0x72, 0x53, 0x4E, 0x6F, 0x72, 0x67, 0x43, 0x49, 0x51, 0x44, 0x61, 0x72, + 0x33, 0x34, 0x78, 0x58, 0x2F, 0x57, 0x6C, 0x75, 0x44, 0x6B, 0x6A, 0x0A, 0x58, 0x4A, + 0x51, 0x54, 0x61, 0x72, 0x4C, 0x59, 0x76, 0x78, 0x2B, 0x74, 0x65, 0x36, 0x44, 0x31, + 0x64, 0x74, 0x77, 0x52, 0x44, 0x63, 0x6D, 0x6A, 0x58, 0x53, 0x37, 0x4B, 0x72, 0x41, + 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x0A, 0x4D, 0x49, 0x49, 0x43, 0x6C, 0x6A, 0x43, 0x43, 0x41, 0x6A, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4A, 0x56, 0x76, 0x58, 0x63, 0x32, + 0x39, 0x47, 0x2B, 0x48, 0x70, 0x51, 0x45, 0x6E, 0x4A, 0x31, 0x50, 0x51, 0x7A, 0x7A, + 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, 0x55, 0x4D, 0x41, 0x6F, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4D, 0x34, 0x39, 0x42, 0x41, 0x4D, 0x43, 0x0A, 0x4D, 0x47, 0x67, 0x78, + 0x47, 0x6A, 0x41, 0x59, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x4D, 0x4D, 0x45, 0x55, + 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4E, 0x48, 0x57, 0x43, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4E, 0x42, 0x4D, 0x52, 0x6F, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4B, 0x44, 0x42, 0x46, 0x4A, 0x62, 0x6E, 0x52, 0x6C, + 0x62, 0x43, 0x42, 0x44, 0x0A, 0x62, 0x33, 0x4A, 0x77, 0x62, 0x33, 0x4A, 0x68, 0x64, + 0x47, 0x6C, 0x76, 0x62, 0x6A, 0x45, 0x55, 0x4D, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x77, 0x77, 0x4C, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, + 0x32, 0x78, 0x68, 0x63, 0x6D, 0x45, 0x78, 0x43, 0x7A, 0x41, 0x4A, 0x42, 0x67, 0x4E, + 0x56, 0x42, 0x41, 0x67, 0x4D, 0x41, 0x6B, 0x4E, 0x42, 0x4D, 0x51, 0x73, 0x77, 0x0A, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4A, 0x56, 0x55, 0x7A, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4F, 0x44, 0x41, 0x31, 0x4D, 0x6A, 0x45, 0x78, + 0x4D, 0x44, 0x55, 0x77, 0x4D, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7A, 0x4D, 0x7A, + 0x41, 0x31, 0x4D, 0x6A, 0x45, 0x78, 0x4D, 0x44, 0x55, 0x77, 0x4D, 0x54, 0x42, 0x61, + 0x4D, 0x48, 0x41, 0x78, 0x49, 0x6A, 0x41, 0x67, 0x0A, 0x42, 0x67, 0x4E, 0x56, 0x42, + 0x41, 0x4D, 0x4D, 0x47, 0x55, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4E, + 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, 0x64, + 0x47, 0x5A, 0x76, 0x63, 0x6D, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6A, 0x41, + 0x59, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, 0x4D, 0x45, 0x55, 0x6C, 0x75, 0x64, + 0x47, 0x56, 0x73, 0x0A, 0x49, 0x45, 0x4E, 0x76, 0x63, 0x6E, 0x42, 0x76, 0x63, 0x6D, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4D, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, + 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4C, 0x4D, 0x41, 0x6B, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x0A, 0x43, + 0x7A, 0x41, 0x4A, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6C, 0x56, + 0x54, 0x4D, 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, + 0x6A, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, + 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4E, 0x53, 0x42, 0x2F, 0x37, + 0x74, 0x32, 0x31, 0x6C, 0x58, 0x53, 0x4F, 0x0A, 0x32, 0x43, 0x75, 0x7A, 0x70, 0x78, + 0x77, 0x37, 0x34, 0x65, 0x4A, 0x42, 0x37, 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, + 0x35, 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, 0x54, 0x4C, 0x71, 0x36, 0x68, + 0x4B, 0x6B, 0x36, 0x7A, 0x2B, 0x55, 0x69, 0x52, 0x5A, 0x43, 0x6E, 0x71, 0x52, 0x37, + 0x70, 0x73, 0x4F, 0x76, 0x67, 0x71, 0x46, 0x65, 0x53, 0x78, 0x6C, 0x6D, 0x54, 0x6C, + 0x4A, 0x6C, 0x0A, 0x65, 0x54, 0x6D, 0x69, 0x32, 0x57, 0x59, 0x7A, 0x33, 0x71, 0x4F, + 0x42, 0x75, 0x7A, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4E, 0x56, 0x48, + 0x53, 0x4D, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5A, 0x51, 0x7A, + 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4F, 0x44, 0x74, 0x4A, 0x56, 0x53, 0x76, + 0x31, 0x41, 0x62, 0x4F, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x0A, 0x42, 0x67, + 0x4E, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7A, 0x42, 0x4A, 0x4D, 0x45, 0x65, 0x67, + 0x52, 0x61, 0x42, 0x44, 0x68, 0x6B, 0x46, 0x6F, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7A, + 0x6F, 0x76, 0x4C, 0x32, 0x4E, 0x6C, 0x63, 0x6E, 0x52, 0x70, 0x5A, 0x6D, 0x6C, 0x6A, + 0x59, 0x58, 0x52, 0x6C, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6E, 0x56, 0x7A, 0x64, 0x47, + 0x56, 0x6B, 0x63, 0x32, 0x56, 0x79, 0x0A, 0x64, 0x6D, 0x6C, 0x6A, 0x5A, 0x58, 0x4D, + 0x75, 0x61, 0x57, 0x35, 0x30, 0x5A, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4C, + 0x30, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6D, 0x39, + 0x76, 0x64, 0x45, 0x4E, 0x42, 0x4C, 0x6D, 0x52, 0x6C, 0x63, 0x6A, 0x41, 0x64, 0x42, + 0x67, 0x4E, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6C, 0x57, 0x39, + 0x64, 0x0A, 0x7A, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6C, 0x41, 0x53, 0x63, 0x6E, 0x55, + 0x39, 0x44, 0x50, 0x4F, 0x41, 0x56, 0x63, 0x4C, 0x33, 0x6C, 0x51, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2F, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4D, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2F, 0x77, 0x51, 0x49, 0x4D, 0x41, 0x59, 0x42, 0x0A, 0x41, 0x66, 0x38, + 0x43, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, + 0x6A, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x52, 0x77, 0x41, 0x77, 0x52, 0x41, 0x49, + 0x67, 0x58, 0x73, 0x56, 0x6B, 0x69, 0x30, 0x77, 0x2B, 0x69, 0x36, 0x56, 0x59, 0x47, + 0x57, 0x33, 0x55, 0x46, 0x2F, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, 0x30, 0x59, 0x4A, + 0x44, 0x6A, 0x31, 0x55, 0x65, 0x0A, 0x6E, 0x41, 0x2B, 0x54, 0x6A, 0x44, 0x31, 0x61, + 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, 0x31, 0x53, 0x41, 0x6D, 0x44, 0x35, + 0x78, 0x6B, 0x66, 0x54, 0x56, 0x70, 0x76, 0x6F, 0x34, 0x55, 0x6F, 0x79, 0x69, 0x53, + 0x59, 0x78, 0x72, 0x44, 0x57, 0x4C, 0x6D, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, 0x4E, + 0x4B, 0x79, 0x66, 0x50, 0x4E, 0x2B, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, + 0x4E, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x4D, 0x49, 0x49, 0x43, 0x6A, 0x7A, 0x43, 0x43, 0x41, + 0x6A, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6D, 0x55, + 0x4D, 0x31, 0x6C, 0x71, 0x64, 0x4E, 0x49, 0x6E, 0x7A, 0x67, 0x37, 0x53, 0x56, 0x55, + 0x72, 0x39, 0x51, 0x47, 0x7A, 0x6B, 0x6E, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, + 0x49, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0A, + 0x61, 0x44, 0x45, 0x61, 0x4D, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5A, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x4A, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6A, + 0x41, 0x59, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, 0x4D, 0x45, 0x55, 0x6C, 0x75, + 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4E, 0x76, 0x0A, 0x63, 0x6E, 0x42, 0x76, 0x63, + 0x6D, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4D, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, + 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4C, 0x4D, 0x41, 0x6B, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, + 0x7A, 0x41, 0x4A, 0x0A, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6C, + 0x56, 0x54, 0x4D, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4D, 0x44, 0x55, 0x79, + 0x4D, 0x54, 0x45, 0x77, 0x4E, 0x44, 0x55, 0x78, 0x4D, 0x46, 0x6F, 0x58, 0x44, 0x54, + 0x51, 0x35, 0x4D, 0x54, 0x49, 0x7A, 0x4D, 0x54, 0x49, 0x7A, 0x4E, 0x54, 0x6B, 0x31, + 0x4F, 0x56, 0x6F, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4D, 0x42, 0x67, 0x47, 0x0A, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5A, 0x57, 0x77, + 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4A, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, + 0x30, 0x45, 0x78, 0x47, 0x6A, 0x41, 0x59, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, + 0x4D, 0x45, 0x55, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4E, 0x76, 0x63, + 0x6E, 0x42, 0x76, 0x63, 0x6D, 0x46, 0x30, 0x0A, 0x61, 0x57, 0x39, 0x75, 0x4D, 0x52, + 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, + 0x45, 0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, + 0x51, 0x30, 0x45, 0x78, 0x43, 0x7A, 0x41, 0x4A, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x0A, 0x41, 0x6C, 0x56, 0x54, 0x4D, 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, + 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4B, + 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, + 0x45, 0x43, 0x36, 0x6E, 0x45, 0x77, 0x4D, 0x44, 0x49, 0x59, 0x5A, 0x4F, 0x6A, 0x2F, + 0x69, 0x50, 0x57, 0x73, 0x43, 0x7A, 0x61, 0x45, 0x4B, 0x69, 0x37, 0x0A, 0x31, 0x4F, + 0x69, 0x4F, 0x53, 0x4C, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6A, 0x62, 0x6E, 0x42, 0x56, + 0x4A, 0x66, 0x56, 0x6E, 0x6B, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6A, 0x6B, 0x44, 0x59, + 0x59, 0x4C, 0x30, 0x4D, 0x78, 0x4F, 0x34, 0x6D, 0x71, 0x73, 0x79, 0x59, 0x6A, 0x6C, + 0x42, 0x61, 0x6C, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4A, 0x42, 0x4B, + 0x35, 0x7A, 0x6C, 0x4B, 0x4F, 0x42, 0x0A, 0x75, 0x7A, 0x43, 0x42, 0x75, 0x44, 0x41, + 0x66, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x53, 0x4D, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x51, 0x69, 0x5A, 0x51, 0x7A, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4F, + 0x44, 0x74, 0x4A, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4F, 0x53, 0x63, 0x47, 0x72, + 0x44, 0x42, 0x53, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7A, 0x42, + 0x4A, 0x0A, 0x4D, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6B, 0x46, 0x6F, + 0x64, 0x48, 0x52, 0x77, 0x63, 0x7A, 0x6F, 0x76, 0x4C, 0x32, 0x4E, 0x6C, 0x63, 0x6E, + 0x52, 0x70, 0x5A, 0x6D, 0x6C, 0x6A, 0x59, 0x58, 0x52, 0x6C, 0x63, 0x79, 0x35, 0x30, + 0x63, 0x6E, 0x56, 0x7A, 0x64, 0x47, 0x56, 0x6B, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6D, + 0x6C, 0x6A, 0x5A, 0x58, 0x4D, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0A, 0x5A, 0x57, 0x77, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4C, 0x30, 0x6C, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, + 0x30, 0x64, 0x59, 0x55, 0x6D, 0x39, 0x76, 0x64, 0x45, 0x4E, 0x42, 0x4C, 0x6D, 0x52, + 0x6C, 0x63, 0x6A, 0x41, 0x64, 0x42, 0x67, 0x4E, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x49, 0x6D, 0x55, 0x4D, 0x31, 0x6C, 0x71, 0x64, 0x4E, 0x49, 0x6E, + 0x7A, 0x67, 0x37, 0x53, 0x56, 0x0A, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7A, 0x6B, 0x6E, + 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2F, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4D, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2F, 0x77, 0x51, 0x49, 0x4D, 0x41, + 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x0A, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, + 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4F, 0x57, 0x2F, 0x35, 0x51, 0x6B, + 0x52, 0x2B, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4E, 0x6F, 0x6F, 0x77, 0x4C, + 0x75, 0x50, 0x52, 0x4C, 0x73, 0x57, 0x47, 0x66, 0x2F, 0x59, 0x69, 0x37, 0x47, 0x53, + 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, 0x67, 0x0A, 0x41, 0x69, 0x45, 0x41, + 0x34, 0x4A, 0x30, 0x6C, 0x72, 0x48, 0x6F, 0x4D, 0x73, 0x2B, 0x58, 0x6F, 0x35, 0x6F, + 0x2F, 0x73, 0x58, 0x36, 0x4F, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, 0x41, 0x76, 0x5A, + 0x55, 0x47, 0x4F, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, + 0x49, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x0A, 0x00, + ]; + let expected_ethereum_addr = [ + 0x62, 0x73, 0x06, 0x09, 0x0A, 0xBA, 0xB3, 0xA6, 0xE1, 0x40, 0x0E, 0x93, 0x45, 0xBC, + 0x60, 0xC7, 0x8A, 0x8B, 0xEF, 0x57, + ]; + let expected_reportdata = ReportData::V1(ReportDataV1 { + ethereum_address: expected_ethereum_addr, + }); + let expected_reportdata_bytes: [u8; 64] = expected_reportdata.into(); + assert_eq!( + expected_reportdata_bytes, + [ + 0x62, 0x73, 0x06, 0x09, 0x0A, 0xBA, 0xB3, 0xA6, 0xE1, 0x40, 0x0E, 0x93, 0x45, 0xBC, + 0x60, 0xC7, 0x8A, 0x8B, 0xEF, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + ] + ); + + let quote = Quote::parse("e).unwrap(); + let expected_mrsigner = + hex::decode("c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d") + .unwrap(); + + if let Report::SgxEnclave(report_body) = quote.report { + let expected_reportdata = hex::encode(expected_reportdata_bytes); + let expected_mrsigner = hex::encode(expected_mrsigner); + let actual_reportdata = hex::encode(&report_body.report_data[..]); + let actual_mrsigner = hex::encode(&report_body.mr_signer[..]); + assert_eq!(expected_reportdata, actual_reportdata); + assert_eq!(expected_mrsigner, actual_mrsigner); + } else { + panic!("SGX quote expected"); + } + } } From afa524c18cfe8980e626efdc30024546f0bb11a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20B=C4=99za?= Date: Fri, 17 Jan 2025 12:41:07 +0100 Subject: [PATCH 029/114] Address code review comments --- bin/tee-key-preexec/src/main.rs | 24 +----------------------- bin/verify-attestation/src/main.rs | 20 ++++++++++---------- crates/teepot/src/prover/reportdata.rs | 5 +++++ 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 02b0cc2..6399681 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -8,7 +8,6 @@ use anyhow::{Context, Result}; use clap::Parser; -use core::convert::AsRef; use secp256k1::{rand, Secp256k1}; use std::{ffi::OsString, os::unix::process::CommandExt, process::Command}; use teepot::{ @@ -46,7 +45,7 @@ fn main_with_error() -> Result<()> { let ethereum_address = public_key_to_ethereum_address(&verifying_key); let report_data = ReportDataV1 { ethereum_address }; let report_data_bytes: [u8; 64] = report_data.into(); - let tee_type = match get_quote(report_data_bytes.as_ref()) { + let tee_type = match get_quote(&report_data_bytes) { Ok((tee_type, quote)) => { // save quote to file std::fs::write(TEE_QUOTE_FILE, quote)?; @@ -87,24 +86,3 @@ fn main() -> Result<()> { } ret } - -#[cfg(test)] -mod tests { - use secp256k1::{PublicKey, Secp256k1, SecretKey}; - - use super::*; - - #[test] - fn test_public_key_to_address() { - let secp = Secp256k1::new(); - let secret_key_bytes = - hex::decode("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3") - .unwrap(); - let secret_key = SecretKey::from_slice(&secret_key_bytes).unwrap(); - let public_key = PublicKey::from_secret_key(&secp, &secret_key); - let expected_address = hex::decode("627306090abaB3A6e1400e9345bC60c78a8BEf57").unwrap(); - let address = public_key_to_ethereum_address(&public_key); - - assert_eq!(address, expected_address.as_slice()); - } -} diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index 8ba0c2b..fba3c16 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -3,15 +3,16 @@ //! Tool for SGX attestation and batch signature verification -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use clap::{Args, Parser, Subcommand}; use core::convert::TryInto; use hex::encode; -use secp256k1::{Message, PublicKey}; +use secp256k1::Message; use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; use teepot::{ client::TcbLevel, ethereum::recover_signer, + prover::reportdata::ReportData, quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, }; use zksync_basic_types::H256; @@ -87,15 +88,14 @@ fn verify_signature( quote_verification_result: &QuoteVerificationResult, signature_args: &SignatureArgs, ) -> Result<()> { - let reportdata = "e_verification_result.quote.get_report_data(); - let public_key = PublicKey::from_slice(reportdata)?; - println!("Public key from attestation quote: {}", public_key); + let report_data = ReportData::try_from(quote_verification_result.quote.get_report_data())?; + let ethereum_address_from_quote = match report_data { + ReportData::V1(report_data_v1) => report_data_v1.ethereum_address, + _ => return Err(anyhow!("Unsupported report data version")), + }; let signature_bytes: &[u8] = &fs::read(&signature_args.signature_file)?; - let ethereum_address_from_quote = "e_verification_result.quote.get_report_data()[..20]; - let root_hash_bytes = signature_args.root_hash.as_bytes(); - let root_hash_msg = Message::from_digest_slice(root_hash_bytes)?; - let ethereum_address_from_signature = - recover_signer(&signature_bytes.try_into()?, &root_hash_msg)?; + let root_hash = Message::from_digest_slice(signature_args.root_hash.as_bytes())?; + let ethereum_address_from_signature = recover_signer(&signature_bytes.try_into()?, &root_hash)?; let verification_successful = ethereum_address_from_signature == ethereum_address_from_quote; println!( diff --git a/crates/teepot/src/prover/reportdata.rs b/crates/teepot/src/prover/reportdata.rs index d9665a4..bcff688 100644 --- a/crates/teepot/src/prover/reportdata.rs +++ b/crates/teepot/src/prover/reportdata.rs @@ -35,6 +35,11 @@ pub enum ReportData { } fn report_data_to_bytes(data: &[u8], version: u8) -> [u8; REPORT_DATA_LENGTH] { + debug_assert!( + data.len() < REPORT_DATA_LENGTH, // Ensure there is space for the version byte + "Data length exceeds maximum of {} bytes", + REPORT_DATA_LENGTH + ); let mut bytes = [0u8; REPORT_DATA_LENGTH]; bytes[..data.len()].copy_from_slice(data); bytes[REPORT_DATA_LENGTH - 1] = version; From 11a22c9e67c0785ba416e2f22863f48ae6c161b1 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 21 Jan 2025 16:42:52 +0100 Subject: [PATCH 030/114] feat: add Google Metadata support and TDX container test - Introduced `google-metadata` binary for reading GCP instance attributes. - Added TDX container test with new `container-test-tdx` package. - Updated Nix workflow and deployment scripts for Google Metadata integration. - Bumped `anyhow` to 1.0.95 and updated Cargo.lock. Signed-off-by: Harald Hoyer --- .github/workflows/nix.yml | 1 + Cargo.lock | 133 +++++++++++++++++- Cargo.toml | 2 + assets/config.json | 4 + assets/gcloud-deploy.sh | 13 +- bin/google-metadata/Cargo.toml | 16 +++ bin/google-metadata/src/main.rs | 74 ++++++++++ checks/cargoClippy/default.nix | 8 ++ .../cargoFmt => checks/cargoDeny}/default.nix | 4 +- .../cargoDeny => checks/cargoFmt}/default.nix | 4 +- flake.nix | 18 +-- packages/cargoClippy/default.nix | 8 -- packages/container-test-tdx/default.nix | 24 ++++ packages/teepot/default.nix | 5 +- .../teepotCrate/default.nix | 19 ++- shells/teepot/default.nix | 5 +- 16 files changed, 286 insertions(+), 52 deletions(-) create mode 100644 assets/config.json create mode 100644 bin/google-metadata/Cargo.toml create mode 100644 bin/google-metadata/src/main.rs create mode 100644 checks/cargoClippy/default.nix rename {packages/cargoFmt => checks/cargoDeny}/default.nix (50%) rename {packages/cargoDeny => checks/cargoFmt}/default.nix (50%) delete mode 100644 packages/cargoClippy/default.nix create mode 100644 packages/container-test-tdx/default.nix rename teepot-crate.nix => packages/teepotCrate/default.nix (67%) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 53bd89b..1a1e28f 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -73,6 +73,7 @@ jobs: - { nixpackage: 'container-self-attestation-test-sgx-azure' } - { nixpackage: 'container-verify-attestation-sgx' } - { nixpackage: 'container-verify-era-proof-attestation-sgx' } + - { nixpackage: 'container-test-tdx' } steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v30 diff --git a/Cargo.lock b/Cargo.lock index b770552..2d4b5b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,9 +337,9 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "argon2" @@ -1927,8 +1927,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1999,6 +2001,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "google-metadata" +version = "0.3.0" +dependencies = [ + "anyhow", + "reqwest 0.12.9", + "reqwest-middleware", + "reqwest-retry", + "serde_json", + "tokio", +] + [[package]] name = "gpt" version = "4.0.0" @@ -2596,6 +2610,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "intel-tee-quote-verification-sys" version = "0.2.1" @@ -3575,6 +3601,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -3582,7 +3619,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -3593,7 +3644,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.8", "smallvec", "windows-targets 0.52.6", ] @@ -3905,7 +3956,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot", + "parking_lot 0.12.3", "prometheus-client-derive-encode", ] @@ -4099,6 +4150,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -4242,6 +4302,52 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "reqwest-middleware" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ccd3b55e711f91a9885a2fa6fbbb2e39db1776420b062efc058c6410f7e5e3" +dependencies = [ + "anyhow", + "async-trait", + "http 1.2.0", + "reqwest 0.12.9", + "serde", + "thiserror", + "tower-service", +] + +[[package]] +name = "reqwest-retry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "getrandom", + "http 1.2.0", + "hyper 1.5.2", + "parking_lot 0.11.2", + "reqwest 0.12.9", + "reqwest-middleware", + "retry-policies", + "thiserror", + "tokio", + "tracing", + "wasm-timer", +] + +[[package]] +name = "retry-policies" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c" +dependencies = [ + "rand", +] + [[package]] name = "rfc6979" version = "0.3.1" @@ -5543,7 +5649,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -6200,6 +6306,21 @@ version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.76" diff --git a/Cargo.toml b/Cargo.toml index 54564d4..dd5af39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,8 @@ pgp = "0.14.2" pkcs8 = { version = "0.10" } rand = "0.8" reqwest = { version = "0.12", features = ["json"] } +reqwest-middleware = "0.4.0" +reqwest-retry = "0.7.0" rsa = { version = "0.9.6", features = ["sha2", "pem"] } rustls = { version = "0.23.20" } secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] } diff --git a/assets/config.json b/assets/config.json new file mode 100644 index 0000000..a69a474 --- /dev/null +++ b/assets/config.json @@ -0,0 +1,4 @@ +{ + "foo": "bar", + "bar": "baz" +} diff --git a/assets/gcloud-deploy.sh b/assets/gcloud-deploy.sh index b2f8a22..7eeaa06 100755 --- a/assets/gcloud-deploy.sh +++ b/assets/gcloud-deploy.sh @@ -7,8 +7,12 @@ set -ex +BASE_DIR=${0%/*} + NO=${NO:-1} +ZONE=${ZONE:-us-central1-c} + nix build -L .#tdx_google gsutil cp result/tdx_base_1.vmdk gs://tdx_vms/ @@ -21,8 +25,8 @@ gcloud migration vms image-imports create \ --source-file=gs://tdx_vms/tdx_base_1.vmdk \ tdx-img-pre-"${NO}" -gcloud compute instances stop tdx-pilot --zone us-central1-c --project tdx-pilot || : -gcloud compute instances delete tdx-pilot --zone us-central1-c --project tdx-pilot || : +gcloud compute instances stop tdx-pilot --zone ${ZONE} --project tdx-pilot || : +gcloud compute instances delete tdx-pilot --zone ${ZONE} --project tdx-pilot || : while gcloud migration vms image-imports list --location=us-central1 --project=tdx-pilot | grep -F RUNNING; do sleep 1 @@ -36,10 +40,11 @@ gcloud compute images create \ tdx-img-f-"${NO}" gcloud compute instances create tdx-pilot \ - --machine-type c3-standard-4 --zone us-central1-c \ + --machine-type c3-standard-4 --zone ${ZONE} \ --confidential-compute-type=TDX \ --maintenance-policy=TERMINATE \ --image-project=tdx-pilot \ --project tdx-pilot \ - --metadata=container_hub="docker.io",container_image="amd64/hello-world@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57" \ + --metadata=container_hub="docker.io",container_image="matterlabsrobot/test-tdx:117p5y281limw0w7b03v802ij00c5gzw" \ + --metadata-from-file=container_config=$BASE_DIR/config.json \ --image tdx-img-f-"${NO}" diff --git a/bin/google-metadata/Cargo.toml b/bin/google-metadata/Cargo.toml new file mode 100644 index 0000000..15e1a98 --- /dev/null +++ b/bin/google-metadata/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "google-metadata" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +[dependencies] +anyhow.workspace = true +reqwest.workspace = true +reqwest-middleware.workspace = true +reqwest-retry.workspace = true +serde_json.workspace = true +tokio.workspace = true diff --git a/bin/google-metadata/src/main.rs b/bin/google-metadata/src/main.rs new file mode 100644 index 0000000..33bdc66 --- /dev/null +++ b/bin/google-metadata/src/main.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use anyhow::{bail, Result}; +use reqwest::Client; +use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; +use reqwest_retry::{policies::ExponentialBackoff, Jitter, RetryTransientMiddleware}; +use serde_json::Value; +use std::time::Duration; + +const DEFAULT_INSTANCE_METADATA_BASE_URL: &str = + "http://metadata.google.internal/computeMetadata/v1/instance/attributes"; + +async fn fetch_gcp_metadata( + http_client: &ClientWithMiddleware, + metadata_key: &str, +) -> Result { + // Validate the metadata key: + if metadata_key.is_empty() { + bail!("Empty metadata_key"); + } + + let url = format!("{DEFAULT_INSTANCE_METADATA_BASE_URL}/{metadata_key}"); + + // Make an HTTP GET request: + let response = http_client + .get(url) + .header("Metadata-Flavor", "Google") + .send() + .await?; + + // Handle response: + if response.status().is_success() { + let metadata_text = response.text().await?; + serde_json::from_str(&metadata_text) + .map_err(|e| anyhow::format_err!("Failed to parse metadata JSON: {}", e)) + } else { + let status = response.status(); + let error_body = response + .text() + .await + .unwrap_or_else(|_| "".to_string()); + bail!( + "Failed to fetch metadata: {}, Response body: {}", + status, + error_body + ); + } +} + +#[tokio::main] +async fn main() -> Result<()> { + // Build the client with retry middleware and exponential backoff: + let retry_policy = ExponentialBackoff::builder() + .retry_bounds(Duration::from_secs(1), Duration::from_secs(32)) + .jitter(Jitter::Bounded) + .base(2) + .build_with_total_retry_duration(Duration::from_secs(60)); + let client = ClientBuilder::new(Client::builder().build()?) // Underlying reqwest client + .with(RetryTransientMiddleware::new_with_policy(retry_policy)) // Add retry middleware + .build(); + + // Fetch and display metadata: + match fetch_gcp_metadata(&client, "container_config").await { + Ok(container_config) => { + println!("Container config:\n{:#?}", container_config); + } + Err(e) => { + eprintln!("Error fetching container config: {}", e); + } + } + + Ok(()) +} diff --git a/checks/cargoClippy/default.nix b/checks/cargoClippy/default.nix new file mode 100644 index 0000000..2b16ef7 --- /dev/null +++ b/checks/cargoClippy/default.nix @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ teepot }: teepot.teepot.passthru.craneLib.cargoClippy ( + teepot.teepot.passthru.commonArgs // { + pname = "teepot"; + inherit (teepot.teepot.passthru) cargoArtifacts; + } +) diff --git a/packages/cargoFmt/default.nix b/checks/cargoDeny/default.nix similarity index 50% rename from packages/cargoFmt/default.nix rename to checks/cargoDeny/default.nix index cc8e631..7f3cb73 100644 --- a/packages/cargoFmt/default.nix +++ b/checks/cargoDeny/default.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.cargoFmt ( - teepotCrate.commonArgs // { +{ teepot }: teepot.teepot.passthru.craneLib.cargoDeny ( + teepot.teepot.passthru.commonArgs // { pname = "teepot"; } ) diff --git a/packages/cargoDeny/default.nix b/checks/cargoFmt/default.nix similarity index 50% rename from packages/cargoDeny/default.nix rename to checks/cargoFmt/default.nix index e4c400a..4f60a7f 100644 --- a/packages/cargoDeny/default.nix +++ b/checks/cargoFmt/default.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.cargoDeny ( - teepotCrate.commonArgs // { +{ teepot }: teepot.teepot.passthru.craneLib.cargoFmt ( + teepot.teepot.passthru.commonArgs // { pname = "teepot"; } ) diff --git a/flake.nix b/flake.nix index 0512524..d4c56ed 100644 --- a/flake.nix +++ b/flake.nix @@ -25,12 +25,9 @@ }; outputs = inputs: - let - src = ./.; - in inputs.snowfall-lib.mkFlake { inherit inputs; - inherit src; + src = ./.; snowfall.namespace = "teepot"; @@ -42,8 +39,6 @@ nixsgx-flake.overlays.default vault-auth-tee-flake.overlays.default rust-overlay.overlays.default - # somehow the original `src` is not available anymore - (final: prev: { teepotCrate = prev.pkgs.callPackage ./teepot-crate.nix { inherit inputs; inherit src; }; }) ]; alias = { @@ -59,16 +54,7 @@ }; outputs-builder = channels: { - formatter = channels.nixpkgs.nixpkgs-fmt; - - checks = { - inherit - (channels.nixpkgs.teepot) cargoFmt; - inherit - (channels.nixpkgs.teepot) cargoClippy; - inherit - (channels.nixpkgs.teepot) cargoDeny; - }; + formatter = channels.nixpkgs.nixfmt-rfc-style; }; }; } diff --git a/packages/cargoClippy/default.nix b/packages/cargoClippy/default.nix deleted file mode 100644 index f356dce..0000000 --- a/packages/cargoClippy/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.cargoClippy ( - teepotCrate.commonArgs // { - pname = "teepot"; - inherit (teepotCrate) cargoArtifacts; - } -) diff --git a/packages/container-test-tdx/default.nix b/packages/container-test-tdx/default.nix new file mode 100644 index 0000000..fd32c49 --- /dev/null +++ b/packages/container-test-tdx/default.nix @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ dockerTools +, buildEnv +, teepot +}: +dockerTools.buildLayeredImage { + name = "test-tdx"; + + config.Entrypoint = [ "${teepot.teepot.google_metadata}/bin/google-metadata" ]; + config.Env = [ "LD_LIBRARY_PATH=/lib" ]; + contents = buildEnv { + name = "image-root"; + + paths = with dockerTools;[ + teepot.teepot.google_metadata + usrBinEnv + binSh + caCertificates + fakeNss + ]; + pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; + }; +} diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index 0879e7e..1ab7982 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ lib, pkgs, makeWrapper, teepotCrate }: teepotCrate.craneLib.buildPackage ( +{ lib, pkgs, makeWrapper, teepot }: +let teepotCrate = teepot.teepotCrate; in +teepotCrate.craneLib.buildPackage ( teepotCrate.commonArgs // { pname = "teepot"; inherit (teepotCrate) cargoArtifacts; @@ -17,6 +19,7 @@ outputs = [ "out" + "google_metadata" "rtmr_calc" "sha384_extend" "tdx_extend" diff --git a/teepot-crate.nix b/packages/teepotCrate/default.nix similarity index 67% rename from teepot-crate.nix rename to packages/teepotCrate/default.nix index 4b59a63..29dd051 100644 --- a/teepot-crate.nix +++ b/packages/teepotCrate/default.nix @@ -7,11 +7,10 @@ , pkg-config , rust-bin , pkgs -, src , openssl }: let - rustVersion = rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + rustVersion = rust-bin.fromRustupToolchainFile (inputs.src + "/rust-toolchain.toml"); rustPlatform = makeRustPlatform { cargo = rustVersion; rustc = rustVersion; @@ -34,15 +33,15 @@ let strictDeps = true; src = with lib.fileset; toSource { - root = src; + root = inputs.src; fileset = unions [ - ./Cargo.lock - ./Cargo.toml - ./bin - ./crates - ./rust-toolchain.toml - ./deny.toml - ./taplo.toml + # Default files from crane (Rust and cargo files) + (craneLib.fileset.commonCargoSources inputs.src) + (fileFilter (file: file.hasExt "hcl") (inputs.src + "/bin")) + # deny.toml and friends + (fileFilter (file: file.hasExt "toml") inputs.src) + # Custom test data files + (maybeMissing (inputs.src + "/crates/teepot/tests/data")) ]; }; diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index 67bedf6..a8e3195 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -6,10 +6,9 @@ , teepot , nixsgx , stdenv -, teepotCrate }: let - toolchain_with_src = (teepotCrate.rustVersion.override { + toolchain_with_src = (teepot.teepot.passthru.rustVersion.override { extensions = [ "rustfmt" "clippy" "rust-src" ]; }); in @@ -19,7 +18,7 @@ mkShell { nativeBuildInputs = with pkgs; [ toolchain_with_src pkg-config - teepotCrate.rustPlatform.bindgenHook + teepot.teepot.passthru.rustPlatform.bindgenHook ]; packages = with pkgs; [ From 6b9984f4d69681d41f61d862a1fb66a10262355b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 03:12:07 +0000 Subject: [PATCH 031/114] chore(deps): update rust crate clap to v4.5.28 --- Cargo.lock | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d4b5b5..322cc7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -918,9 +918,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" dependencies = [ "clap_builder", "clap_derive", @@ -928,9 +928,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstyle", "clap_lex", @@ -939,9 +939,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1637,7 +1637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2918,7 +2918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3998,7 +3998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", - "heck 0.5.0", + "heck 0.4.1", "itertools 0.12.1", "log", "multimap", @@ -4429,7 +4429,7 @@ name = "rtmr-calc" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "gpt", "hex", "pe-sign", @@ -4475,7 +4475,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5002,7 +5002,7 @@ name = "sha384-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "hex", "sha2", ] @@ -5308,7 +5308,7 @@ name = "tdx-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "hex", "teepot", "tracing", @@ -5319,7 +5319,7 @@ name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "hex", "rand", "secp256k1 0.29.1", @@ -5334,7 +5334,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "rsa", "teepot", "tracing", @@ -5362,7 +5362,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.23", + "clap 4.5.28", "serde", "teepot", "tracing", @@ -5378,7 +5378,7 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap 4.5.23", + "clap 4.5.28", "hex", "rustls", "serde_json", @@ -5397,7 +5397,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.23", + "clap 4.5.28", "rustls", "serde_json", "teepot", @@ -5417,7 +5417,7 @@ dependencies = [ "base64 0.22.1", "bytemuck", "bytes", - "clap 4.5.23", + "clap 4.5.28", "const-oid", "enumset", "futures-core", @@ -5460,7 +5460,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.23", + "clap 4.5.28", "serde_json", "teepot", "tracing", @@ -5483,7 +5483,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.23", + "clap 4.5.28", "serde_json", "teepot", "tracing", @@ -5501,7 +5501,7 @@ dependencies = [ "fastrand", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6096,7 +6096,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.23", + "clap 4.5.28", "hex", "pgp", "serde_json", @@ -6113,7 +6113,7 @@ dependencies = [ "actix-web", "anyhow", "base64 0.22.1", - "clap 4.5.23", + "clap 4.5.28", "serde_json", "teepot", "tracing", @@ -6138,7 +6138,7 @@ name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "hex", "secp256k1 0.29.1", "sha3", @@ -6151,7 +6151,7 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.23", + "clap 4.5.28", "ctrlc", "hex", "jsonrpsee-types", @@ -6374,7 +6374,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] From 129c3c13333003ede01534cf9e7e21340997f80d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:23:00 +0000 Subject: [PATCH 032/114] chore(deps): update trufflesecurity/trufflehog action to v3.88.5 --- .github/workflows/secrets_scanner.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/secrets_scanner.yaml b/.github/workflows/secrets_scanner.yaml index 814a625..304e39d 100644 --- a/.github/workflows/secrets_scanner.yaml +++ b/.github/workflows/secrets_scanner.yaml @@ -9,7 +9,7 @@ jobs: with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@06bbd6fd493fcac4a6db0e4850a92bcf932fafed # v3.81.10 + uses: trufflesecurity/trufflehog@f19d6e5d2bef8a8ceca2b7d77ec447fc304f8078 # v3.88.5 with: path: ./ base: ${{ github.event.repository.default_branch }} From decdc55a8960b6a86815e9406e0c9b684b098c59 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:38:07 +0000 Subject: [PATCH 033/114] chore(deps): update rust crate serde to v1.0.217 --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 322cc7a..d5f263f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4826,9 +4826,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] @@ -4845,9 +4845,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", From 87dd28143760c44408f17414f467d4de68227a7e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 12:23:22 +0000 Subject: [PATCH 034/114] chore(deps): update rust crate rustls to v0.23.22 --- Cargo.lock | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5f263f..d6c560f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,7 +619,7 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.12.1", + "itertools", "lazy_static", "lazycell", "log", @@ -1637,7 +1637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2652,15 +2652,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.14" @@ -2918,7 +2909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -3999,7 +3990,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.4.1", - "itertools 0.12.1", + "itertools", "log", "multimap", "once_cell", @@ -4019,7 +4010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools", "proc-macro2", "quote", "syn 1.0.109", @@ -4032,7 +4023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools", "proc-macro2", "quote", "syn 2.0.90", @@ -4475,14 +4466,14 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" dependencies = [ "aws-lc-rs", "log", @@ -5501,7 +5492,7 @@ dependencies = [ "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6983,7 +6974,7 @@ dependencies = [ "chrono", "derive_more 1.0.0-beta.6", "hex", - "itertools 0.10.5", + "itertools", "num", "num_enum 0.7.3", "once_cell", @@ -7016,7 +7007,7 @@ dependencies = [ "bigdecimal", "futures", "hex", - "itertools 0.10.5", + "itertools", "num", "once_cell", "reqwest 0.12.9", From 01eac641825d9e9a40712b613a9f18dd33f2ca13 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 12:56:55 +0000 Subject: [PATCH 035/114] chore(deps): update actions/checkout digest to 11bd719 --- .github/workflows/lint.yml | 4 ++-- .github/workflows/nix.yml | 4 ++-- .github/workflows/secrets_scanner.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7a2e26f..d1b316d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - uses: enarx/spdx@c3e8116ed31c31b3c2e58a26ba5cac407510ca37 with: licenses: |- @@ -27,6 +27,6 @@ jobs: name: taplo runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - uses: cachix/install-nix-action@v30 - run: nix run nixpkgs#taplo -- fmt --check diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 1a1e28f..3dafb07 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -15,7 +15,7 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - uses: cachix/install-nix-action@v30 with: extra_nix_config: | @@ -36,7 +36,7 @@ jobs: needs: check runs-on: [ matterlabs-default-infra-runners ] steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - uses: cachix/install-nix-action@v30 with: extra_nix_config: | diff --git a/.github/workflows/secrets_scanner.yaml b/.github/workflows/secrets_scanner.yaml index 304e39d..064a41d 100644 --- a/.github/workflows/secrets_scanner.yaml +++ b/.github/workflows/secrets_scanner.yaml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - name: TruffleHog OSS From 7d01a240d4840d8b9b197ef03270a61a60024a8b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:37:44 +0000 Subject: [PATCH 036/114] chore(deps): update rust crate reqwest to v0.12.12 --- Cargo.lock | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6c560f..020bfbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -477,7 +477,7 @@ dependencies = [ "rustversion", "serde", "sync_wrapper 0.1.2", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", ] @@ -2006,7 +2006,7 @@ name = "google-metadata" version = "0.3.0" dependencies = [ "anyhow", - "reqwest 0.12.9", + "reqwest 0.12.12", "reqwest-middleware", "reqwest-retry", "serde_json", @@ -2785,7 +2785,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.4.13", "tracing", "url", ] @@ -2909,7 +2909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3669,7 +3669,7 @@ dependencies = [ "digest", "num-traits", "pem-rfc7468 1.0.0-rc.2", - "reqwest 0.12.9", + "reqwest 0.12.12", "rsa", "sha1", "sha2", @@ -3726,7 +3726,7 @@ dependencies = [ "aes-gcm", "aes-kw", "argon2", - "base64 0.22.1", + "base64 0.21.7", "bitfield", "block-padding", "blowfish", @@ -4251,9 +4251,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64 0.22.1", "bytes", @@ -4285,6 +4285,7 @@ dependencies = [ "system-configuration 0.6.1", "tokio", "tokio-native-tls", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -4302,7 +4303,7 @@ dependencies = [ "anyhow", "async-trait", "http 1.2.0", - "reqwest 0.12.9", + "reqwest 0.12.12", "serde", "thiserror", "tower-service", @@ -4321,7 +4322,7 @@ dependencies = [ "http 1.2.0", "hyper 1.5.2", "parking_lot 0.11.2", - "reqwest 0.12.9", + "reqwest 0.12.12", "reqwest-middleware", "retry-policies", "thiserror", @@ -5764,7 +5765,7 @@ dependencies = [ "prost 0.11.9", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -5790,6 +5791,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -6146,7 +6162,7 @@ dependencies = [ "ctrlc", "hex", "jsonrpsee-types", - "reqwest 0.12.9", + "reqwest 0.12.12", "secp256k1 0.29.1", "serde", "serde_with 3.11.0", @@ -7010,7 +7026,7 @@ dependencies = [ "itertools", "num", "once_cell", - "reqwest 0.12.9", + "reqwest 0.12.12", "serde", "serde_json", "thiserror", From 49faaa984b20719988f3043dbe0d17d0802ef2a9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:49:56 +0000 Subject: [PATCH 037/114] chore(deps): update enarx/spdx digest to b5bfdd4 --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d1b316d..b1340ff 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: steps: - name: checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - uses: enarx/spdx@c3e8116ed31c31b3c2e58a26ba5cac407510ca37 + - uses: enarx/spdx@b5bfdd4410071bf058c8333d0e70020001524b6b with: licenses: |- Apache-2.0 From 45309e58f40008dc9e476143c9f70939c2df2188 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 10 Feb 2025 15:40:28 +0100 Subject: [PATCH 038/114] chore: cargo deps update with code fixes for the new versions. Signed-off-by: Harald Hoyer --- Cargo.lock | 794 +++++++++++--------- Cargo.toml | 13 +- bin/verify-era-proof-attestation/Cargo.toml | 2 - crates/teepot/src/ethereum/mod.rs | 11 +- crates/teepot/src/server/pki.rs | 12 +- crates/teepot/src/sgx/sign.rs | 8 +- 6 files changed, 447 insertions(+), 393 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 020bfbd..953205b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "bytes", "futures-core", "futures-sink", @@ -32,11 +32,11 @@ dependencies = [ "actix-utils", "ahash", "base64 0.22.1", - "bitflags 2.6.0", + "bitflags 2.8.0", "brotli", "bytes", "bytestring", - "derive_more 0.99.18", + "derive_more 0.99.19", "encoding_rs", "flate2", "futures-core", @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -175,7 +175,7 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more 0.99.18", + "derive_more 0.99.19", "encoding_rs", "futures-core", "futures-util", @@ -206,7 +206,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -275,7 +275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -362,13 +362,13 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -410,7 +410,7 @@ dependencies = [ "bytes", "cfg-if", "cookie", - "derive_more 0.99.18", + "derive_more 0.99.19", "futures-core", "futures-util", "h2 0.3.26", @@ -430,9 +430,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.12.0" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +checksum = "4c2b7ddaa2c56a367ad27a094ad8ef4faacf8a617c2575acb2ba88949df999ca" dependencies = [ "aws-lc-sys", "paste", @@ -441,16 +441,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.24.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8478a5c29ead3f3be14aff8a202ad965cf7da6856860041bfca271becf8ba48b" +checksum = "54ac4f13dad353b209b34cbec082338202cbc01c8f00336b55c750c13ac91f8f" dependencies = [ "bindgen 0.69.5", "cc", "cmake", "dunce", "fs_extra", - "libc", "paste", ] @@ -606,7 +605,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.90", + "syn 2.0.98", "which", ] @@ -616,10 +615,10 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "cexpr", "clang-sys", - "itertools", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -629,7 +628,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.90", + "syn 2.0.98", "which", ] @@ -640,10 +639,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] -name = "bitfield" +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bitfield" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" [[package]] name = "bitflags" @@ -653,9 +668,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitvec" @@ -719,9 +734,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -729,9 +744,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "serde", @@ -748,9 +763,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" @@ -760,22 +775,22 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -786,9 +801,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" [[package]] name = "bytestring" @@ -820,9 +835,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.5" +version = "1.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" dependencies = [ "jobserver", "libc", @@ -859,12 +874,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chrono" version = "0.4.39" @@ -946,7 +955,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -968,9 +977,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.52" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -1009,6 +1018,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -1044,9 +1073,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -1098,9 +1127,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -1109,7 +1138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -1121,7 +1150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -1133,7 +1162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "typenum", ] @@ -1146,16 +1175,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "ctrlc" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" -dependencies = [ - "nix", - "windows-sys 0.59.0", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -1166,7 +1185,7 @@ dependencies = [ "cpufeatures", "curve25519-dalek-derive", "digest", - "fiat-crypto 0.2.9", + "fiat-crypto", "rustc_version", "subtle", "zeroize", @@ -1180,7 +1199,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1228,7 +1247,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1250,7 +1269,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1303,7 +1322,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1334,7 +1353,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1344,20 +1363,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1377,7 +1396,7 @@ checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "unicode-xid", ] @@ -1410,7 +1429,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1504,17 +1523,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed448-goldilocks" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87b5fa9e9e3dd5fe1369f380acd3dcdfa766dbd0a1cd5b048fb40e38a6a78e79" -dependencies = [ - "fiat-crypto 0.1.20", - "hex", - "subtle", -] - [[package]] name = "either" version = "1.13.0" @@ -1535,7 +1543,7 @@ dependencies = [ "generic-array", "group 0.12.1", "pkcs8 0.9.0", - "rand_core 0.6.4", + "rand_core", "sec1 0.3.0", "subtle", "zeroize", @@ -1556,7 +1564,7 @@ dependencies = [ "hkdf", "pem-rfc7468 0.7.0", "pkcs8 0.10.2", - "rand_core 0.6.4", + "rand_core", "sec1 0.7.3", "subtle", "zeroize", @@ -1564,9 +1572,9 @@ dependencies = [ [[package]] name = "elsa" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" +checksum = "2343daaeabe09879d4ea058bb4f1e63da3fc07dadc6634e01bda1b3d6a9d9d2b" dependencies = [ "stable_deref_trait", ] @@ -1599,7 +1607,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1653,7 +1661,7 @@ dependencies = [ "serde", "serde_json", "sha3", - "thiserror", + "thiserror 1.0.69", "uint", ] @@ -1696,7 +1704,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1706,16 +1714,10 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] -[[package]] -name = "fiat-crypto" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1866,7 +1868,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1929,10 +1931,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "ghash" version = "0.5.1" @@ -1951,9 +1965,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "gloo-net" @@ -1970,7 +1984,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -2019,7 +2033,7 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffa5448a0d9d541f1840c0e1b5fe513360861ca83c4b920619f54efe277f9254" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "crc", "simple-bytes", "uuid", @@ -2032,7 +2046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2043,7 +2057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2059,7 +2073,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -2078,7 +2092,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.2.0", - "indexmap 2.7.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -2124,6 +2138,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2220,9 +2243,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -2262,9 +2285,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -2282,13 +2305,13 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.4" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "log", "rustls", @@ -2331,7 +2354,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "native-tls", "tokio", @@ -2350,7 +2373,7 @@ dependencies = [ "futures-util", "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.2", + "hyper 1.6.0", "pin-project-lite", "socket2", "tokio", @@ -2496,7 +2519,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2546,9 +2569,9 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "impl-rlp" @@ -2576,7 +2599,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2592,9 +2615,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -2633,9 +2656,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iter-read" @@ -2652,6 +2675,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -2668,7 +2700,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -2689,9 +2721,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -2707,7 +2739,7 @@ dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", "jsonrpsee-proc-macros", - "jsonrpsee-types", + "jsonrpsee-types 0.23.2", "jsonrpsee-wasm-client", "jsonrpsee-ws-client", "tracing", @@ -2730,7 +2762,7 @@ dependencies = [ "rustls-pki-types", "rustls-platform-verifier", "soketto", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-rustls", "tokio-util", @@ -2753,12 +2785,12 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "jsonrpsee-types", + "jsonrpsee-types 0.23.2", "pin-project", "rustc-hash", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", "tracing", @@ -2774,16 +2806,16 @@ dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.1", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-rustls", "hyper-util", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.23.2", "rustls", "rustls-platform-verifier", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tower 0.4.13", "tracing", @@ -2800,7 +2832,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2813,7 +2845,19 @@ dependencies = [ "http 1.2.0", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.24.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6" +dependencies = [ + "http 1.2.0", + "serde", + "serde_json", + "thiserror 1.0.69", ] [[package]] @@ -2824,7 +2868,7 @@ checksum = "4727ac037f834c6f04c0912cada7532dbddb54e92fbc64e33d6cb8c24af313c9" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.23.2", ] [[package]] @@ -2836,7 +2880,7 @@ dependencies = [ "http 1.2.0", "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.23.2", "url", ] @@ -2909,7 +2953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -2935,14 +2979,14 @@ checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" @@ -2979,9 +3023,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "logos" @@ -3003,7 +3047,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3060,7 +3104,7 @@ checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ "miette-derive", "once_cell", - "thiserror", + "thiserror 1.0.69", "unicode-width", ] @@ -3072,7 +3116,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3089,9 +3133,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] @@ -3104,7 +3148,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -3122,9 +3166,9 @@ checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" dependencies = [ "libc", "log", @@ -3137,18 +3181,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -3297,7 +3329,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3309,14 +3341,14 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -3335,9 +3367,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "opaque-debug" @@ -3347,11 +3379,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "cfg-if", "foreign-types", "libc", @@ -3368,20 +3400,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc", @@ -3428,7 +3460,7 @@ dependencies = [ "opentelemetry_sdk", "prost 0.11.9", "reqwest 0.11.27", - "thiserror", + "thiserror 1.0.69", "tokio", "tonic", ] @@ -3466,7 +3498,7 @@ dependencies = [ "js-sys", "once_cell", "pin-project-lite", - "thiserror", + "thiserror 1.0.69", "urlencoding", ] @@ -3488,7 +3520,7 @@ dependencies = [ "rand", "regex", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-stream", ] @@ -3513,9 +3545,9 @@ dependencies = [ [[package]] name = "os_info" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ca711d8b83edbb00b44d504503cd247c9c0bd8b0fa2694f2a1a3d8165379ce" +checksum = "2a604e53c24761286860eba4e2c8b23a0161526476b1de520139d69cdb85a6b5" dependencies = [ "log", "serde", @@ -3542,9 +3574,9 @@ dependencies = [ [[package]] name = "p384" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ "ecdsa 0.16.9", "elliptic-curve 0.13.8", @@ -3562,34 +3594,36 @@ dependencies = [ "ecdsa 0.16.9", "elliptic-curve 0.13.8", "primeorder", - "rand_core 0.6.4", + "rand_core", "sha2", ] [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] @@ -3647,7 +3681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -3713,20 +3747,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.7.0", + "indexmap 2.7.1", ] [[package]] name = "pgp" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1877a97fd422433220ad272eb008ec55691944b1200e9eb204e3cb2cb69d34e9" +checksum = "30249ac8a98b356b473b04bc5358c75a260aa96a295d0743ce752fe7b173f235" dependencies = [ "aes", "aes-gcm", "aes-kw", "argon2", - "base64 0.21.7", + "base64 0.22.1", "bitfield", "block-padding", "blowfish", @@ -3776,38 +3810,37 @@ dependencies = [ "sha3", "signature 2.2.0", "smallvec", - "thiserror", + "thiserror 2.0.11", "twofish", "x25519-dalek", - "x448", "zeroize", ] [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -3881,12 +3914,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ "proc-macro2", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3927,14 +3960,14 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit 0.22.23", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -3959,7 +3992,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3989,8 +4022,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", - "heck 0.4.1", - "itertools", + "heck 0.5.0", + "itertools 0.12.1", "log", "multimap", "once_cell", @@ -3999,7 +4032,7 @@ dependencies = [ "prost 0.12.6", "prost-types", "regex", - "syn 2.0.90", + "syn 2.0.98", "tempfile", ] @@ -4010,7 +4043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -4023,10 +4056,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools", + "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -4066,7 +4099,7 @@ dependencies = [ "prost-reflect", "prost-types", "protox-parse", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4078,7 +4111,7 @@ dependencies = [ "logos", "miette", "prost-types", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4092,9 +4125,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -4113,7 +4146,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4123,22 +4156,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -4156,7 +4183,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", ] [[package]] @@ -4265,7 +4292,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-rustls", "hyper-tls 0.6.0", "hyper-util", @@ -4305,7 +4332,7 @@ dependencies = [ "http 1.2.0", "reqwest 0.12.12", "serde", - "thiserror", + "thiserror 1.0.69", "tower-service", ] @@ -4318,14 +4345,14 @@ dependencies = [ "anyhow", "async-trait", "futures", - "getrandom", + "getrandom 0.2.15", "http 1.2.0", - "hyper 1.5.2", + "hyper 1.6.0", "parking_lot 0.11.2", "reqwest 0.12.12", "reqwest-middleware", "retry-policies", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "wasm-timer", @@ -4369,7 +4396,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -4408,7 +4435,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8 0.10.2", - "rand_core 0.6.4", + "rand_core", "sha2", "signature 2.2.0", "spki 0.7.3", @@ -4459,11 +4486,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", @@ -4519,9 +4546,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-platform-verifier" @@ -4564,15 +4591,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -4637,10 +4664,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ + "bitcoin_hashes", "rand", "secp256k1-sys 0.10.1", ] @@ -4678,7 +4706,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "core-foundation", "core-foundation-sys", "libc", @@ -4688,9 +4716,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -4698,9 +4726,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "send_wrapper" @@ -4810,7 +4838,7 @@ dependencies = [ "rand", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "time", "url", "uuid", @@ -4843,14 +4871,14 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -4882,19 +4910,19 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_derive", "serde_json", - "serde_with_macros 3.11.0", + "serde_with_macros 3.12.0", "time", ] @@ -4912,14 +4940,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -4928,7 +4956,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "itoa", "ryu", "serde", @@ -5040,7 +5068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -5050,7 +5078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -5196,9 +5224,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -5228,7 +5256,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -5248,7 +5276,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "core-foundation", "system-configuration-sys 0.6.0", ] @@ -5314,7 +5342,7 @@ dependencies = [ "clap 4.5.28", "hex", "rand", - "secp256k1 0.29.1", + "secp256k1 0.30.0", "teepot", "tracing", "tracing-log 0.2.0", @@ -5413,7 +5441,7 @@ dependencies = [ "const-oid", "enumset", "futures-core", - "getrandom", + "getrandom 0.3.1", "hex", "num-integer", "num-traits", @@ -5423,17 +5451,17 @@ dependencies = [ "rand", "rsa", "rustls", - "secp256k1 0.29.1", + "secp256k1 0.30.0", "serde", "serde_json", - "serde_with 3.11.0", + "serde_with 3.12.0", "sha2", "sha3", "signature 2.2.0", "tdx-attest-rs", "teepot-tee-quote-verification-rs", "testaso", - "thiserror", + "thiserror 2.0.11", "tokio", "tracing", "tracing-log 0.2.0", @@ -5485,12 +5513,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5536,7 +5565,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] @@ -5547,7 +5585,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -5612,9 +5661,9 @@ dependencies = [ [[package]] name = "tls_codec" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" +checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" dependencies = [ "tls_codec_derive", "zeroize", @@ -5622,20 +5671,20 @@ dependencies = [ [[package]] name = "tls_codec_derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" +checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "tokio" -version = "1.42.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -5661,13 +5710,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -5727,20 +5776,20 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "toml_datetime", - "winnow 0.6.20", + "winnow 0.7.1", ] [[package]] @@ -5851,7 +5900,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -5952,7 +6001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -5999,9 +6048,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "unicode-width" @@ -6082,19 +6131,19 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.11.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" dependencies = [ - "getrandom", + "getrandom 0.3.1", "serde", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vault-admin" @@ -6147,7 +6196,7 @@ dependencies = [ "anyhow", "clap 4.5.28", "hex", - "secp256k1 0.29.1", + "secp256k1 0.30.0", "sha3", "teepot", "zksync_basic_types", @@ -6159,17 +6208,15 @@ version = "0.3.0" dependencies = [ "anyhow", "clap 4.5.28", - "ctrlc", "hex", - "jsonrpsee-types", + "jsonrpsee-types 0.24.8", "reqwest 0.12.12", - "secp256k1 0.29.1", + "secp256k1 0.30.0", "serde", - "serde_with 3.11.0", + "serde_with 3.12.0", "teepot", "tokio", "tracing", - "tracing-log 0.2.0", "tracing-subscriber", "url", "zksync_basic_types", @@ -6218,7 +6265,7 @@ checksum = "8bb19c33cd5f04dcf4e767635e058a998edbc2b7fca32ade0a4a1cea0f8e9b34" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -6247,35 +6294,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.99" +name = "wasi" +version = "0.13.3+wasi-0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -6286,9 +6343,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6296,22 +6353,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-timer" @@ -6330,9 +6390,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -6340,9 +6400,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.7" +version = "0.26.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" dependencies = [ "rustls-pki-types", ] @@ -6381,7 +6441,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -6588,9 +6648,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" dependencies = [ "memchr", ] @@ -6605,6 +6665,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -6633,22 +6702,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core 0.6.4", + "rand_core", "serde", "zeroize", ] -[[package]] -name = "x448" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd07d4fae29e07089dbcacf7077cd52dce7760125ca9a4dd5a35ca603ffebb" -dependencies = [ - "ed448-goldilocks", - "hex", - "rand_core 0.5.1", -] - [[package]] name = "x509-cert" version = "0.2.5" @@ -6683,7 +6741,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "synstructure", ] @@ -6705,7 +6763,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -6725,7 +6783,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "synstructure", ] @@ -6747,7 +6805,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -6769,7 +6827,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -6807,7 +6865,7 @@ version = "0.132.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0769f7b27d8fb06e715da3290c575cac5d04d10a557faef180e847afce50ac4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "blake2", "ethereum-types", "k256 0.11.6", @@ -6831,7 +6889,7 @@ dependencies = [ "serde_json", "serde_with 1.14.0", "strum", - "thiserror", + "thiserror 1.0.69", "tiny-keccak", "url", ] @@ -6847,7 +6905,7 @@ dependencies = [ "pin-project", "rand", "sha3", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tracing", @@ -6880,7 +6938,7 @@ checksum = "587de103f745d0b88b49a9fb98cb002c4b7ce6ad042e17845091dce67b8aa984" dependencies = [ "anyhow", "rand", - "thiserror", + "thiserror 1.0.69", "zksync_concurrency", ] @@ -6913,7 +6971,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.69", "zksync_basic_types", "zksync_utils", ] @@ -6964,7 +7022,7 @@ dependencies = [ "prost-reflect", "protox", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -6990,7 +7048,7 @@ dependencies = [ "chrono", "derive_more 1.0.0-beta.6", "hex", - "itertools", + "itertools 0.10.5", "num", "num_enum 0.7.3", "once_cell", @@ -7000,7 +7058,7 @@ dependencies = [ "serde", "serde_json", "strum", - "thiserror", + "thiserror 1.0.69", "tracing", "zksync_basic_types", "zksync_config", @@ -7023,13 +7081,13 @@ dependencies = [ "bigdecimal", "futures", "hex", - "itertools", + "itertools 0.10.5", "num", "once_cell", "reqwest 0.12.12", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "zk_evm", @@ -7074,7 +7132,7 @@ dependencies = [ "rustls", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", "vise", diff --git a/Cargo.toml b/Cargo.toml index dd5af39..c883025 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,28 +25,27 @@ bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "ex bytes = "1" clap = { version = "4.5", features = ["std", "derive", "env", "error-context", "help", "usage", "wrap_help"], default-features = false } const-oid = { version = "0.9", default-features = false } -ctrlc = "3.4" enumset = { version = "1.1", features = ["serde"] } futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } -getrandom = "0.2.14" +getrandom = { version = "0.3.1", features = ["std"] } gpt = "4.0.0" 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.3.0" } intel-tee-quote-verification-sys = { version = "0.2.1" } -jsonrpsee-types = { version = "0.23", default-features = false } +jsonrpsee-types = { version = "0.24", default-features = false } num-integer = "0.1.46" num-traits = "0.2.18" p256 = "0.13.2" pe-sign = "0.1.10" -pgp = "0.14.2" +pgp = "0.15" pkcs8 = { version = "0.10" } -rand = "0.8" +rand = { version = "0.8", features = ["std", "std_rng"] } reqwest = { version = "0.12", features = ["json"] } reqwest-middleware = "0.4.0" reqwest-retry = "0.7.0" rsa = { version = "0.9.6", features = ["sha2", "pem"] } rustls = { version = "0.23.20" } -secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] } +secp256k1 = { version = "0.30", features = ["rand", "global-context"] } serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" serde_with = { version = "3.8", features = ["base64", "hex"] } @@ -56,7 +55,7 @@ signature = "2.2.0" tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } teepot = { path = "crates/teepot" } testaso = "0.1.0" -thiserror = "1.0.59" +thiserror = "2.0.11" tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time"] } tracing = "0.1" tracing-actix-web = "0.7" diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index acd88a9..70e6379 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -10,7 +10,6 @@ version.workspace = true [dependencies] anyhow.workspace = true clap.workspace = true -ctrlc.workspace = true hex.workspace = true jsonrpsee-types.workspace = true reqwest.workspace = true @@ -20,7 +19,6 @@ serde_with = { workspace = true, features = ["hex"] } teepot.workspace = true tokio.workspace = true tracing.workspace = true -tracing-log.workspace = true tracing-subscriber.workspace = true url.workspace = true zksync_basic_types.workspace = true diff --git a/crates/teepot/src/ethereum/mod.rs b/crates/teepot/src/ethereum/mod.rs index a8ab878..30c7263 100644 --- a/crates/teepot/src/ethereum/mod.rs +++ b/crates/teepot/src/ethereum/mod.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Ethereum-specific helper functions for on-chain verification of Intel SGX attestation. @@ -15,7 +15,7 @@ use sha3::{Digest, Keccak256}; pub fn recover_signer(sig: &[u8; 65], root_hash: &Message) -> Result<[u8; 20]> { let sig = RecoverableSignature::from_compact( &sig[0..64], - RecoveryId::from_i32(sig[64] as i32 - 27)?, + RecoveryId::try_from(sig[64] as i32 - 27)?, )?; let public = SECP256K1.recover_ecdsa(root_hash, &sig)?; Ok(public_key_to_ethereum_address(&public)) @@ -50,7 +50,7 @@ mod tests { signature[..64].copy_from_slice(&data); // as defined in the Ethereum Yellow Paper (Appendix F) // https://ethereum.github.io/yellowpaper/paper.pdf - signature[64] = 27 + rec_id.to_i32() as u8; + signature[64] = 27 + i32::from(rec_id) as u8; Ok(signature) } @@ -63,7 +63,8 @@ mod tests { let secret_key_bytes = hex::decode("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3") .unwrap(); - let secret_key = SecretKey::from_slice(&secret_key_bytes).unwrap(); + let secret_key = + SecretKey::from_byte_array(secret_key_bytes.as_slice().try_into().unwrap()).unwrap(); let public_key = PublicKey::from_secret_key(&secp, &secret_key); let expected_address = hex::decode("627306090abaB3A6e1400e9345bC60c78a8BEf57").unwrap(); let address = public_key_to_ethereum_address(&public_key); @@ -74,7 +75,7 @@ mod tests { // the secret key let root_hash = H256::random(); let root_hash_bytes = root_hash.as_bytes(); - let msg_to_sign = Message::from_digest_slice(root_hash_bytes).unwrap(); + let msg_to_sign = Message::from_digest(root_hash_bytes.try_into().unwrap()); let signature = sign_message(&secret_key, msg_to_sign).unwrap(); // Recover the signer's Ethereum address from the signature and the message, and verify it diff --git a/crates/teepot/src/server/pki.rs b/crates/teepot/src/server/pki.rs index ffa04c3..305df84 100644 --- a/crates/teepot/src/server/pki.rs +++ b/crates/teepot/src/server/pki.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Create a private key and a signed and self-signed certificates @@ -10,10 +10,10 @@ use const_oid::{ db::rfc5280::{ID_KP_CLIENT_AUTH, ID_KP_SERVER_AUTH}, AssociatedOid, }; -use getrandom::getrandom; use intel_tee_quote_verification_rs::tee_qv_get_collateral; use p256::{ecdsa::DerSignature, pkcs8::EncodePrivateKey}; use pkcs8::der; +use rand::rngs::OsRng; use rustls::pki_types::PrivatePkcs8KeyDer; use sha2::{Digest, Sha256}; use signature::Signer; @@ -136,7 +136,7 @@ pub fn make_self_signed_cert( rustls::pki_types::PrivateKeyDer<'static>, )> { // Generate a keypair. - let mut rng = rand::thread_rng(); + let mut rng = OsRng; let signing_key = p256::ecdsa::SigningKey::random(&mut rng); let verifying_key = signing_key.verifying_key(); let verifying_key_der = verifying_key @@ -154,7 +154,7 @@ pub fn make_self_signed_cert( let collateral = tee_qv_get_collateral("e).context("Failed to get own collateral")?; let mut serial = [0u8; 16]; - getrandom(&mut serial)?; + getrandom::fill(&mut serial)?; let mut builder = CertificateBuilder::new( Profile::Leaf { @@ -223,7 +223,7 @@ where S::VerifyingKey: EncodePublicKey, { // Generate a keypair. - let mut rng = rand::thread_rng(); + let mut rng = rand::rngs::OsRng; let signing_key = p256::ecdsa::SigningKey::random(&mut rng); let verifying_key = signing_key.verifying_key(); let verifying_key_der = verifying_key @@ -240,7 +240,7 @@ where let subject = Name::from_str(dn)?; let mut serial = [0u8; 16]; - getrandom(&mut serial)?; + getrandom::fill(&mut serial)?; let mut builder = CertificateBuilder::new( Profile::Leaf { diff --git a/crates/teepot/src/sgx/sign.rs b/crates/teepot/src/sgx/sign.rs index 7b58f43..bb73a98 100644 --- a/crates/teepot/src/sgx/sign.rs +++ b/crates/teepot/src/sgx/sign.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs // Copyright (c) The Enarx Project Developers https://github.com/enarx/sgx @@ -12,14 +12,12 @@ use bytemuck::{bytes_of, Pod, Zeroable}; use num_integer::Integer; use num_traits::ToPrimitive; -use rand::thread_rng; use rsa::{ pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey, LineEnding}, traits::PublicKeyParts, BigUint, Pkcs1v15Sign, RsaPrivateKey, }; -use sha2::Digest as _; -use sha2::Sha256; +use sha2::{Digest as _, Sha256}; pub use zeroize::Zeroizing; /// Enclave CPU attributes @@ -270,7 +268,7 @@ impl PrivateKey for RS256PrivateKey { type Error = rsa::errors::Error; fn generate(exponent: u8) -> Result { - let mut rng = thread_rng(); + let mut rng = rand::rngs::OsRng; let exp = BigUint::from(exponent); let key = RsaPrivateKey::new_with_exp(&mut rng, 384 * 8, &exp)?; Ok(Self::new(key)) From f3f5147bb15cfd590b7f1c6f72fad56537dd1b13 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 18:59:21 +0000 Subject: [PATCH 039/114] chore(deps): update trufflesecurity/trufflehog action to v3.88.6 --- .github/workflows/secrets_scanner.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/secrets_scanner.yaml b/.github/workflows/secrets_scanner.yaml index 064a41d..1e89f90 100644 --- a/.github/workflows/secrets_scanner.yaml +++ b/.github/workflows/secrets_scanner.yaml @@ -9,7 +9,7 @@ jobs: with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@f19d6e5d2bef8a8ceca2b7d77ec447fc304f8078 # v3.88.5 + uses: trufflesecurity/trufflehog@943daae06ba9cc80437a748155c818e9e3177a30 # v3.88.6 with: path: ./ base: ${{ github.event.repository.default_branch }} From c5cdc1e4ab3eb3c623d1497d55eafe3baccd3e70 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 10 Feb 2025 10:46:34 +0100 Subject: [PATCH 040/114] feat(google-tdx): disable LLMNR and MulticastDNS - Configured resolved service, disabling LLMNR and MulticastDNS for improved resolution settings. - Removed commented-out Prometheus Node config Signed-off-by: Harald Hoyer --- packages/tdx_google/configuration.nix | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index c25618c..9a23de8 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -26,6 +26,13 @@ networking.firewall.allowedTCPPortRanges = [{ from = 1024; to = 65535; }]; networking.firewall.allowedUDPPortRanges = [{ from = 1024; to = 65535; }]; + services.resolved.enable = true; + services.resolved.llmnr = "false"; + services.resolved.extraConfig = '' + [Resolve] + MulticastDNS=no + ''; + networking.useNetworkd = lib.mkDefault true; # don't fill up the logs @@ -80,8 +87,6 @@ disabledCollectors = [ "textfile" ]; - #openFirewall = true; - #firewallFilter = "-i br0 -p tcp -m tcp --dport 9100"; }; environment.systemPackages = with pkgs; [ From ff22db6054335c4c8800e97b126257176c043f00 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 10 Feb 2025 10:48:51 +0100 Subject: [PATCH 041/114] chore(google-tdx): removed commented-out ssh debugging Signed-off-by: Harald Hoyer --- packages/tdx_google/configuration.nix | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index 9a23de8..6e2eb40 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -8,19 +8,6 @@ "${toString modulesPath}/profiles/qemu-guest.nix" ]; - /* - # SSH login for debugging - services.sshd.enable = true; - networking.firewall.allowedTCPPorts = [ 22 ]; - services.openssh.settings.PermitRootLogin = lib.mkOverride 999 "yes"; - users.users.root.openssh.authorizedKeys.keys = [ - "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIDsb/Tr69YN5MQLweWPuJaRGm+h2kOyxfD6sqKEDTIwoAAAABHNzaDo=" - "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBACLgT81iB1iWWVuXq6PdQ5GAAGhaZhSKnveQCvcNnAOZ5WKH80bZShKHyAYzrzbp8IGwLWJcZQ7TqRK+qZdfagAAAAEc3NoOg==" - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAYbUTKpy4QR3s944/hjJ1UK05asFEs/SmWeUbtS0cdA660sT4xHnRfals73FicOoz+uIucJCwn/SCM804j+wtM=" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNsmP15vH8BVKo7bdvIiiEjiQboPGcRPqJK0+bH4jKD" - ]; - */ - # the container might want to listen on ports networking.firewall.enable = true; networking.firewall.allowedTCPPortRanges = [{ from = 1024; to = 65535; }]; From 9266a9f072a3238753fe834e1a689eab51932215 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 10 Feb 2025 11:35:25 +0100 Subject: [PATCH 042/114] feat(google-tdx): add Vector service integration - Enable Vector service and configure OpenTelemetry source. - Add sinks for logs output to console and Kafka. - Configure environment setup for Kafka using GCP metadata API. Signed-off-by: Harald Hoyer --- packages/tdx_google/configuration.nix | 57 +++++++++++++++++++++++- systems/x86_64-linux/tdxtest/default.nix | 5 +++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index 6e2eb40..9c6b663 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -8,6 +8,61 @@ "${toString modulesPath}/profiles/qemu-guest.nix" ]; + services.vector.enable = true; + services.vector.settings = { + api.enabled = false; + sources = { + otlp = { + type = "opentelemetry"; + grpc = { address = "127.0.0.1:4317"; }; + http = { + address = "127.0.0.1:4318"; + keepalive = { + max_connection_age_jitter_factor = 0.1; + max_connection_age_secs = 300; + }; + }; + }; + }; + sinks = { + console = { + inputs = [ "otlp.logs" ]; + target = "stdout"; + type = "console"; + encoding = { codec = "json"; }; + }; + kafka = { + type = "kafka"; + inputs = [ "otlp.logs" ]; + bootstrap_servers = "\${KAFKA_URLS:-127.0.0.1:0}"; + topic = "\${KAFKA_TOPIC:-tdx-google}"; + encoding = { + codec = "json"; + compression = "lz4"; + }; + }; + }; + }; + systemd.services.vector.path = [ pkgs.curl pkgs.coreutils ]; + # `-` means, that the file can be missing, so that `ExecStartPre` can execute and create it + systemd.services.vector.serviceConfig.EnvironmentFile = "-/run/vector/env"; + # `+` means, that the process has access to all files, to be able to write to `/run` + systemd.services.vector.serviceConfig.ExecStartPre = "+" + toString ( + pkgs.writeShellScript "vector-start-pre" '' + set -eu -o pipefail + : "''${KAFKA_URLS:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_urls" -H "Metadata-Flavor: Google")}" + : "''${KAFKA_TOPIC:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_topic" -H "Metadata-Flavor: Google")}" + + KAFKA_TOPIC="''${KAFKA_TOPIC:-tdx-google}" + + mkdir -p /run/vector + cat >/run/vector/env <&2 test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 - exec docker run --init --privileged "sha256:$DIGEST" + exec docker run --network=host --init --privileged "sha256:$DIGEST" ''; postStop = lib.mkDefault '' diff --git a/systems/x86_64-linux/tdxtest/default.nix b/systems/x86_64-linux/tdxtest/default.nix index d95dce5..96a2e8c 100644 --- a/systems/x86_64-linux/tdxtest/default.nix +++ b/systems/x86_64-linux/tdxtest/default.nix @@ -34,6 +34,11 @@ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNsmP15vH8BVKo7bdvIiiEjiQboPGcRPqJK0+bH4jKD" ]; + environment.systemPackages = with pkgs; [ + strace + tcpdump + ]; + fileSystems = { "/" = { From 908579cd602897ee244f665ca66eea474658dd87 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 13 Feb 2025 15:47:36 +0100 Subject: [PATCH 043/114] feat: rewrite google-metadata test as tdx-test Signed-off-by: Harald Hoyer --- .github/workflows/nix.yml | 2 +- Cargo.lock | 496 +++++++++++++------ Cargo.toml | 14 +- bin/google-metadata/src/main.rs | 74 --- bin/{google-metadata => tdx-test}/Cargo.toml | 10 +- bin/tdx-test/src/main.rs | 59 +++ crates/teepot/Cargo.toml | 9 + crates/teepot/src/config/mod.rs | 294 +++++++++++ crates/teepot/src/lib.rs | 3 +- packages/container-tdx-test/default.nix | 35 ++ packages/container-test-tdx/default.nix | 24 - packages/teepot/default.nix | 2 +- 12 files changed, 771 insertions(+), 251 deletions(-) delete mode 100644 bin/google-metadata/src/main.rs rename bin/{google-metadata => tdx-test}/Cargo.toml (61%) create mode 100644 bin/tdx-test/src/main.rs create mode 100644 crates/teepot/src/config/mod.rs create mode 100644 packages/container-tdx-test/default.nix delete mode 100644 packages/container-test-tdx/default.nix diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 3dafb07..f17c396 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -73,7 +73,7 @@ jobs: - { nixpackage: 'container-self-attestation-test-sgx-azure' } - { nixpackage: 'container-verify-attestation-sgx' } - { nixpackage: 'container-verify-era-proof-attestation-sgx' } - - { nixpackage: 'container-test-tdx' } + - { nixpackage: 'container-tdx-test' } steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v30 diff --git a/Cargo.lock b/Cargo.lock index 953205b..8f427cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,12 +354,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "async-trait" version = "0.1.86" @@ -460,7 +488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", @@ -481,6 +509,33 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core 0.4.5", + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.2", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.3.4" @@ -498,6 +553,26 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -1012,6 +1087,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bed69047ed42e52c7e38d6421eeb8ceefb4f2a2b52eed59137f7bad7908f6800" +[[package]] +name = "config" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf9dc8d4ef88e27a8cb23e85cb116403dedd57f7971964dc4b18ccead548901" +dependencies = [ + "async-trait", + "pathdiff", + "serde", + "serde_json", + "toml", + "winnow 0.7.1", + "yaml-rust2", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -1929,10 +2019,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -2015,18 +2103,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "google-metadata" -version = "0.3.0" -dependencies = [ - "anyhow", - "reqwest 0.12.12", - "reqwest-middleware", - "reqwest-retry", - "serde_json", - "tokio", -] - [[package]] name = "gpt" version = "4.0.0" @@ -2105,12 +2181,30 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "heck" version = "0.4.1" @@ -2296,6 +2390,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -2333,6 +2428,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -2633,18 +2741,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "intel-tee-quote-verification-sys" version = "0.2.1" @@ -3428,7 +3524,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" dependencies = [ "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry_sdk 0.20.0", +] + +[[package]] +name = "opentelemetry" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "opentelemetry-appender-tracing" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5feffc321035ad94088a7e5333abb4d84a8726e54a802e736ce9dd7237e85b" +dependencies = [ + "log", + "opentelemetry 0.27.1", + "tracing", + "tracing-core", + "tracing-log 0.2.0", + "tracing-subscriber", ] [[package]] @@ -3454,15 +3578,34 @@ dependencies = [ "futures-core", "http 0.2.12", "opentelemetry-http", - "opentelemetry-proto", - "opentelemetry-semantic-conventions", + "opentelemetry-proto 0.3.0", + "opentelemetry-semantic-conventions 0.12.0", "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry_sdk 0.20.0", "prost 0.11.9", "reqwest 0.11.27", "thiserror 1.0.69", "tokio", - "tonic", + "tonic 0.9.2", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" +dependencies = [ + "async-trait", + "futures-core", + "http 1.2.0", + "opentelemetry 0.27.1", + "opentelemetry-proto 0.27.0", + "opentelemetry_sdk 0.27.1", + "prost 0.13.5", + "thiserror 1.0.69", + "tokio", + "tonic 0.12.3", + "tracing", ] [[package]] @@ -3472,9 +3615,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" dependencies = [ "opentelemetry_api", - "opentelemetry_sdk", + "opentelemetry_sdk 0.20.0", "prost 0.11.9", - "tonic", + "tonic 0.9.2", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" +dependencies = [ + "opentelemetry 0.27.1", + "opentelemetry_sdk 0.27.1", + "prost 0.13.5", + "tonic 0.12.3", ] [[package]] @@ -3483,9 +3638,15 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" dependencies = [ - "opentelemetry", + "opentelemetry 0.20.0", ] +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fb3a2f78c2d55362cd6c313b8abedfbc0142ab3c2676822068fd2ab7d51f9b7" + [[package]] name = "opentelemetry_api" version = "0.20.0" @@ -3525,6 +3686,27 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "opentelemetry_sdk" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "opentelemetry 0.27.1", + "percent-encoding", + "rand", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "ordered-float" version = "2.10.1" @@ -3626,17 +3808,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -3644,21 +3815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -3669,7 +3826,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.8", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -3691,6 +3848,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "pe-sign" version = "0.1.10" @@ -3980,7 +4143,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.3", + "parking_lot", "prometheus-client-derive-encode", ] @@ -4015,6 +4178,16 @@ dependencies = [ "prost-derive 0.12.6", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive 0.13.5", +] + [[package]] name = "prost-build" version = "0.12.6" @@ -4062,6 +4235,19 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "prost-reflect" version = "0.12.0" @@ -4168,15 +4354,6 @@ dependencies = [ "getrandom 0.2.15", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.8" @@ -4321,52 +4498,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "reqwest-middleware" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ccd3b55e711f91a9885a2fa6fbbb2e39db1776420b062efc058c6410f7e5e3" -dependencies = [ - "anyhow", - "async-trait", - "http 1.2.0", - "reqwest 0.12.12", - "serde", - "thiserror 1.0.69", - "tower-service", -] - -[[package]] -name = "reqwest-retry" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178" -dependencies = [ - "anyhow", - "async-trait", - "futures", - "getrandom 0.2.15", - "http 1.2.0", - "hyper 1.6.0", - "parking_lot 0.11.2", - "reqwest 0.12.12", - "reqwest-middleware", - "retry-policies", - "thiserror 1.0.69", - "tokio", - "tracing", - "wasm-timer", -] - -[[package]] -name = "retry-policies" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c" -dependencies = [ - "rand", -] - [[package]] name = "rfc6979" version = "0.3.1" @@ -4886,6 +5017,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -5334,6 +5474,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "tdx-test" +version = "0.3.0" +dependencies = [ + "anyhow", + "serde", + "teepot", + "thiserror 2.0.11", + "tokio", + "tracing", +] + [[package]] name = "tee-key-preexec" version = "0.3.0" @@ -5433,11 +5585,13 @@ dependencies = [ "actix-http", "actix-web", "anyhow", + "async-trait", "awc", "base64 0.22.1", "bytemuck", "bytes", "clap 4.5.28", + "config", "const-oid", "enumset", "futures-core", @@ -5445,10 +5599,16 @@ dependencies = [ "hex", "num-integer", "num-traits", + "opentelemetry 0.27.1", + "opentelemetry-appender-tracing", + "opentelemetry-otlp 0.27.0", + "opentelemetry-semantic-conventions 0.28.0", + "opentelemetry_sdk 0.27.1", "p256", "pgp", "pkcs8 0.10.2", "rand", + "reqwest 0.12.12", "rsa", "rustls", "secp256k1 0.30.0", @@ -5464,6 +5624,7 @@ dependencies = [ "thiserror 2.0.11", "tokio", "tracing", + "tracing-futures", "tracing-log 0.2.0", "tracing-subscriber", "tracing-test", @@ -5690,7 +5851,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5764,11 +5925,26 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.23", +] + [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -5788,6 +5964,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" dependencies = [ "indexmap 2.7.1", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.7.1", ] @@ -5799,7 +5977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.7", "bytes", "futures-core", @@ -5808,7 +5986,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", "prost 0.11.9", @@ -5820,6 +5998,36 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.7.9", + "base64 0.22.1", + "bytes", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-timeout 0.5.2", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.5", + "socket2", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.4.13" @@ -5913,6 +6121,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.4" @@ -5942,8 +6160,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75327c6b667828ddc28f5e3f169036cb793c3f588d83bf0f262a7f062ffed3c8" dependencies = [ "once_cell", - "opentelemetry", - "opentelemetry_sdk", + "opentelemetry 0.20.0", + "opentelemetry_sdk 0.20.0", "smallvec", "tracing", "tracing-core", @@ -6373,21 +6591,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.77" @@ -6721,6 +6924,17 @@ dependencies = [ "tls_codec", ] +[[package]] +name = "yaml-rust2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + [[package]] name = "yoke" version = "0.7.5" @@ -7103,9 +7317,9 @@ checksum = "ff02e5df2e986592b916077f210b28a35e63d947936f99431041ad79289306e8" dependencies = [ "anyhow", "chrono", - "opentelemetry", - "opentelemetry-otlp", - "opentelemetry-semantic-conventions", + "opentelemetry 0.20.0", + "opentelemetry-otlp 0.13.0", + "opentelemetry-semantic-conventions 0.12.0", "sentry", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index c883025..fb382b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,13 @@ homepage = "https://github.com/matter-labs/teepot" actix-http = "3" actix-web = { version = "4.5", features = ["rustls-0_23"] } anyhow = "1.0.82" +async-trait = "0.1.86" awc = { version = "3.4", features = ["rustls-0_23-webpki-roots"] } base64 = "0.22.0" bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "extern_crate_std"] } bytes = "1" clap = { version = "4.5", features = ["std", "derive", "env", "error-context", "help", "usage", "wrap_help"], default-features = false } +config = { version = "0.15.8", default-features = false, features = ["yaml", "json", "toml", "async"] } const-oid = { version = "0.9", default-features = false } enumset = { version = "1.1", features = ["serde"] } futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } @@ -35,14 +37,17 @@ intel-tee-quote-verification-sys = { version = "0.2.1" } jsonrpsee-types = { version = "0.24", default-features = false } num-integer = "0.1.46" num-traits = "0.2.18" +opentelemetry = { version = "0.27.0", features = ["default", "logs"] } +opentelemetry-appender-tracing = { version = "0.27.0", features = ["experimental_metadata_attributes", "log"] } +opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "logs"] } +opentelemetry-semantic-conventions = { version = "0.28.0", features = ["semconv_experimental"] } +opentelemetry_sdk = { version = "0.27.1", features = ["tokio", "rt-tokio"] } p256 = "0.13.2" pe-sign = "0.1.10" pgp = "0.15" pkcs8 = { version = "0.10" } rand = { version = "0.8", features = ["std", "std_rng"] } reqwest = { version = "0.12", features = ["json"] } -reqwest-middleware = "0.4.0" -reqwest-retry = "0.7.0" rsa = { version = "0.9.6", features = ["sha2", "pem"] } rustls = { version = "0.23.20" } secp256k1 = { version = "0.30", features = ["rand", "global-context"] } @@ -56,11 +61,12 @@ tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCent teepot = { path = "crates/teepot" } testaso = "0.1.0" thiserror = "2.0.11" -tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time"] } +tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time", "signal"] } tracing = "0.1" tracing-actix-web = "0.7" +tracing-futures = { version = "0.2.5", features = ["std"] } tracing-log = "0.2" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "ansi"] } tracing-test = { version = "0.2.5", features = ["no-env-filter"] } url = "2.5.2" webpki-roots = "0.26.1" diff --git a/bin/google-metadata/src/main.rs b/bin/google-metadata/src/main.rs deleted file mode 100644 index 33bdc66..0000000 --- a/bin/google-metadata/src/main.rs +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2025 Matter Labs - -use anyhow::{bail, Result}; -use reqwest::Client; -use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; -use reqwest_retry::{policies::ExponentialBackoff, Jitter, RetryTransientMiddleware}; -use serde_json::Value; -use std::time::Duration; - -const DEFAULT_INSTANCE_METADATA_BASE_URL: &str = - "http://metadata.google.internal/computeMetadata/v1/instance/attributes"; - -async fn fetch_gcp_metadata( - http_client: &ClientWithMiddleware, - metadata_key: &str, -) -> Result { - // Validate the metadata key: - if metadata_key.is_empty() { - bail!("Empty metadata_key"); - } - - let url = format!("{DEFAULT_INSTANCE_METADATA_BASE_URL}/{metadata_key}"); - - // Make an HTTP GET request: - let response = http_client - .get(url) - .header("Metadata-Flavor", "Google") - .send() - .await?; - - // Handle response: - if response.status().is_success() { - let metadata_text = response.text().await?; - serde_json::from_str(&metadata_text) - .map_err(|e| anyhow::format_err!("Failed to parse metadata JSON: {}", e)) - } else { - let status = response.status(); - let error_body = response - .text() - .await - .unwrap_or_else(|_| "".to_string()); - bail!( - "Failed to fetch metadata: {}, Response body: {}", - status, - error_body - ); - } -} - -#[tokio::main] -async fn main() -> Result<()> { - // Build the client with retry middleware and exponential backoff: - let retry_policy = ExponentialBackoff::builder() - .retry_bounds(Duration::from_secs(1), Duration::from_secs(32)) - .jitter(Jitter::Bounded) - .base(2) - .build_with_total_retry_duration(Duration::from_secs(60)); - let client = ClientBuilder::new(Client::builder().build()?) // Underlying reqwest client - .with(RetryTransientMiddleware::new_with_policy(retry_policy)) // Add retry middleware - .build(); - - // Fetch and display metadata: - match fetch_gcp_metadata(&client, "container_config").await { - Ok(container_config) => { - println!("Container config:\n{:#?}", container_config); - } - Err(e) => { - eprintln!("Error fetching container config: {}", e); - } - } - - Ok(()) -} diff --git a/bin/google-metadata/Cargo.toml b/bin/tdx-test/Cargo.toml similarity index 61% rename from bin/google-metadata/Cargo.toml rename to bin/tdx-test/Cargo.toml index 15e1a98..ea2a368 100644 --- a/bin/google-metadata/Cargo.toml +++ b/bin/tdx-test/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "google-metadata" +name = "tdx-test" version.workspace = true edition.workspace = true authors.workspace = true @@ -9,8 +9,8 @@ homepage.workspace = true [dependencies] anyhow.workspace = true -reqwest.workspace = true -reqwest-middleware.workspace = true -reqwest-retry.workspace = true -serde_json.workspace = true +serde.workspace = true +teepot.workspace = true +thiserror.workspace = true tokio.workspace = true +tracing.workspace = true diff --git a/bin/tdx-test/src/main.rs b/bin/tdx-test/src/main.rs new file mode 100644 index 0000000..217b5c2 --- /dev/null +++ b/bin/tdx-test/src/main.rs @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use teepot::config::{load_config_with_telemetry, TelemetryConfig}; +use thiserror::Error; +use tracing::{debug, error, info, trace, warn}; + +// Configuration struct +#[derive(Debug, Serialize, Deserialize)] +struct AppConfig { + server: ServerConfig, + telemetry: TelemetryConfig, +} + +impl Default for AppConfig { + fn default() -> Self { + Self { + server: ServerConfig::default(), + telemetry: TelemetryConfig::new( + env!("CARGO_CRATE_NAME").into(), + env!("CARGO_PKG_VERSION").into(), + ), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct ServerConfig { + port: u16, +} + +impl Default for ServerConfig { + fn default() -> Self { + Self { port: 8080 } + } +} + +// Error handling +#[derive(Error, Debug)] +enum AppError { + #[error("Internal server error")] + Internal(#[from] anyhow::Error), +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let config = load_config_with_telemetry(|config: &AppConfig| &config.telemetry).await?; + + loop { + error!(?config, "error test!"); + warn!(?config, "warn test!"); + info!(?config, "info test!"); + debug!(?config, "debug test!"); + trace!(?config, "trace test!"); + tokio::time::sleep(std::time::Duration::from_secs(60)).await; + } +} diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index 3b3b6b8..ca0731e 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -14,10 +14,12 @@ repository.workspace = true actix-http.workspace = true actix-web.workspace = true anyhow.workspace = true +async-trait.workspace = true awc.workspace = true bytemuck.workspace = true bytes.workspace = true clap.workspace = true +config.workspace = true const-oid.workspace = true enumset.workspace = true futures-core.workspace = true @@ -26,10 +28,16 @@ hex.workspace = true intel-tee-quote-verification-rs.workspace = true num-integer.workspace = true num-traits.workspace = true +opentelemetry.workspace = true +opentelemetry-appender-tracing.workspace = true +opentelemetry-otlp.workspace = true +opentelemetry-semantic-conventions.workspace = true +opentelemetry_sdk.workspace = true p256.workspace = true pgp.workspace = true pkcs8.workspace = true rand.workspace = true +reqwest.workspace = true rsa.workspace = true rustls.workspace = true secp256k1 = { workspace = true, features = ["recovery"] } @@ -42,6 +50,7 @@ signature.workspace = true tdx-attest-rs.workspace = true thiserror.workspace = true tracing.workspace = true +tracing-futures.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true webpki-roots.workspace = true diff --git a/crates/teepot/src/config/mod.rs b/crates/teepot/src/config/mod.rs new file mode 100644 index 0000000..b5f7595 --- /dev/null +++ b/crates/teepot/src/config/mod.rs @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +//! Configuration handling + +use async_trait::async_trait; +use config::{ + builder::AsyncState, AsyncSource, Config, ConfigBuilder, ConfigError, File, FileFormat, Format, + Map, +}; +use opentelemetry::KeyValue; +use opentelemetry_otlp::WithExportConfig; +use opentelemetry_sdk::{logs::LoggerProvider, runtime, Resource}; +use opentelemetry_semantic_conventions::{ + attribute::{SERVICE_NAME, SERVICE_VERSION}, + SCHEMA_URL, +}; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; +use tracing::trace; +use tracing_subscriber::{ + fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, +}; + +const DEFAULT_INSTANCE_METADATA_BASE_URL: &str = + "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_config"; + +/// Get the configuration via HTTP +#[derive(Debug)] +pub struct HttpSource { + /// the URI + pub uri: String, + /// the expected format + pub format: F, + /// if this is required, it will error, if not available + pub required: bool, +} + +#[async_trait] +impl AsyncSource for HttpSource { + async fn collect(&self) -> Result, ConfigError> { + let response = match reqwest::get(&self.uri) + .await + .map_err(|e| ConfigError::Foreign(Box::new(e))) + { + Ok(response) => response, + Err(e) => { + if self.required { + return Err(e); + } else { + return Ok(Map::new()); + } + } + }; + + // error conversion is possible from custom AsyncSource impls + response + .text() + .await + .map_err(|e| ConfigError::Foreign(Box::new(e))) + .and_then(|text| { + self.format + .parse(Some(&self.uri), &text) + .map_err(ConfigError::Foreign) + }) + .or_else(|res| { + if self.required { + Err(res) + } else { + Ok(Map::new()) + } + }) + } +} + +/// Main telemetry configuration container +#[derive(Debug, Serialize, Deserialize)] +pub struct TelemetryConfig { + /// The crate name `env!("CARGO_CRATE_NAME")` + pub crate_name: String, + /// The package version `env!("CARGO_PKG_VERSION")` + pub pkg_version: String, + /// OpenTelemetry Protocol (OTLP) specific settings + pub otlp: TelemetryOtlpConfig, + /// Logging-specific configuration + pub logging: TelemetryLoggingConfig, +} + +impl TelemetryConfig { + /// Create a new TelemetryConfig, usually with + /// ```rust, + /// # use teepot::config::TelemetryConfig; + /// let telemetry_config = TelemetryConfig::new( + /// env!("CARGO_CRATE_NAME").into(), + /// env!("CARGO_PKG_VERSION").into(), + /// ); + /// ``` + pub fn new(crate_name: String, pkg_version: String) -> Self { + Self { + crate_name, + pkg_version, + otlp: TelemetryOtlpConfig::default(), + logging: TelemetryLoggingConfig::default(), + } + } +} + +/// Configuration for logging behavior +#[derive(Debug, Serialize, Deserialize)] +pub struct TelemetryLoggingConfig { + /// The logging level (e.g., "debug", "info", "warn", "error") + pub level: String, + /// Whether to output logs in JSON format + pub json: bool, + /// Whether to output logs to console + pub console: bool, +} + +impl Default for TelemetryLoggingConfig { + fn default() -> Self { + Self { + level: "warn".into(), + json: false, + console: true, + } + } +} + +/// OpenTelemetry Protocol specific configuration +#[derive(Debug, Serialize, Deserialize)] +pub struct TelemetryOtlpConfig { + /// Controls whether OpenTelemetry Protocol (OTLP) export is enabled. + /// FIXME: has no effect right now + pub enable: bool, + /// The endpoint URL for the OpenTelemetry collector + pub endpoint: String, + /// The protocol to use for OTLP communication (e.g., "grpc", "http/protobuf") + pub protocol: String, +} + +impl Default for TelemetryOtlpConfig { + fn default() -> Self { + Self { + enable: true, + endpoint: "127.0.0.1:4317".to_string(), + protocol: "grpc".to_string(), + } + } +} + +fn protocol_from_string(protocol: &str) -> Result { + match protocol.to_lowercase().as_str() { + "http/protobuf" => Ok(opentelemetry_otlp::Protocol::HttpBinary), + "http/json" => Ok(opentelemetry_otlp::Protocol::HttpJson), + "grpc" => Ok(opentelemetry_otlp::Protocol::Grpc), + _ => Err(anyhow::anyhow!("Invalid protocol")), + } +} + +/// Loads configuration and sets up logging based on the provided configuration accessor +/// +/// # Type Parameters +/// * `S` - Configuration type that implements Default, Serialize, Deserialize, and Send +/// +/// # Arguments +/// * `get_telemetry_config` - Function to extract `TelemetryConfig` from type `S` +/// +/// # Returns +/// * `Result` - The loaded configuration or error +pub async fn load_config_with_telemetry< + S: Default + Serialize + for<'a> Deserialize<'a> + Send + 'static, +>( + get_telemetry_config: fn(&S) -> &TelemetryConfig, +) -> Result> { + with_console_logging(async move { + trace!("Loading config"); + // Load configuration + let config = ConfigBuilder::::default() + .add_source(Config::try_from(&S::default())?) + .add_source(File::with_name("config/default").required(false)) + .add_source( + config::Environment::with_prefix("APP") + .try_parsing(true) + .separator("_"), + ) + .add_async_source(HttpSource { + uri: DEFAULT_INSTANCE_METADATA_BASE_URL.into(), + format: FileFormat::Json, + required: false, + }) + .build() + .await? + .try_deserialize::()?; + + // Initialize telemetry + init_telemetry(get_telemetry_config(&config))?; + Ok::>(config) + }) + .await +} + +fn create_console_format_layer() -> tracing_subscriber::fmt::Layer +where + S: for<'a> tracing::Subscriber + Send + Sync + 'static, +{ + tracing_subscriber::fmt::layer() + .with_target(true) + .with_thread_ids(true) + .with_line_number(true) + .with_file(true) + .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) + .with_ansi(true) + .with_thread_names(true) +} + +async fn with_console_logging(fut: F) -> F::Output +where + F: std::future::Future + Send + 'static, + F::Output: Send + 'static, +{ + // Configure console logging + let fmt_layer = create_console_format_layer(); + + let subs = tracing_subscriber::registry() + .with(EnvFilter::new("trace")) + .with(fmt_layer.pretty()); + + let _default = tracing::subscriber::set_default(subs); + + tracing_futures::WithSubscriber::with_current_subscriber(fut).await +} + +fn init_telemetry( + config: &TelemetryConfig, +) -> Result<(), Box> { + std::env::set_var( + "RUST_LOG", + std::env::var("RUST_LOG").unwrap_or_else(|_| { + format!( + // `otel::tracing` should be a level info to emit opentelemetry trace & span + // `otel::setup` set to debug to log detected resources, configuration read and infered + "warn,{crate_name}={log_level},teepot={log_level},otel::tracing=error,otel=error", + log_level = config.logging.level, + crate_name = config.crate_name + ) + }), + ); + // Configure OpenTelemetry resource + let resource = Resource::from_schema_url( + [ + KeyValue::new(SERVICE_NAME, config.crate_name.clone()), + KeyValue::new(SERVICE_VERSION, config.pkg_version.clone()), + ], + SCHEMA_URL, + ); + + // Configure the OTLP exporter + let logging_provider = LoggerProvider::builder() + .with_batch_exporter( + opentelemetry_otlp::LogExporter::builder() + .with_tonic() + .with_endpoint(&config.otlp.endpoint) + .with_protocol(protocol_from_string(&config.otlp.protocol)?) + .build()?, + runtime::Tokio, + ) + .with_resource(resource) + .build(); + + let logging_layer = + opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge::new(&logging_provider); + + // Configure console logging + let fmt_layer = create_console_format_layer(); + + // Combine layers based on configuration + let subscriber = tracing_subscriber::registry() + .with(EnvFilter::from_default_env()) + .with(logging_layer); + + // Add console logging if enabled + if config.logging.console { + // Optionally configure JSON logging + if config.logging.json { + subscriber.with(fmt_layer.json()).init() + } else { + subscriber.with(fmt_layer.pretty()).init() + } + } else { + subscriber.init() + }; + + Ok(()) +} diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 8f73489..1860eb3 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Helper functions to verify Intel SGX enclaves and other TEEs. @@ -7,6 +7,7 @@ #![deny(clippy::all)] pub mod client; +pub mod config; pub mod ethereum; pub mod json; pub mod log; diff --git a/packages/container-tdx-test/default.nix b/packages/container-tdx-test/default.nix new file mode 100644 index 0000000..e12c646 --- /dev/null +++ b/packages/container-tdx-test/default.nix @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ lib +, openssl +, curl +, dockerTools +, buildEnv +, teepot +, nixsgx +}: +dockerTools.buildLayeredImage { + name = "tdx-test"; + + config.Entrypoint = [ "${teepot.teepot.tdx_test}/bin/tdx-test-dcap" ]; + config.Env = [ + "SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt" + ]; + + contents = buildEnv { + name = "image-root"; + + paths = with dockerTools;[ + teepot.teepot.tdx_test + openssl.out + curl.out + nixsgx.sgx-dcap.quote_verify + nixsgx.sgx-dcap.default_qpl + usrBinEnv + binSh + caCertificates + fakeNss + ]; + pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; + }; +} diff --git a/packages/container-test-tdx/default.nix b/packages/container-test-tdx/default.nix deleted file mode 100644 index fd32c49..0000000 --- a/packages/container-test-tdx/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2024 Matter Labs -{ dockerTools -, buildEnv -, teepot -}: -dockerTools.buildLayeredImage { - name = "test-tdx"; - - config.Entrypoint = [ "${teepot.teepot.google_metadata}/bin/google-metadata" ]; - config.Env = [ "LD_LIBRARY_PATH=/lib" ]; - contents = buildEnv { - name = "image-root"; - - paths = with dockerTools;[ - teepot.teepot.google_metadata - usrBinEnv - binSh - caCertificates - fakeNss - ]; - pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; - }; -} diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index 1ab7982..9aee174 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -19,7 +19,7 @@ teepotCrate.craneLib.buildPackage ( outputs = [ "out" - "google_metadata" + "tdx_test" "rtmr_calc" "sha384_extend" "tdx_extend" From a41460b7f0cf5122f9c93555da406d29055ccd69 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 13 Feb 2025 15:46:23 +0100 Subject: [PATCH 044/114] feat(tdx-google): enhance container service setup - Add `vector.service` and `chronyd.service` dependencies to `docker_start_container` service. - Use `EnvironmentFile` and a pre-start script to dynamically generate environment variables for container setup. - Improve error handling and clarity in container initialization. --- bin/tdx-test/src/main.rs | 3 +- crates/teepot/src/config/mod.rs | 40 ++++++++++++++++----------- packages/tdx_google/configuration.nix | 35 +++++++++++++++-------- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/bin/tdx-test/src/main.rs b/bin/tdx-test/src/main.rs index 217b5c2..539f859 100644 --- a/bin/tdx-test/src/main.rs +++ b/bin/tdx-test/src/main.rs @@ -46,7 +46,8 @@ enum AppError { #[tokio::main] async fn main() -> Result<(), Box> { - let config = load_config_with_telemetry(|config: &AppConfig| &config.telemetry).await?; + let config = + load_config_with_telemetry("APP".into(), |config: &AppConfig| &config.telemetry).await?; loop { error!(?config, "error test!"); diff --git a/crates/teepot/src/config/mod.rs b/crates/teepot/src/config/mod.rs index b5f7595..5cf24a0 100644 --- a/crates/teepot/src/config/mod.rs +++ b/crates/teepot/src/config/mod.rs @@ -170,27 +170,35 @@ fn protocol_from_string(protocol: &str) -> Result Deserialize<'a> + Send + 'static, >( + env_prefix: String, get_telemetry_config: fn(&S) -> &TelemetryConfig, ) -> Result> { with_console_logging(async move { trace!("Loading config"); // Load configuration - let config = ConfigBuilder::::default() - .add_source(Config::try_from(&S::default())?) - .add_source(File::with_name("config/default").required(false)) - .add_source( - config::Environment::with_prefix("APP") - .try_parsing(true) - .separator("_"), - ) - .add_async_source(HttpSource { - uri: DEFAULT_INSTANCE_METADATA_BASE_URL.into(), - format: FileFormat::Json, - required: false, - }) - .build() - .await? - .try_deserialize::()?; + let config = { + let c = ConfigBuilder::::default() + .add_source(Config::try_from(&S::default())?) + .add_source(File::with_name("config/default").required(false)) + .add_source( + config::Environment::with_prefix(&env_prefix) + .try_parsing(true) + .separator("_"), + ); + + if std::env::var_os("GOOGLE_METADATA").is_some() { + c.add_async_source(HttpSource { + uri: DEFAULT_INSTANCE_METADATA_BASE_URL.into(), + format: FileFormat::Json, + required: false, + }) + .build() + .await? + .try_deserialize::()? + } else { + c.build().await?.try_deserialize::()? + } + }; // Initialize telemetry init_telemetry(get_telemetry_config(&config))?; diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index 9c6b663..9111999 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -85,23 +85,36 @@ systemd.services.docker_start_container = { description = "The main application container"; wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "docker.service" ]; - requires = [ "network-online.target" "docker.service" ]; + after = [ "network-online.target" "docker.service" "vector.service" "chronyd.service" ]; + requires = [ "network-online.target" "docker.service" "vector.service" ]; serviceConfig = { Type = "exec"; User = "root"; + EnvironmentFile = "-/run/container/env"; + ExecStartPre = "+" + toString ( + pkgs.writeShellScript "container-start-pre" '' + set -eu -o pipefail + : "''${CONTAINER_IMAGE:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_image" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_HUB:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_hub" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_USER:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_user" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_TOKEN:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_token" -H "Metadata-Flavor: Google")}" + + : "''${CONTAINER_IMAGE:?Error: Missing CONTAINER_IMAGE}" + : "''${CONTAINER_HUB:?Error: Missing CONTAINER_HUB}" + + mkdir -p /run/container + cat >/run/container/env <&2 test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 - exec docker run --network=host --init --privileged "sha256:$DIGEST" + exec docker run --env "GOOGLE_METADATA=1" --network=host --init --privileged "sha256:$DIGEST" ''; postStop = lib.mkDefault '' From fbbb37ca5a2e5bf521c0b721649ecd75a62f472e Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 13 Feb 2025 15:40:20 +0100 Subject: [PATCH 045/114] tests(tdxtest): ramp up the testing Signed-off-by: Harald Hoyer --- systems/x86_64-linux/tdxtest/default.nix | 147 ++++-------------- .../v1/instance/attributes/container_config | 21 +++ .../v1/instance/attributes/container_hub | 1 + .../v1/instance/attributes/container_image | 1 + .../v1/instance/attributes/kafka_topic | 1 + .../v1/instance/attributes/kafka_urls | 1 + 6 files changed, 52 insertions(+), 120 deletions(-) create mode 100644 systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_config create mode 100644 systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_hub create mode 100644 systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image create mode 100644 systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_topic create mode 100644 systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_urls diff --git a/systems/x86_64-linux/tdxtest/default.nix b/systems/x86_64-linux/tdxtest/default.nix index 96a2e8c..668d840 100644 --- a/systems/x86_64-linux/tdxtest/default.nix +++ b/systems/x86_64-linux/tdxtest/default.nix @@ -7,13 +7,33 @@ ./../../../packages/tdx_google/configuration.nix ]; + networking.hosts = { + "127.0.0.100" = [ "metadata.google.internal" ]; + # might want to run kafka on the testing host + "10.0.2.2" = [ "kafka" ]; + }; + + # emulate metadata.google.internal + services.static-web-server = { + enable = true; + listen = "127.0.0.100:80"; + root = ./web-root; + }; + + # systemd.services.vector = { + # environment = { + # KAFKA_URLS = "10.0.2.2:9092"; + # KAFKA_TOPIC = "tdx-google-test"; + # }; + # }; + systemd.services.docker_start_container = { - environment = { - CONTAINER_IMAGE = "amd64/hello-world@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57"; - CONTAINER_HUB = "docker.io"; - CONTAINER_USER = ""; - CONTAINER_TOKEN = ""; - }; + # environment = { + # CONTAINER_IMAGE = "matterlabsrobot/tdx-test:pnj1ryxxb8gbzk9wh18s9bcqrzr1z9ff"; + # CONTAINER_HUB = "docker.io"; + # CONTAINER_TOKEN = ""; + # CONTAINER_USER = ""; + # }; postStop = '' : @@ -37,6 +57,7 @@ environment.systemPackages = with pkgs; [ strace tcpdump + static-web-server ]; @@ -60,118 +81,4 @@ cores = 4; }; }; - - /* - services.loki = { - enable = true; - configuration = { - server.http_listen_port = 3030; - auth_enabled = false; - analytics.reporting_enabled = false; - - ingester = { - lifecycler = { - address = "127.0.0.1"; - ring = { - kvstore = { - store = "inmemory"; - }; - replication_factor = 1; - }; - }; - chunk_idle_period = "1h"; - max_chunk_age = "1h"; - chunk_target_size = 999999; - chunk_retain_period = "30s"; - }; - - schema_config = { - configs = [ - { - from = "2024-04-25"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - ]; - }; - - storage_config = { - tsdb_shipper = { - active_index_directory = "/var/lib/loki/tsdb-shipper-active"; - cache_location = "/var/lib/loki/tsdb-shipper-cache"; - cache_ttl = "24h"; - }; - - filesystem = { - directory = "/var/lib/loki/chunks"; - }; - }; - - limits_config = { - reject_old_samples = true; - reject_old_samples_max_age = "168h"; - volume_enabled = true; - }; - - - table_manager = { - retention_deletes_enabled = false; - retention_period = "0s"; - }; - - compactor = { - working_directory = "/var/lib/loki"; - compactor_ring = { - kvstore = { - store = "inmemory"; - }; - }; - }; - }; - }; - - services.promtail = { - enable = true; - configuration = { - server = { - http_listen_port = 3031; - grpc_listen_port = 0; - }; - clients = [ - { - url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}/loki/api/v1/push"; - } - ]; - scrape_configs = [{ - job_name = "journal"; - journal = { - max_age = "12h"; - labels = { - job = "systemd-journal"; - }; - }; - relabel_configs = [ - { - source_labels = [ "__journal__systemd_unit" ]; - target_label = "systemd_unit"; - } - { - source_labels = [ "__journal__hostname" ]; - target_label = "nodename"; - } - { - source_labels = [ "__journal_container_id" ]; - target_label = "container_id"; - } - ]; - }]; - }; - # extraFlags - }; - */ } diff --git a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_config b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_config new file mode 100644 index 0000000..3258906 --- /dev/null +++ b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_config @@ -0,0 +1,21 @@ +{ + "server": { + "port": 8080, + "timeout_seconds": 30 + }, + "metrics": { + "port": 9000 + }, + "telemetry": { + "otlp": { + "enable": true, + "endpoint": "http://127.0.0.1:4317", + "protocol": "grpc" + }, + "logging": { + "level": "trace", + "console": true, + "json": false + } + } +} diff --git a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_hub b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_hub new file mode 100644 index 0000000..243e482 --- /dev/null +++ b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_hub @@ -0,0 +1 @@ +docker.io diff --git a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image new file mode 100644 index 0000000..8b18200 --- /dev/null +++ b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image @@ -0,0 +1 @@ +matterlabsrobot/tdx-test:81hgl91s5hj0sb83c7ij9acf2s5qjvb5 diff --git a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_topic b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_topic new file mode 100644 index 0000000..fba611d --- /dev/null +++ b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_topic @@ -0,0 +1 @@ +tdx-google diff --git a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_urls b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_urls new file mode 100644 index 0000000..8758015 --- /dev/null +++ b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/kafka_urls @@ -0,0 +1 @@ +10.0.2.2:9092 From daf375836b2785f901885b2359803e6d448f82dc Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 13 Feb 2025 15:41:23 +0100 Subject: [PATCH 046/114] chore: remove unused deps Signed-off-by: Harald Hoyer --- Cargo.lock | 4 ---- bin/tee-key-preexec/Cargo.toml | 1 - bin/vault-admin/Cargo.toml | 2 -- bin/verify-attestation/Cargo.toml | 1 - 4 files changed, 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f427cc..808055e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5492,7 +5492,6 @@ version = "0.3.0" dependencies = [ "anyhow", "clap 4.5.28", - "hex", "rand", "secp256k1 0.30.0", "teepot", @@ -6376,8 +6375,6 @@ dependencies = [ "serde_json", "teepot", "tracing", - "tracing-log 0.2.0", - "tracing-subscriber", ] [[package]] @@ -6415,7 +6412,6 @@ dependencies = [ "clap 4.5.28", "hex", "secp256k1 0.30.0", - "sha3", "teepot", "zksync_basic_types", ] diff --git a/bin/tee-key-preexec/Cargo.toml b/bin/tee-key-preexec/Cargo.toml index 20d3e37..e5a62cc 100644 --- a/bin/tee-key-preexec/Cargo.toml +++ b/bin/tee-key-preexec/Cargo.toml @@ -12,7 +12,6 @@ repository.workspace = true [dependencies] anyhow.workspace = true clap.workspace = true -hex.workspace = true rand.workspace = true secp256k1.workspace = true teepot.workspace = true diff --git a/bin/vault-admin/Cargo.toml b/bin/vault-admin/Cargo.toml index 3bd199b..b9c7e12 100644 --- a/bin/vault-admin/Cargo.toml +++ b/bin/vault-admin/Cargo.toml @@ -17,5 +17,3 @@ pgp.workspace = true serde_json.workspace = true teepot.workspace = true tracing.workspace = true -tracing-log.workspace = true -tracing-subscriber.workspace = true diff --git a/bin/verify-attestation/Cargo.toml b/bin/verify-attestation/Cargo.toml index 5a7c276..ff473d9 100644 --- a/bin/verify-attestation/Cargo.toml +++ b/bin/verify-attestation/Cargo.toml @@ -12,6 +12,5 @@ anyhow.workspace = true clap.workspace = true hex.workspace = true secp256k1.workspace = true -sha3.workspace = true teepot.workspace = true zksync_basic_types.workspace = true From bbbce81541fc9d48844b85a05a490d9e7efa25cb Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 19 Feb 2025 11:16:34 +0100 Subject: [PATCH 047/114] feat(configuration): update journald and serial settings - Set journald console to `/dev/ttyS0` for improved logging. - Disable `serial-getty@ttyS0` service to avoid conflicts. --- packages/tdx_google/configuration.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index 9111999..89973a5 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -63,6 +63,9 @@ '' ); + services.journald.console = "/dev/ttyS0"; + systemd.services."serial-getty@ttyS0".enable = lib.mkForce false; + # the container might want to listen on ports networking.firewall.enable = true; networking.firewall.allowedTCPPortRanges = [{ from = 1024; to = 65535; }]; From 98a71b3e3ad2eb6da4cc4e0b366b6ba3e3baf17e Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 19 Feb 2025 13:58:39 +0100 Subject: [PATCH 048/114] fix(teepot): add custom HTTP header for google metadata and update default endpoint - Replace `reqwest::get` with a configured `reqwest::Client` to support custom headers (e.g., "Metadata-Flavor: Google"). - Update default OTLP endpoint to include the "http://" prefix for clarity. --- crates/teepot/src/config/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/teepot/src/config/mod.rs b/crates/teepot/src/config/mod.rs index 5cf24a0..dea99ce 100644 --- a/crates/teepot/src/config/mod.rs +++ b/crates/teepot/src/config/mod.rs @@ -39,7 +39,12 @@ pub struct HttpSource { #[async_trait] impl AsyncSource for HttpSource { async fn collect(&self) -> Result, ConfigError> { - let response = match reqwest::get(&self.uri) + let response = match reqwest::Client::builder() + .build() + .map_err(|e| ConfigError::Foreign(Box::new(e)))? + .get(&self.uri) + .header("Metadata-Flavor", "Google") + .send() .await .map_err(|e| ConfigError::Foreign(Box::new(e))) { @@ -142,7 +147,7 @@ impl Default for TelemetryOtlpConfig { fn default() -> Self { Self { enable: true, - endpoint: "127.0.0.1:4317".to_string(), + endpoint: "http://127.0.0.1:4317".to_string(), protocol: "grpc".to_string(), } } From 5d2ad57cfdd97ea9b26e223be48f6e2dce97829c Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 19 Feb 2025 10:57:46 +0100 Subject: [PATCH 049/114] refactor(tdx_google): modularize tdx_google configuration - Split `tdx_google/configuration.nix` into smaller modules: `vector.nix`, and `container.nix`. - Simplified the main configuration by leveraging modular imports for better readability and maintainability. Signed-off-by: Harald Hoyer # Conflicts: # packages/tdx_google/configuration.nix --- packages/tdx_google/configuration.nix | 107 -------------------------- packages/tdx_google/container.nix | 57 ++++++++++++++ packages/tdx_google/vector.nix | 60 +++++++++++++++ 3 files changed, 117 insertions(+), 107 deletions(-) create mode 100644 packages/tdx_google/container.nix create mode 100644 packages/tdx_google/vector.nix diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index 89973a5..cba2e4f 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -8,61 +8,6 @@ "${toString modulesPath}/profiles/qemu-guest.nix" ]; - services.vector.enable = true; - services.vector.settings = { - api.enabled = false; - sources = { - otlp = { - type = "opentelemetry"; - grpc = { address = "127.0.0.1:4317"; }; - http = { - address = "127.0.0.1:4318"; - keepalive = { - max_connection_age_jitter_factor = 0.1; - max_connection_age_secs = 300; - }; - }; - }; - }; - sinks = { - console = { - inputs = [ "otlp.logs" ]; - target = "stdout"; - type = "console"; - encoding = { codec = "json"; }; - }; - kafka = { - type = "kafka"; - inputs = [ "otlp.logs" ]; - bootstrap_servers = "\${KAFKA_URLS:-127.0.0.1:0}"; - topic = "\${KAFKA_TOPIC:-tdx-google}"; - encoding = { - codec = "json"; - compression = "lz4"; - }; - }; - }; - }; - systemd.services.vector.path = [ pkgs.curl pkgs.coreutils ]; - # `-` means, that the file can be missing, so that `ExecStartPre` can execute and create it - systemd.services.vector.serviceConfig.EnvironmentFile = "-/run/vector/env"; - # `+` means, that the process has access to all files, to be able to write to `/run` - systemd.services.vector.serviceConfig.ExecStartPre = "+" + toString ( - pkgs.writeShellScript "vector-start-pre" '' - set -eu -o pipefail - : "''${KAFKA_URLS:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_urls" -H "Metadata-Flavor: Google")}" - : "''${KAFKA_TOPIC:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_topic" -H "Metadata-Flavor: Google")}" - - KAFKA_TOPIC="''${KAFKA_TOPIC:-tdx-google}" - - mkdir -p /run/vector - cat >/run/vector/env </run/container/env <&2 - test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 - exec docker run --env "GOOGLE_METADATA=1" --network=host --init --privileged "sha256:$DIGEST" - ''; - - postStop = lib.mkDefault '' - shutdown --reboot +5 - ''; - }; - services.prometheus.exporters.node = { enable = true; port = 9100; diff --git a/packages/tdx_google/container.nix b/packages/tdx_google/container.nix new file mode 100644 index 0000000..19ced88 --- /dev/null +++ b/packages/tdx_google/container.nix @@ -0,0 +1,57 @@ +{ lib +, modulesPath +, pkgs +, ... +}: { + virtualisation.docker.enable = true; + + systemd.services.docker_start_container = { + description = "The main application container"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "docker.service" "vector.service" "chronyd.service" ]; + requires = [ "network-online.target" "docker.service" "vector.service" ]; + serviceConfig = { + Type = "exec"; + User = "root"; + EnvironmentFile = "-/run/container/env"; + ExecStartPre = "+" + toString ( + pkgs.writeShellScript "container-start-pre" '' + set -eu -o pipefail + : "''${CONTAINER_IMAGE:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_image" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_HUB:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_hub" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_USER:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_user" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_TOKEN:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_token" -H "Metadata-Flavor: Google")}" + + : "''${CONTAINER_IMAGE:?Error: Missing CONTAINER_IMAGE}" + : "''${CONTAINER_HUB:?Error: Missing CONTAINER_HUB}" + + mkdir -p /run/container + cat >/run/container/env <&2 + test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 + exec docker run --env "GOOGLE_METADATA=1" --network=host --init --privileged "sha256:$DIGEST" + ''; + + postStop = lib.mkDefault '' + shutdown --reboot +5 + ''; + }; +} diff --git a/packages/tdx_google/vector.nix b/packages/tdx_google/vector.nix new file mode 100644 index 0000000..63ada3c --- /dev/null +++ b/packages/tdx_google/vector.nix @@ -0,0 +1,60 @@ +{ lib +, modulesPath +, pkgs +, ... +}: { + services.vector.enable = true; + services.vector.settings = { + api.enabled = false; + sources = { + otlp = { + type = "opentelemetry"; + grpc = { address = "127.0.0.1:4317"; }; + http = { + address = "127.0.0.1:4318"; + keepalive = { + max_connection_age_jitter_factor = 0.1; + max_connection_age_secs = 300; + }; + }; + }; + }; + sinks = { + console = { + inputs = [ "otlp.logs" ]; + target = "stdout"; + type = "console"; + encoding = { codec = "json"; }; + }; + kafka = { + type = "kafka"; + inputs = [ "otlp.logs" ]; + bootstrap_servers = "\${KAFKA_URLS:-127.0.0.1:0}"; + topic = "\${KAFKA_TOPIC:-tdx-google}"; + encoding = { + codec = "json"; + compression = "lz4"; + }; + }; + }; + }; + systemd.services.vector.path = [ pkgs.curl pkgs.coreutils ]; + # `-` means, that the file can be missing, so that `ExecStartPre` can execute and create it + systemd.services.vector.serviceConfig.EnvironmentFile = "-/run/vector/env"; + # `+` means, that the process has access to all files, to be able to write to `/run` + systemd.services.vector.serviceConfig.ExecStartPre = "+" + toString ( + pkgs.writeShellScript "vector-start-pre" '' + set -eu -o pipefail + : "''${KAFKA_URLS:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_urls" -H "Metadata-Flavor: Google")}" + : "''${KAFKA_TOPIC:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_topic" -H "Metadata-Flavor: Google")}" + + KAFKA_TOPIC="''${KAFKA_TOPIC:-tdx-google}" + + mkdir -p /run/vector + cat >/run/vector/env < Date: Wed, 19 Feb 2025 11:01:25 +0100 Subject: [PATCH 050/114] refactor(tdx_google): simplify service configurations - Replaced hardcoded metadata-fetching logic with shared metadata service. - Removed custom pre-start scripts and refactored environment handling. - Updated Vector configuration to include custom field transformations. - Streamlined container startup process and ensured proper cleanup. Signed-off-by: Harald Hoyer --- packages/tdx_google/configuration.nix | 3 ++ packages/tdx_google/container.nix | 45 +++++++---------------- packages/tdx_google/metadata.nix | 53 +++++++++++++++++++++++++++ packages/tdx_google/vector.nix | 49 ++++++++++++++----------- 4 files changed, 98 insertions(+), 52 deletions(-) create mode 100644 packages/tdx_google/metadata.nix diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index cba2e4f..0fee234 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -6,6 +6,9 @@ imports = [ "${toString modulesPath}/profiles/minimal.nix" "${toString modulesPath}/profiles/qemu-guest.nix" + ./metadata.nix + ./vector.nix + ./container.nix ]; services.journald.console = "/dev/ttyS0"; diff --git a/packages/tdx_google/container.nix b/packages/tdx_google/container.nix index 19ced88..07be8df 100644 --- a/packages/tdx_google/container.nix +++ b/packages/tdx_google/container.nix @@ -8,46 +8,29 @@ systemd.services.docker_start_container = { description = "The main application container"; wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "docker.service" "vector.service" "chronyd.service" ]; - requires = [ "network-online.target" "docker.service" "vector.service" ]; + after = [ "network-online.target" "docker.service" "vector.service" "chronyd.service" "metadata.service" ]; + requires = [ "network-online.target" "docker.service" "vector.service" "metadata.service" ]; serviceConfig = { Type = "exec"; User = "root"; - EnvironmentFile = "-/run/container/env"; - ExecStartPre = "+" + toString ( - pkgs.writeShellScript "container-start-pre" '' - set -eu -o pipefail - : "''${CONTAINER_IMAGE:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_image" -H "Metadata-Flavor: Google")}" - : "''${CONTAINER_HUB:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_hub" -H "Metadata-Flavor: Google")}" - : "''${CONTAINER_USER:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_user" -H "Metadata-Flavor: Google")}" - : "''${CONTAINER_TOKEN:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_token" -H "Metadata-Flavor: Google")}" - - : "''${CONTAINER_IMAGE:?Error: Missing CONTAINER_IMAGE}" - : "''${CONTAINER_HUB:?Error: Missing CONTAINER_HUB}" - - mkdir -p /run/container - cat >/run/container/env <&2 test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 - exec docker run --env "GOOGLE_METADATA=1" --network=host --init --privileged "sha256:$DIGEST" + + docker run -d --rm \ + --name tdx_container \ + --env "GOOGLE_METADATA=1" \ + --network=host \ + --init \ + --privileged \ + "sha256:$DIGEST" + exec docker wait tdx_container ''; postStop = lib.mkDefault '' diff --git a/packages/tdx_google/metadata.nix b/packages/tdx_google/metadata.nix new file mode 100644 index 0000000..98be396 --- /dev/null +++ b/packages/tdx_google/metadata.nix @@ -0,0 +1,53 @@ +{ lib +, modulesPath +, pkgs +, ... +}: { + systemd.services.metadata = { + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + enable = true; + path = [ pkgs.curl pkgs.docker pkgs.teepot.teepot.tdx_extend pkgs.coreutils ]; + wantedBy = [ "default.target" ]; + after = [ "network-online.target" "docker.service" ]; + requires = [ "network-online.target" "docker.service" ]; + script = '' + set -eu -o pipefail + : "''${CONTAINER_HUB:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_hub" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_IMAGE:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_image" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_TOKEN:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_token" -H "Metadata-Flavor: Google")}" + : "''${CONTAINER_USER:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/container_user" -H "Metadata-Flavor: Google")}" + : "''${HOST_ID:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/id" -H "Metadata-Flavor: Google")}" + : "''${HOST_IMAGE:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/image" -H "Metadata-Flavor: Google")}" + : "''${HOST_NAME:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/hostname" -H "Metadata-Flavor: Google")}" + : "''${KAFKA_TOPIC:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_topic" -H "Metadata-Flavor: Google")}" + : "''${KAFKA_URLS:=$(curl --silent --fail "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kafka_urls" -H "Metadata-Flavor: Google")}" + + : "''${CONTAINER_IMAGE:?Error: Missing CONTAINER_IMAGE}" + : "''${CONTAINER_HUB:?Error: Missing CONTAINER_HUB}" + + if [[ $CONTAINER_USER ]] && [[ $CONTAINER_TOKEN ]]; then + docker login -u "$CONTAINER_USER" -p "$CONTAINER_TOKEN" "$CONTAINER_HUB" + fi + + docker pull "''${CONTAINER_HUB}/''${CONTAINER_IMAGE}" + CONTAINER_DIGEST=$(docker inspect --format '{{.Id}}' "''${CONTAINER_HUB}/''${CONTAINER_IMAGE}") + + mkdir -p /run/env + cat >/run/env/env </run/vector/env < Date: Wed, 19 Feb 2025 11:09:13 +0100 Subject: [PATCH 051/114] chore(tdx_google): remove unused `teepot` package from system environment Signed-off-by: Harald Hoyer --- packages/tdx_google/configuration.nix | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/tdx_google/configuration.nix b/packages/tdx_google/configuration.nix index 0fee234..1298769 100644 --- a/packages/tdx_google/configuration.nix +++ b/packages/tdx_google/configuration.nix @@ -43,10 +43,6 @@ ]; }; - environment.systemPackages = with pkgs; [ - teepot.teepot - ]; - # /var is on tmpfs anyway services.journald.storage = "volatile"; From a5cf220c576852b1b32351aa04b3fca0119f59a2 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 20 Feb 2025 12:12:57 +0100 Subject: [PATCH 052/114] feat(tdx_google): add support for attestation in container - Mount `/sys/kernel/config` to enable attestation for TDX containers. - Ensures compatibility with TDX guest measurements during runtime. --- packages/tdx_google/container.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/tdx_google/container.nix b/packages/tdx_google/container.nix index 07be8df..701e9f1 100644 --- a/packages/tdx_google/container.nix +++ b/packages/tdx_google/container.nix @@ -23,12 +23,14 @@ echo "Measuring $DIGEST" >&2 test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 + # /sys/kernel/config is needed for attestation docker run -d --rm \ --name tdx_container \ --env "GOOGLE_METADATA=1" \ --network=host \ --init \ --privileged \ + -v /sys/kernel/config:/sys/kernel/config \ "sha256:$DIGEST" exec docker wait tdx_container ''; From 049f1b3de8e772edbe262748b9d54122cec47708 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 20 Feb 2025 14:16:44 +0100 Subject: [PATCH 053/114] feat(tdx): add TDX RTMR extension support with UEFI marker - Added `UEFI_MARKER_DIGEST_BYTES` constant for TDX RTMR extension. - Implemented RTMR3 extension in `tee-key-preexec` for TDX attestation flow. - Updated `rtmr-calc` to use `UEFI_MARKER_DIGEST_BYTES` for RTMR1 extension. Signed-off-by: Harald Hoyer --- bin/rtmr-calc/src/main.rs | 9 ++++++--- bin/tee-key-preexec/src/main.rs | 19 +++++++++++++++++-- crates/teepot/src/tdx/rtmr.rs | 27 ++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs index 97b4cf4..c49d95e 100644 --- a/bin/rtmr-calc/src/main.rs +++ b/bin/rtmr-calc/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs use anyhow::{anyhow, Result}; use clap::Parser; @@ -10,7 +10,10 @@ use std::{ io::{Error, ErrorKind, Read, Seek, SeekFrom}, path::PathBuf, }; -use teepot::log::{setup_logging, LogLevelParser}; +use teepot::{ + log::{setup_logging, LogLevelParser}, + tdx::rtmr::UEFI_MARKER_DIGEST_BYTES, +}; use tracing::{debug, info, level_filters::LevelFilter}; /// Precalculate rtmr1 and rtmr2 values. @@ -98,7 +101,7 @@ fn main() -> Result<()> { Ok: validseparator: UEFI */ - rtmr1.extend(&hex::decode("394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0")?); + rtmr1.extend(&UEFI_MARKER_DIGEST_BYTES); // Open disk image. let cfg = gpt::GptConfig::new().writable(false); diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 6399681..3eeb8b9 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs //! Pre-exec for binary running in a TEE needing attestation of a secret signing key @@ -11,7 +11,10 @@ use clap::Parser; use secp256k1::{rand, Secp256k1}; use std::{ffi::OsString, os::unix::process::CommandExt, process::Command}; use teepot::{ - ethereum::public_key_to_ethereum_address, prover::reportdata::ReportDataV1, quote::get_quote, + ethereum::public_key_to_ethereum_address, + prover::reportdata::ReportDataV1, + quote::get_quote, + tdx::rtmr::{TdxRtmrEvent, UEFI_MARKER_DIGEST_BYTES}, }; use tracing::error; use tracing_log::LogTracer; @@ -46,6 +49,18 @@ fn main_with_error() -> Result<()> { let report_data = ReportDataV1 { ethereum_address }; let report_data_bytes: [u8; 64] = report_data.into(); let tee_type = match get_quote(&report_data_bytes) { + Ok((teepot::quote::TEEType::TDX, quote)) => { + // In the case of TDX, we want to advance RTMR 3 after getting the quote, + // so that any breach can't generate a new attestation with the expected RTMRs + TdxRtmrEvent::default() + .with_rtmr_index(3) + .with_extend_data(UEFI_MARKER_DIGEST_BYTES) + .extend()?; + + // save quote to file + std::fs::write(TEE_QUOTE_FILE, quote)?; + teepot::quote::TEEType::TDX.to_string() + } Ok((tee_type, quote)) => { // save quote to file std::fs::write(TEE_QUOTE_FILE, quote)?; diff --git a/crates/teepot/src/tdx/rtmr.rs b/crates/teepot/src/tdx/rtmr.rs index bbe478e..dbb8d67 100644 --- a/crates/teepot/src/tdx/rtmr.rs +++ b/crates/teepot/src/tdx/rtmr.rs @@ -1,10 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs //! rtmr event data use crate::sgx::QuoteError; +/// The sha384 digest of 0u32, which is used in the UEFI TPM protocol +/// as a marker. Used to advance the PCR. +/// ```shell +/// $ echo -n -e "\000\000\000\000" | sha384sum -b +/// 394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0 *- +/// ``` +pub const UEFI_MARKER_DIGEST_BYTES: [u8; 48] = [ + 0x39, 0x43, 0x41, 0xb7, 0x18, 0x2c, 0xd2, 0x27, 0xc5, 0xc6, 0xb0, 0x7e, 0xf8, 0x00, 0x0c, 0xdf, + 0xd8, 0x61, 0x36, 0xc4, 0x29, 0x2b, 0x8e, 0x57, 0x65, 0x73, 0xad, 0x7e, 0xd9, 0xae, 0x41, 0x01, + 0x9f, 0x58, 0x18, 0xb4, 0xb9, 0x71, 0xc9, 0xef, 0xfc, 0x60, 0xe1, 0xad, 0x9f, 0x12, 0x89, 0xf0, +]; + /// The actual rtmr event data handled in DCAP #[repr(C, packed)] pub struct TdxRtmrEvent { @@ -88,3 +100,16 @@ impl From for Vec { res } } + +#[cfg(test)] +mod test { + use super::UEFI_MARKER_DIGEST_BYTES; + + #[test] + fn test_uefi_marker_digest() { + assert_eq!( + UEFI_MARKER_DIGEST_BYTES.to_vec(), + hex::decode("394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0").unwrap() + ); + } +} From cf4a6cfb608e01ea322d768b5c0e03b725e23880 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 20 Feb 2025 15:18:34 +0100 Subject: [PATCH 054/114] feat(tdx_google): add onFailure action to reboot on metadata.service errors - Introduce `onFailure` handler to trigger reboot after 5 minutes. - Enhances system reliability by automating recovery measures. Signed-off-by: Harald Hoyer --- packages/tdx_google/metadata.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/tdx_google/metadata.nix b/packages/tdx_google/metadata.nix index 98be396..1e7e182 100644 --- a/packages/tdx_google/metadata.nix +++ b/packages/tdx_google/metadata.nix @@ -49,5 +49,8 @@ KAFKA_URLS="''${KAFKA_URLS}" EOF ''; + postStop = lib.mkDefault '' + shutdown --reboot +5 + ''; }; } From f822c70721bd1657d1d3b2cda2db3e66a8ea62e4 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 18 Feb 2025 10:04:05 +0100 Subject: [PATCH 055/114] chore: remove unused `rand` dependency and update crates - Removed `rand` dependency from multiple `.toml` files and updated relevant imports to use `rand_core::OsRng`. - Updated OpenTelemetry dependencies to latest versions and refactored SDK initialization to use `SdkLoggerProvider`. - Bumped versions of several dependencies including `clap`, `awc`, `ring`, and `smallvec` for compatibility and features. Signed-off-by: Harald Hoyer --- Cargo.lock | 218 ++++++++++++++++++-------------- Cargo.toml | 11 +- bin/tee-key-preexec/Cargo.toml | 1 - crates/teepot/Cargo.toml | 1 - crates/teepot/src/config/mod.rs | 21 +-- crates/teepot/src/server/pki.rs | 5 +- crates/teepot/src/sgx/sign.rs | 3 +- 7 files changed, 140 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 808055e..fdb34a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,9 +337,9 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" [[package]] name = "argon2" @@ -458,9 +458,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b7ddaa2c56a367ad27a094ad8ef4faacf8a617c2575acb2ba88949df999ca" +checksum = "3c6a895b664295a4ba0c2c0203c7075ea585dd75cd5c37a8efac829e13e460ef" dependencies = [ "aws-lc-sys", "paste", @@ -469,9 +469,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ac4f13dad353b209b34cbec082338202cbc01c8f00336b55c750c13ac91f8f" +checksum = "0f9dd2e03ee80ca2822dd6ea431163d2ef259f2066a4d6ccaca6d9dcb386aa43" dependencies = [ "bindgen 0.69.5", "cc", @@ -910,9 +910,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.13" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" dependencies = [ "jobserver", "libc", @@ -1002,9 +1002,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.28" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" +checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" dependencies = [ "clap_builder", "clap_derive", @@ -1012,9 +1012,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.27" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" dependencies = [ "anstyle", "clap_lex", @@ -1098,7 +1098,7 @@ dependencies = [ "serde", "serde_json", "toml", - "winnow 0.7.1", + "winnow 0.7.3", "yaml-rust2", ] @@ -1724,9 +1724,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -2158,9 +2158,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", @@ -2386,7 +2386,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", + "h2 0.4.8", "http 1.2.0", "http-body 1.0.1", "httparse", @@ -2780,6 +2780,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -3229,9 +3238,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ "adler2", ] @@ -3262,9 +3271,9 @@ checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" [[package]] name = "native-tls" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -3475,9 +3484,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -3507,9 +3516,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" dependencies = [ "cc", "libc", @@ -3529,26 +3538,26 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7" +checksum = "236e667b670a5cdf90c258f5a55794ec5ac5027e960c224bff8367a59e1e6426" dependencies = [ "futures-core", "futures-sink", "js-sys", "pin-project-lite", - "thiserror 1.0.69", + "thiserror 2.0.11", "tracing", ] [[package]] name = "opentelemetry-appender-tracing" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5feffc321035ad94088a7e5333abb4d84a8726e54a802e736ce9dd7237e85b" +checksum = "c513c7af3bec30113f3d4620134ff923295f1e9c580fda2b8abe0831f925ddc0" dependencies = [ "log", - "opentelemetry 0.27.1", + "opentelemetry 0.28.0", "tracing", "tracing-core", "tracing-log 0.2.0", @@ -3568,6 +3577,20 @@ dependencies = [ "reqwest 0.11.27", ] +[[package]] +name = "opentelemetry-http" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8863faf2910030d139fb48715ad5ff2f35029fc5f244f6d5f689ddcf4d26253" +dependencies = [ + "async-trait", + "bytes", + "http 1.2.0", + "opentelemetry 0.28.0", + "reqwest 0.12.12", + "tracing", +] + [[package]] name = "opentelemetry-otlp" version = "0.13.0" @@ -3577,7 +3600,7 @@ dependencies = [ "async-trait", "futures-core", "http 0.2.12", - "opentelemetry-http", + "opentelemetry-http 0.9.0", "opentelemetry-proto 0.3.0", "opentelemetry-semantic-conventions 0.12.0", "opentelemetry_api", @@ -3591,18 +3614,20 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" +checksum = "5bef114c6d41bea83d6dc60eb41720eedd0261a67af57b66dd2b84ac46c01d91" dependencies = [ "async-trait", "futures-core", "http 1.2.0", - "opentelemetry 0.27.1", - "opentelemetry-proto 0.27.0", - "opentelemetry_sdk 0.27.1", + "opentelemetry 0.28.0", + "opentelemetry-http 0.28.0", + "opentelemetry-proto 0.28.0", + "opentelemetry_sdk 0.28.0", "prost 0.13.5", - "thiserror 1.0.69", + "reqwest 0.12.12", + "thiserror 2.0.11", "tokio", "tonic 0.12.3", "tracing", @@ -3622,12 +3647,12 @@ dependencies = [ [[package]] name = "opentelemetry-proto" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" +checksum = "56f8870d3024727e99212eb3bb1762ec16e255e3e6f58eeb3dc8db1aa226746d" dependencies = [ - "opentelemetry 0.27.1", - "opentelemetry_sdk 0.27.1", + "opentelemetry 0.28.0", + "opentelemetry_sdk 0.28.0", "prost 0.13.5", "tonic 0.12.3", ] @@ -3688,20 +3713,20 @@ dependencies = [ [[package]] name = "opentelemetry_sdk" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" +checksum = "84dfad6042089c7fc1f6118b7040dc2eb4ab520abbf410b79dc481032af39570" dependencies = [ "async-trait", "futures-channel", "futures-executor", "futures-util", "glob", - "opentelemetry 0.27.1", + "opentelemetry 0.28.0", "percent-encoding", "rand", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.11", "tokio", "tokio-stream", "tracing", @@ -4123,7 +4148,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.23", + "toml_edit 0.22.24", ] [[package]] @@ -4242,7 +4267,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.98", @@ -4465,7 +4490,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.7", + "h2 0.4.8", "http 1.2.0", "http-body 1.0.1", "http-body-util", @@ -4521,15 +4546,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -4579,7 +4603,7 @@ name = "rtmr-calc" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", + "clap 4.5.30", "gpt", "hex", "pe-sign", @@ -4630,9 +4654,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.22" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "aws-lc-rs", "log", @@ -4977,9 +5001,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.217" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] @@ -4996,9 +5020,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", @@ -5007,9 +5031,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", "memchr", @@ -5162,7 +5186,7 @@ name = "sha384-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", + "clap 4.5.30", "hex", "sha2", ] @@ -5238,9 +5262,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "socket2" @@ -5468,7 +5492,7 @@ name = "tdx-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", + "clap 4.5.30", "hex", "teepot", "tracing", @@ -5491,8 +5515,7 @@ name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", - "rand", + "clap 4.5.30", "secp256k1 0.30.0", "teepot", "tracing", @@ -5505,7 +5528,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", + "clap 4.5.30", "rsa", "teepot", "tracing", @@ -5533,7 +5556,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.28", + "clap 4.5.30", "serde", "teepot", "tracing", @@ -5549,7 +5572,7 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap 4.5.28", + "clap 4.5.30", "hex", "rustls", "serde_json", @@ -5568,7 +5591,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.28", + "clap 4.5.30", "rustls", "serde_json", "teepot", @@ -5589,7 +5612,7 @@ dependencies = [ "base64 0.22.1", "bytemuck", "bytes", - "clap 4.5.28", + "clap 4.5.30", "config", "const-oid", "enumset", @@ -5598,15 +5621,14 @@ dependencies = [ "hex", "num-integer", "num-traits", - "opentelemetry 0.27.1", + "opentelemetry 0.28.0", "opentelemetry-appender-tracing", - "opentelemetry-otlp 0.27.0", + "opentelemetry-otlp 0.28.0", "opentelemetry-semantic-conventions 0.28.0", - "opentelemetry_sdk 0.27.1", + "opentelemetry_sdk 0.28.0", "p256", "pgp", "pkcs8 0.10.2", - "rand", "reqwest 0.12.12", "rsa", "rustls", @@ -5640,7 +5662,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.28", + "clap 4.5.30", "serde_json", "teepot", "tracing", @@ -5663,7 +5685,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.28", + "clap 4.5.30", "serde_json", "teepot", "tracing", @@ -5673,9 +5695,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.16.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", @@ -5933,7 +5955,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.23", + "toml_edit 0.22.24", ] [[package]] @@ -5958,15 +5980,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.23" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.1", + "winnow 0.7.3", ] [[package]] @@ -6008,7 +6030,7 @@ dependencies = [ "axum 0.7.9", "base64 0.22.1", "bytes", - "h2 0.4.7", + "h2 0.4.8", "http 1.2.0", "http-body 1.0.1", "http-body-util", @@ -6238,9 +6260,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "uint" @@ -6265,9 +6287,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "unicode-width" @@ -6348,9 +6370,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" +checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" dependencies = [ "getrandom 0.3.1", "serde", @@ -6369,7 +6391,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.28", + "clap 4.5.30", "hex", "pgp", "serde_json", @@ -6384,7 +6406,7 @@ dependencies = [ "actix-web", "anyhow", "base64 0.22.1", - "clap 4.5.28", + "clap 4.5.30", "serde_json", "teepot", "tracing", @@ -6409,7 +6431,7 @@ name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", + "clap 4.5.30", "hex", "secp256k1 0.30.0", "teepot", @@ -6421,7 +6443,7 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.28", + "clap 4.5.30", "hex", "jsonrpsee-types 0.24.8", "reqwest 0.12.12", @@ -6847,9 +6869,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index fb382b2..1fce9ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ actix-http = "3" actix-web = { version = "4.5", features = ["rustls-0_23"] } anyhow = "1.0.82" async-trait = "0.1.86" -awc = { version = "3.4", features = ["rustls-0_23-webpki-roots"] } +awc = { version = "3.5", features = ["rustls-0_23-webpki-roots"] } base64 = "0.22.0" bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "extern_crate_std"] } bytes = "1" @@ -37,16 +37,15 @@ intel-tee-quote-verification-sys = { version = "0.2.1" } jsonrpsee-types = { version = "0.24", default-features = false } num-integer = "0.1.46" num-traits = "0.2.18" -opentelemetry = { version = "0.27.0", features = ["default", "logs"] } -opentelemetry-appender-tracing = { version = "0.27.0", features = ["experimental_metadata_attributes", "log"] } -opentelemetry-otlp = { version = "0.27.0", features = ["grpc-tonic", "logs"] } +opentelemetry = { version = "0.28.0", features = ["default", "logs"] } +opentelemetry-appender-tracing = { version = "0.28.1", features = ["experimental_metadata_attributes", "log"] } +opentelemetry-otlp = { version = "0.28.0", features = ["grpc-tonic", "logs"] } opentelemetry-semantic-conventions = { version = "0.28.0", features = ["semconv_experimental"] } -opentelemetry_sdk = { version = "0.27.1", features = ["tokio", "rt-tokio"] } +opentelemetry_sdk = { version = "0.28.0", features = ["tokio", "rt-tokio"] } p256 = "0.13.2" pe-sign = "0.1.10" pgp = "0.15" pkcs8 = { version = "0.10" } -rand = { version = "0.8", features = ["std", "std_rng"] } reqwest = { version = "0.12", features = ["json"] } rsa = { version = "0.9.6", features = ["sha2", "pem"] } rustls = { version = "0.23.20" } diff --git a/bin/tee-key-preexec/Cargo.toml b/bin/tee-key-preexec/Cargo.toml index e5a62cc..60a7b93 100644 --- a/bin/tee-key-preexec/Cargo.toml +++ b/bin/tee-key-preexec/Cargo.toml @@ -12,7 +12,6 @@ repository.workspace = true [dependencies] anyhow.workspace = true clap.workspace = true -rand.workspace = true secp256k1.workspace = true teepot.workspace = true tracing.workspace = true diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index ca0731e..83b7386 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -36,7 +36,6 @@ opentelemetry_sdk.workspace = true p256.workspace = true pgp.workspace = true pkcs8.workspace = true -rand.workspace = true reqwest.workspace = true rsa.workspace = true rustls.workspace = true diff --git a/crates/teepot/src/config/mod.rs b/crates/teepot/src/config/mod.rs index dea99ce..0132c62 100644 --- a/crates/teepot/src/config/mod.rs +++ b/crates/teepot/src/config/mod.rs @@ -10,7 +10,7 @@ use config::{ }; use opentelemetry::KeyValue; use opentelemetry_otlp::WithExportConfig; -use opentelemetry_sdk::{logs::LoggerProvider, runtime, Resource}; +use opentelemetry_sdk::{logs::SdkLoggerProvider, Resource}; use opentelemetry_semantic_conventions::{ attribute::{SERVICE_NAME, SERVICE_VERSION}, SCHEMA_URL, @@ -259,23 +259,24 @@ fn init_telemetry( }), ); // Configure OpenTelemetry resource - let resource = Resource::from_schema_url( - [ - KeyValue::new(SERVICE_NAME, config.crate_name.clone()), - KeyValue::new(SERVICE_VERSION, config.pkg_version.clone()), - ], - SCHEMA_URL, - ); + let resource = Resource::builder() + .with_schema_url( + [ + KeyValue::new(SERVICE_NAME, config.crate_name.clone()), + KeyValue::new(SERVICE_VERSION, config.pkg_version.clone()), + ], + SCHEMA_URL, + ) + .build(); // Configure the OTLP exporter - let logging_provider = LoggerProvider::builder() + let logging_provider = SdkLoggerProvider::builder() .with_batch_exporter( opentelemetry_otlp::LogExporter::builder() .with_tonic() .with_endpoint(&config.otlp.endpoint) .with_protocol(protocol_from_string(&config.otlp.protocol)?) .build()?, - runtime::Tokio, ) .with_resource(resource) .build(); diff --git a/crates/teepot/src/server/pki.rs b/crates/teepot/src/server/pki.rs index 305df84..b7e28d0 100644 --- a/crates/teepot/src/server/pki.rs +++ b/crates/teepot/src/server/pki.rs @@ -13,10 +13,9 @@ use const_oid::{ use intel_tee_quote_verification_rs::tee_qv_get_collateral; use p256::{ecdsa::DerSignature, pkcs8::EncodePrivateKey}; use pkcs8::der; -use rand::rngs::OsRng; use rustls::pki_types::PrivatePkcs8KeyDer; use sha2::{Digest, Sha256}; -use signature::Signer; +use signature::{rand_core::OsRng, Signer}; use std::{str::FromStr, time::Duration}; use tracing::debug; use x509_cert::{ @@ -223,7 +222,7 @@ where S::VerifyingKey: EncodePublicKey, { // Generate a keypair. - let mut rng = rand::rngs::OsRng; + let mut rng = OsRng; let signing_key = p256::ecdsa::SigningKey::random(&mut rng); let verifying_key = signing_key.verifying_key(); let verifying_key_der = verifying_key diff --git a/crates/teepot/src/sgx/sign.rs b/crates/teepot/src/sgx/sign.rs index bb73a98..4019590 100644 --- a/crates/teepot/src/sgx/sign.rs +++ b/crates/teepot/src/sgx/sign.rs @@ -14,6 +14,7 @@ use num_integer::Integer; use num_traits::ToPrimitive; use rsa::{ pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey, LineEnding}, + rand_core::OsRng, traits::PublicKeyParts, BigUint, Pkcs1v15Sign, RsaPrivateKey, }; @@ -268,7 +269,7 @@ impl PrivateKey for RS256PrivateKey { type Error = rsa::errors::Error; fn generate(exponent: u8) -> Result { - let mut rng = rand::rngs::OsRng; + let mut rng = OsRng; let exp = BigUint::from(exponent); let key = RsaPrivateKey::new_with_exp(&mut rng, 384 * 8, &exp)?; Ok(Self::new(key)) From d6061c35a8cb5ac9279382b6cdb519e241f7a8d1 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 28 Feb 2025 14:14:57 +0100 Subject: [PATCH 056/114] fix(teepot-vault): use `ring` as `CryptoProvider` for `rustls` New `rustls` needs global install of default `CryptoProvider`. Signed-off-by: Harald Hoyer --- Cargo.toml | 2 +- bin/tee-vault-admin/src/main.rs | 29 ++++++++++----------- bin/tee-vault-unseal/src/main.rs | 42 ++++++++++++++++++------------- bin/vault-admin/README.md | 2 +- bin/vault-admin/src/main.rs | 4 +-- crates/teepot/src/client/mod.rs | 43 ++++++++++++++++++++------------ 6 files changed, 70 insertions(+), 52 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1fce9ca..33f2b2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ pgp = "0.15" pkcs8 = { version = "0.10" } reqwest = { version = "0.12", features = ["json"] } rsa = { version = "0.9.6", features = ["sha2", "pem"] } -rustls = { version = "0.23.20" } +rustls = { version = "0.23.20", default-features = false, features = ["std", "logging", "tls12", "ring"] } secp256k1 = { version = "0.30", features = ["rand", "global-context"] } serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" diff --git a/bin/tee-vault-admin/src/main.rs b/bin/tee-vault-admin/src/main.rs index 6972217..d8574a9 100644 --- a/bin/tee-vault-admin/src/main.rs +++ b/bin/tee-vault-admin/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Server to handle requests to the Vault TEE @@ -9,26 +9,27 @@ mod command; mod digest; mod sign; -use actix_web::web::Data; -use actix_web::{web, App, HttpServer}; +use actix_web::{web, web::Data, App, HttpServer}; use anyhow::{Context, Result}; use clap::Parser; use command::post_command; use digest::get_digest; use rustls::ServerConfig; use sign::post_sign; -use std::net::Ipv6Addr; -use std::sync::Arc; -use teepot::json::http::{SignRequest, VaultCommandRequest, DIGEST_URL}; -use teepot::server::attestation::{get_quote_and_collateral, VaultAttestationArgs}; -use teepot::server::new_json_cfg; -use teepot::server::pki::make_self_signed_cert; -use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use std::{net::Ipv6Addr, sync::Arc}; +use teepot::{ + json::http::{SignRequest, VaultCommandRequest, DIGEST_URL}, + server::{ + attestation::{get_quote_and_collateral, VaultAttestationArgs}, + new_json_cfg, + pki::make_self_signed_cert, + }, + sgx::{parse_tcb_levels, EnumSet, TcbLevel}, +}; use tracing::{error, info}; use tracing_actix_web::TracingLogger; use tracing_log::LogTracer; -use tracing_subscriber::Registry; -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; /// Server state pub struct ServerState { @@ -70,6 +71,8 @@ async fn main() -> Result<()> { // don't return for now, we can still serve requests but we won't be able to attest } + let _ = rustls::crypto::ring::default_provider().install_default(); + // init server config builder with safe defaults let config = ServerConfig::builder() .with_no_client_auth() @@ -78,8 +81,6 @@ async fn main() -> Result<()> { info!("Starting HTTPS server at port {}", args.port); - info!("Quote verified! Connection secure!"); - let server_state = Arc::new(ServerState { report_data, vault_attestation: args.attestation, diff --git a/bin/tee-vault-unseal/src/main.rs b/bin/tee-vault-unseal/src/main.rs index b3db5c4..65ffb4f 100644 --- a/bin/tee-vault-unseal/src/main.rs +++ b/bin/tee-vault-unseal/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Server to initialize and unseal the Vault TEE. @@ -9,27 +9,33 @@ mod init; mod unseal; -use actix_web::rt::time::sleep; -use actix_web::web::Data; -use actix_web::{web, App, HttpServer}; +use actix_web::{rt::time::sleep, web, web::Data, App, HttpServer}; use anyhow::{bail, Context, Result}; use awc::Client; use clap::Parser; use init::post_init; use rustls::ServerConfig; -use std::fmt::Debug; -use std::io::Read; -use std::net::Ipv6Addr; -use std::path::PathBuf; -use std::sync::{Arc, RwLock}; -use std::time::Duration; -use teepot::client::{AttestationArgs, TeeConnection}; -use teepot::json::http::{Init, Unseal}; -use teepot::json::secrets::AdminConfig; -use teepot::server::attestation::{get_quote_and_collateral, VaultAttestationArgs}; -use teepot::server::new_json_cfg; -use teepot::server::pki::make_self_signed_cert; -use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use std::{ + fmt::Debug, + io::Read, + net::Ipv6Addr, + path::PathBuf, + sync::{Arc, RwLock}, + time::Duration, +}; +use teepot::{ + client::{AttestationArgs, TeeConnection}, + json::{ + http::{Init, Unseal}, + secrets::AdminConfig, + }, + server::{ + attestation::{get_quote_and_collateral, VaultAttestationArgs}, + new_json_cfg, + pki::make_self_signed_cert, + }, + sgx::{parse_tcb_levels, EnumSet, TcbLevel}, +}; use tracing::{error, info}; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; @@ -136,6 +142,8 @@ async fn main() -> Result<()> { let (report_data, cert_chain, priv_key) = make_self_signed_cert("CN=localhost", None)?; + let _ = rustls::crypto::ring::default_provider().install_default(); + // init server config builder with safe defaults let config = ServerConfig::builder() .with_no_client_auth() diff --git a/bin/vault-admin/README.md b/bin/vault-admin/README.md index 7685279..fb9151f 100644 --- a/bin/vault-admin/README.md +++ b/bin/vault-admin/README.md @@ -9,7 +9,7 @@ Verified signature for `81A312C59D679D930FA9E8B06D728F29A2DBABF8` ❯ RUST_LOG=info cargo run -p vault-admin -- \ - send \ + command \ --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ --sgx-allowed-tcb-levels SwHardeningNeeded \ --server https://127.0.0.1:8444 \ diff --git a/bin/vault-admin/src/main.rs b/bin/vault-admin/src/main.rs index eb123ef..1739313 100644 --- a/bin/vault-admin/src/main.rs +++ b/bin/vault-admin/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs use anyhow::{anyhow, bail, Context, Result}; use clap::{Args, Parser, Subcommand}; @@ -117,8 +117,6 @@ async fn main() -> Result<()> { &args.log_level, )?)?; - info!("Quote verified! Connection secure!"); - match args.cmd { SubCommands::Command(args) => send_commands(args).await?, SubCommands::SignTee(args) => send_sig_request(args).await?, diff --git a/crates/teepot/src/client/mod.rs b/crates/teepot/src/client/mod.rs index ea59e8c..dc76066 100644 --- a/crates/teepot/src/client/mod.rs +++ b/crates/teepot/src/client/mod.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs. @@ -8,29 +8,36 @@ pub mod vault; -pub use crate::quote::verify_quote_with_collateral; -pub use crate::quote::QuoteVerificationResult; -use crate::quote::Report; -use crate::server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}; -use crate::sgx::Quote; -pub use crate::sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}; +use crate::{ + quote::Report, + server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}, + sgx::Quote, +}; +pub use crate::{ + quote::{verify_quote_with_collateral, QuoteVerificationResult}, + sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}, +}; use actix_web::http::header; use anyhow::Result; use awc::{Client, Connector}; use clap::Args; use const_oid::AssociatedOid; use intel_tee_quote_verification_rs::Collateral; -use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; -use rustls::client::WebPkiServerVerifier; -use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; -use rustls::{ClientConfig, DigitallySignedStruct, Error, SignatureScheme}; +use rustls::{ + client::{ + danger::{HandshakeSignatureValid, ServerCertVerifier}, + WebPkiServerVerifier, + }, + pki_types::{CertificateDer, ServerName, UnixTime}, + ClientConfig, DigitallySignedStruct, Error, SignatureScheme, +}; use sha2::{Digest, Sha256}; -use std::sync::Arc; -use std::time; -use std::time::Duration; +use std::{sync::Arc, time, time::Duration}; use tracing::{debug, error, info, trace, warn}; -use x509_cert::der::{Decode as _, Encode as _}; -use x509_cert::Certificate; +use x509_cert::{ + der::{Decode as _, Encode as _}, + Certificate, +}; /// Options and arguments needed to attest a TEE #[derive(Args, Debug, Clone)] @@ -63,6 +70,8 @@ impl TeeConnection { /// This will verify the attestation report and check that the enclave /// is running the expected code. pub fn new(args: &AttestationArgs) -> Self { + let _ = rustls::crypto::ring::default_provider().install_default(); + let tls_config = Arc::new( ClientConfig::builder() .dangerous() @@ -260,6 +269,8 @@ impl TeeConnection { } } + info!("Quote verified! Connection secure!"); + Ok(rustls::client::danger::ServerCertVerified::assertion()) } From c26b3db29006ad3e0239f8604618019aacf437d0 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 28 Feb 2025 16:50:22 +0100 Subject: [PATCH 057/114] fix(verify-era-proof-attestation): handle missing RecoveryId signatures - Add fallback for missing RecoveryId in 64-byte signatures. - Improve error context for invalid signature length. - Add debug and trace logs for better diagnosis during verification. Signed-off-by: Harald Hoyer --- .../src/verification.rs | 55 +++++++++++++++---- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/verification.rs b/bin/verify-era-proof-attestation/src/verification.rs index 3c46fe6..6b439f0 100644 --- a/bin/verify-era-proof-attestation/src/verification.rs +++ b/bin/verify-era-proof-attestation/src/verification.rs @@ -1,20 +1,23 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs use crate::{args::AttestationPolicyArgs, client::JsonRpcClient}; use anyhow::{anyhow, Context, Result}; use hex::encode; -use secp256k1::{ecdsa::Signature, Message}; +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId, Signature}, + Message, SECP256K1, +}; use teepot::{ client::TcbLevel, - ethereum::recover_signer, + ethereum::{public_key_to_ethereum_address, recover_signer}, prover::reportdata::ReportData, quote::{ error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult, Report, }, }; -use tracing::{debug, info, warn}; +use tracing::{debug, info, trace, warn}; use zksync_basic_types::{L1BatchNumber, H256}; struct TeeProof { @@ -35,18 +38,51 @@ impl TeeProof { pub fn verify(&self) -> Result { match &self.report { ReportData::V0(report) => { + debug!("ReportData::V0"); let signature = Signature::from_compact(&self.signature)?; let root_hash_msg = Message::from_digest_slice(&self.root_hash.0)?; Ok(signature.verify(&root_hash_msg, &report.pubkey).is_ok()) } ReportData::V1(report) => { + debug!("ReportData::V1"); let ethereum_address_from_report = report.ethereum_address; let root_hash_msg = Message::from_digest_slice(self.root_hash.as_bytes())?; - let signature_bytes: [u8; 65] = self - .signature - .clone() + + trace!("sig len = {}", self.signature.len()); + + let sig_vec = self.signature.clone(); + + if self.signature.len() == 64 { + info!("Signature is missing RecoveryId!"); + // Fallback for missing RecoveryId + for rec_id in [RecoveryId::Zero, RecoveryId::One] { + let Ok(sig) = RecoverableSignature::from_compact(&sig_vec, rec_id) else { + continue; + }; + let Ok(public) = SECP256K1.recover_ecdsa(&root_hash_msg, &sig) else { + continue; + }; + let ethereum_address_from_signature = + public_key_to_ethereum_address(&public); + + debug!( + "Root hash: {}. Ethereum address from the attestation quote: {}. Ethereum address from the signature: {}.", + self.root_hash, + encode(ethereum_address_from_report), + encode(ethereum_address_from_signature), + ); + if ethereum_address_from_signature == ethereum_address_from_report { + info!("Had to use RecoveryId::{rec_id:?}"); + return Ok(true); + } + } + return Ok(false); + } + + let signature_bytes: [u8; 65] = sig_vec .try_into() - .map_err(|e| anyhow!("{:?}", e))?; + .map_err(|e| anyhow!("{:?}", e)) + .context("invalid length of signature bytes")?; let ethereum_address_from_signature = recover_signer(&signature_bytes, &root_hash_msg)?; debug!( @@ -77,8 +113,7 @@ pub async fn verify_batch_proof( let report_data_bytes = quote_verification_result.quote.get_report_data(); let report_data = ReportData::try_from(report_data_bytes)?; let tee_proof = TeeProof::new(report_data, root_hash, signature.to_vec()); - let verification_successful = tee_proof.verify().is_ok(); - Ok(verification_successful) + tee_proof.verify() } pub fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { From a6ea98a0967a4ccfceac259173ecc22bb1061dd4 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 28 Feb 2025 16:50:22 +0100 Subject: [PATCH 058/114] fix(verify-era-proof-attestation): handle missing RecoveryId signatures - add `RecoveryId::Two` and `RecoveryId::Three` Signed-off-by: Harald Hoyer --- bin/verify-era-proof-attestation/src/verification.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/verify-era-proof-attestation/src/verification.rs b/bin/verify-era-proof-attestation/src/verification.rs index 6b439f0..5603fb2 100644 --- a/bin/verify-era-proof-attestation/src/verification.rs +++ b/bin/verify-era-proof-attestation/src/verification.rs @@ -55,7 +55,12 @@ impl TeeProof { if self.signature.len() == 64 { info!("Signature is missing RecoveryId!"); // Fallback for missing RecoveryId - for rec_id in [RecoveryId::Zero, RecoveryId::One] { + for rec_id in [ + RecoveryId::Zero, + RecoveryId::One, + RecoveryId::Two, + RecoveryId::Three, + ] { let Ok(sig) = RecoverableSignature::from_compact(&sig_vec, rec_id) else { continue; }; From 98ed802b7506f54521866264ca64fccb02022bad Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 9 Apr 2024 09:17:31 +0200 Subject: [PATCH 059/114] docs(tee-self-attestation-test): add podman example Signed-off-by: Harald Hoyer --- bin/tee-self-attestation-test/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/tee-self-attestation-test/README.md b/bin/tee-self-attestation-test/README.md index 55d273a..233938f 100644 --- a/bin/tee-self-attestation-test/README.md +++ b/bin/tee-self-attestation-test/README.md @@ -68,3 +68,14 @@ mrsigner: c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d mrenclave: 7ffe70789261a51769f50e129bfafb2aafe91a4e17c3f0d52839006777c652f6 reportdata: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ``` + +## podman + +```bash +❯ podman run -i --rm --group-add=keep-groups -v /var/run/aesmd:/var/run/aesmd -v /dev/sgx_enclave:/dev/sgx_enclave \ + matterlabsrobot/teepot-self-attestation-test-sgx-dcap:latest \ + | base64 -d --ignore-garbage \ + | podman run -i --rm --net host \ + -v /etc/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf \ + matterlabsrobot/verify-attestation-sgx-dcap:latest +``` From 55ea2a606900fb029c41227c9c91421d1eb9a1fb Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 8 Mar 2024 14:27:50 +0100 Subject: [PATCH 060/114] fix(verify-attestation): bail out, if no quote provided Signed-off-by: Harald Hoyer --- bin/verify-attestation/src/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index fba3c16..74e9b7c 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Tool for SGX attestation and batch signature verification -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use clap::{Args, Parser, Subcommand}; use core::convert::TryInto; use hex::encode; @@ -113,6 +113,9 @@ fn verify_signature( } fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { + if attestation_quote_bytes.is_empty() { + bail!("Empty quote provided!"); + } println!( "Verifying quote ({} bytes)...", attestation_quote_bytes.len() From f8bd9e6a089c7592de76c1c493379157322ab4a9 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 18 Feb 2025 13:37:34 +0100 Subject: [PATCH 061/114] chore: split-out vault code from `teepot` in `teepot-vault` Signed-off-by: Harald Hoyer --- Cargo.lock | 51 +++++++---- Cargo.toml | 9 +- README.md | 46 +++++----- .../teepot/tests/data => assets}/gpgkey.asc | 0 .../teepot/tests/data => assets}/gpgkey.pub | 0 bin/tee-ratls-preexec/src/main.rs | 4 +- bin/tee-self-attestation-test/src/main.rs | 4 +- bin/verify-attestation/Cargo.toml | 3 - bin/verify-attestation/src/main.rs | 66 +------------- bin/verify-era-proof-attestation/Cargo.toml | 6 +- .../src/verification.rs | 2 +- crates/teepot-vault/Cargo.toml | 35 ++++++++ .../bin}/tee-stress-client/Cargo.toml | 1 + .../bin}/tee-stress-client/src/main.rs | 15 ++-- .../bin/tee-stress-client/src}/stress.json | 0 .../tee-stress-client/src}/stress.json.asc | 0 .../tee-stress-client.manifest.template | 0 .../bin}/tee-vault-admin/Cargo.toml | 1 + .../bin}/tee-vault-admin/src/command.rs | 10 +-- .../bin}/tee-vault-admin/src/digest.rs | 8 +- .../bin}/tee-vault-admin/src/main.rs | 12 +-- .../bin}/tee-vault-admin/src/sign.rs | 12 +-- .../bin}/tee-vault-unseal/Cargo.toml | 1 + .../tee-vault-unseal/src/admin-policy.hcl | 0 .../bin}/tee-vault-unseal/src/init.rs | 10 +-- .../bin}/tee-vault-unseal/src/main.rs | 36 +++----- .../bin}/tee-vault-unseal/src/unseal.rs | 12 +-- .../teepot-vault/bin}/teepot-read/Cargo.toml | 2 +- .../teepot-vault/bin}/teepot-read/src/main.rs | 6 +- .../teepot-vault/bin}/teepot-write/Cargo.toml | 2 +- .../bin}/teepot-write/src/main.rs | 8 +- .../teepot-vault/bin}/vault-admin/Cargo.toml | 1 + .../teepot-vault/bin}/vault-admin/README.md | 4 +- .../teepot-vault/bin}/vault-admin/src/main.rs | 8 +- .../teepot-vault/bin}/vault-unseal/Cargo.toml | 2 +- .../bin}/vault-unseal/src/main.rs | 14 +-- .../src/client/mod.rs | 17 ++-- .../src/client/vault.rs | 16 ++-- .../{teepot => teepot-vault}/src/json/http.rs | 16 +--- .../{teepot => teepot-vault}/src/json/mod.rs | 0 .../src/json/secrets.rs | 4 +- crates/teepot-vault/src/lib.rs | 24 +++++ crates/teepot-vault/src/server/attestation.rs | 56 ++++++++++++ .../src/server/mod.rs | 17 ++-- .../src/server/signatures.rs | 0 crates/teepot-vault/src/tdx/mod.rs | 32 +++++++ crates/teepot-vault/src/tdx/rtmr.rs | 90 +++++++++++++++++++ ...A312C59D679D930FA9E8B06D728F29A2DBABF8.asc | 0 ...A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 | 0 .../tests/data/test.json | 0 .../tests/data/test.json.asc | 0 .../tests/data/test2.json | 0 .../tests/data/test2.json.asc | 0 crates/teepot/Cargo.toml | 11 +-- crates/teepot/src/ethereum/mod.rs | 7 +- crates/teepot/src/lib.rs | 4 +- .../teepot/src/{server/pki.rs => pki/mod.rs} | 0 .../src/{server => quote}/attestation.rs | 56 +++--------- crates/teepot/src/quote/mod.rs | 4 +- examples/README.md | 10 +-- packages/teepotCrate/default.nix | 3 +- 61 files changed, 450 insertions(+), 308 deletions(-) rename {crates/teepot/tests/data => assets}/gpgkey.asc (100%) rename {crates/teepot/tests/data => assets}/gpgkey.pub (100%) create mode 100644 crates/teepot-vault/Cargo.toml rename {bin => crates/teepot-vault/bin}/tee-stress-client/Cargo.toml (93%) rename {bin => crates/teepot-vault/bin}/tee-stress-client/src/main.rs (91%) rename crates/{teepot/tests/data => teepot-vault/bin/tee-stress-client/src}/stress.json (100%) rename crates/{teepot/tests/data => teepot-vault/bin/tee-stress-client/src}/stress.json.asc (100%) rename {bin => crates/teepot-vault/bin}/tee-stress-client/tee-stress-client.manifest.template (100%) rename {bin => crates/teepot-vault/bin}/tee-vault-admin/Cargo.toml (94%) rename {bin => crates/teepot-vault/bin}/tee-vault-admin/src/command.rs (90%) rename {bin => crates/teepot-vault/bin}/tee-vault-admin/src/digest.rs (82%) rename {bin => crates/teepot-vault/bin}/tee-vault-admin/src/main.rs (93%) rename {bin => crates/teepot-vault/bin}/tee-vault-admin/src/sign.rs (93%) rename {bin => crates/teepot-vault/bin}/tee-vault-unseal/Cargo.toml (93%) rename {bin => crates/teepot-vault/bin}/tee-vault-unseal/src/admin-policy.hcl (100%) rename {bin => crates/teepot-vault/bin}/tee-vault-unseal/src/init.rs (94%) rename {bin => crates/teepot-vault/bin}/tee-vault-unseal/src/main.rs (93%) rename {bin => crates/teepot-vault/bin}/tee-vault-unseal/src/unseal.rs (97%) rename {bin => crates/teepot-vault/bin}/teepot-read/Cargo.toml (94%) rename {bin => crates/teepot-vault/bin}/teepot-read/src/main.rs (95%) rename {bin => crates/teepot-vault/bin}/teepot-write/Cargo.toml (94%) rename {bin => crates/teepot-vault/bin}/teepot-write/src/main.rs (94%) rename {bin => crates/teepot-vault/bin}/vault-admin/Cargo.toml (93%) rename {bin => crates/teepot-vault/bin}/vault-admin/README.md (95%) rename {bin => crates/teepot-vault/bin}/vault-admin/src/main.rs (99%) rename {bin => crates/teepot-vault/bin}/vault-unseal/Cargo.toml (93%) rename {bin => crates/teepot-vault/bin}/vault-unseal/src/main.rs (95%) rename crates/{teepot => teepot-vault}/src/client/mod.rs (98%) rename crates/{teepot => teepot-vault}/src/client/vault.rs (99%) rename crates/{teepot => teepot-vault}/src/json/http.rs (95%) rename crates/{teepot => teepot-vault}/src/json/mod.rs (100%) rename crates/{teepot => teepot-vault}/src/json/secrets.rs (92%) create mode 100644 crates/teepot-vault/src/lib.rs create mode 100644 crates/teepot-vault/src/server/attestation.rs rename crates/{teepot => teepot-vault}/src/server/mod.rs (94%) rename crates/{teepot => teepot-vault}/src/server/signatures.rs (100%) create mode 100644 crates/teepot-vault/src/tdx/mod.rs create mode 100644 crates/teepot-vault/src/tdx/rtmr.rs rename crates/{teepot => teepot-vault}/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc (100%) rename crates/{teepot => teepot-vault}/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 (100%) rename crates/{teepot => teepot-vault}/tests/data/test.json (100%) rename crates/{teepot => teepot-vault}/tests/data/test.json.asc (100%) rename crates/{teepot => teepot-vault}/tests/data/test2.json (100%) rename crates/{teepot => teepot-vault}/tests/data/test2.json.asc (100%) rename crates/teepot/src/{server/pki.rs => pki/mod.rs} (100%) rename crates/teepot/src/{server => quote}/attestation.rs (65%) diff --git a/Cargo.lock b/Cargo.lock index fdb34a6..fabed5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5559,6 +5559,7 @@ dependencies = [ "clap 4.5.30", "serde", "teepot", + "teepot-vault", "tracing", "tracing-log 0.2.0", "tracing-subscriber", @@ -5578,6 +5579,7 @@ dependencies = [ "serde_json", "sha2", "teepot", + "teepot-vault", "tracing", "tracing-actix-web", "tracing-log 0.2.0", @@ -5595,6 +5597,7 @@ dependencies = [ "rustls", "serde_json", "teepot", + "teepot-vault", "tracing", "tracing-log 0.2.0", "tracing-subscriber", @@ -5604,19 +5607,14 @@ dependencies = [ name = "teepot" version = "0.3.0" dependencies = [ - "actix-http", - "actix-web", "anyhow", "async-trait", - "awc", "base64 0.22.1", "bytemuck", - "bytes", "clap 4.5.30", "config", "const-oid", "enumset", - "futures-core", "getrandom 0.3.1", "hex", "num-integer", @@ -5627,7 +5625,6 @@ dependencies = [ "opentelemetry-semantic-conventions 0.28.0", "opentelemetry_sdk 0.28.0", "p256", - "pgp", "pkcs8 0.10.2", "reqwest 0.12.12", "rsa", @@ -5635,7 +5632,6 @@ dependencies = [ "secp256k1 0.30.0", "serde", "serde_json", - "serde_with 3.12.0", "sha2", "sha3", "signature 2.2.0", @@ -5649,10 +5645,8 @@ dependencies = [ "tracing-log 0.2.0", "tracing-subscriber", "tracing-test", - "webpki-roots", "x509-cert", "zeroize", - "zksync_basic_types", ] [[package]] @@ -5664,7 +5658,7 @@ dependencies = [ "awc", "clap 4.5.30", "serde_json", - "teepot", + "teepot-vault", "tracing", "tracing-log 0.2.0", "tracing-subscriber", @@ -5678,6 +5672,35 @@ dependencies = [ "serde", ] +[[package]] +name = "teepot-vault" +version = "0.3.0" +dependencies = [ + "actix-http", + "actix-web", + "anyhow", + "awc", + "base64 0.22.1", + "bytes", + "clap 4.5.30", + "const-oid", + "futures-core", + "hex", + "pgp", + "rustls", + "serde", + "serde_json", + "serde_with 3.12.0", + "sha2", + "tdx-attest-rs", + "teepot", + "teepot-tee-quote-verification-rs", + "thiserror 2.0.11", + "tracing", + "webpki-roots", + "x509-cert", +] + [[package]] name = "teepot-write" version = "0.3.0" @@ -5687,7 +5710,7 @@ dependencies = [ "awc", "clap 4.5.30", "serde_json", - "teepot", + "teepot-vault", "tracing", "tracing-log 0.2.0", "tracing-subscriber", @@ -6396,6 +6419,7 @@ dependencies = [ "pgp", "serde_json", "teepot", + "teepot-vault", "tracing", ] @@ -6408,7 +6432,7 @@ dependencies = [ "base64 0.22.1", "clap 4.5.30", "serde_json", - "teepot", + "teepot-vault", "tracing", "tracing-log 0.2.0", "tracing-subscriber", @@ -6432,10 +6456,7 @@ version = "0.3.0" dependencies = [ "anyhow", "clap 4.5.30", - "hex", - "secp256k1 0.30.0", "teepot", - "zksync_basic_types", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 33f2b2e..717d8b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["crates/*", "bin/*"] +members = ["crates/*", "bin/*", "crates/teepot-vault/bin/*"] resolver = "2" [profile.release] @@ -16,7 +16,6 @@ repository = "https://github.com/matter-labs/teepot" homepage = "https://github.com/matter-labs/teepot" [workspace.dependencies] -actix-http = "3" actix-web = { version = "4.5", features = ["rustls-0_23"] } anyhow = "1.0.82" async-trait = "0.1.86" @@ -28,7 +27,6 @@ clap = { version = "4.5", features = ["std", "derive", "env", "error-context", " config = { version = "0.15.8", default-features = false, features = ["yaml", "json", "toml", "async"] } const-oid = { version = "0.9", default-features = false } enumset = { version = "1.1", features = ["serde"] } -futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } getrandom = { version = "0.3.1", features = ["std"] } gpt = "4.0.0" hex = { version = "0.4.3", features = ["std"], default-features = false } @@ -58,6 +56,7 @@ sha3 = "0.10.8" signature = "2.2.0" tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } teepot = { path = "crates/teepot" } +teepot-vault = { path = "crates/teepot-vault" } testaso = "0.1.0" thiserror = "2.0.11" tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time", "signal"] } @@ -68,9 +67,5 @@ tracing-log = "0.2" tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "ansi"] } tracing-test = { version = "0.2.5", features = ["no-env-filter"] } url = "2.5.2" -webpki-roots = "0.26.1" x509-cert = { version = "0.2", features = ["builder", "signature"] } zeroize = { version = "1.7.0", features = ["serde"] } -zksync_basic_types = "=0.1.0" -zksync_types = "=0.1.0" -zksync_web3_decl = "=0.1.0" diff --git a/README.md b/README.md index 8c18eb5..6169c0d 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,37 @@ ## Parts of this project -- `teepot`: The main rust crate that abstracts TEEs and key-value stores. -- `tee-vault-unseal`: An enclave that uses the Vault API to unseal a vault as a proxy. -- `vault-unseal`: A client utility, that talks to `tee-vault-unseal` to unseal a vault. -- `tee-vault-admin`: An enclave that uses the Vault API to administer a vault as a proxy. -- `vault-admin`: A client utility, that talks to `tee-vault-admin` to administer a vault. -- `teepot-read` : A pre-exec utility that reads from the key-value store and passes the key-value pairs as environment - variables to the enclave. -- `teepot-write` : A pre-exec utility that reads key-values from the environment variables and writes them to the - key-value store. -- `verify-attestation`: A client utility that verifies the attestation of an enclave. -- `tee-key-preexec`: A pre-exec utility that generates a p256 secret key and passes it as an environment variable to the - enclave along with the attestation quote containing the hash of the public key. -- `tdx_google`: A base VM running on Google Cloud TDX. It receives a container URL via the instance metadata, - measures the sha384 of the URL to RTMR3 and launches the container. -- `tdx-extend`: A utility to extend an RTMR register with a hash value. -- `rtmr-calc`: A utility to calculate RTMR1 and RTMR2 from a GPT disk, the linux kernel, the linux initrd - and a UKI (unified kernel image). -- `sha384-extend`: A utility to calculate RTMR registers after extending them with a digest. +### teepot - lib -## Vault +- `teepot`: The main rust crate that abstracts TEEs. + - `verify-attestation`: A client utility that verifies the attestation of an enclave. + - `tee-key-preexec`: A pre-exec utility that generates a p256 secret key and passes it as an environment variable to + the + enclave along with the attestation quote containing the hash of the public key. + - `tdx_google`: A base VM running on Google Cloud TDX. It receives a container URL via the instance metadata, + measures the sha384 of the URL to RTMR3 and launches the container. + - `tdx-extend`: A utility to extend an RTMR register with a hash value. + - `rtmr-calc`: A utility to calculate RTMR1 and RTMR2 from a GPT disk, the linux kernel, the linux initrd + and a UKI (unified kernel image). + - `sha384-extend`: A utility to calculate RTMR registers after extending them with a digest. + +### Vault Part of this project is a key-value store that runs in a Trusted Execution Environment (TEE) and uses Remote Attestation for Authentication. The key-value store is implemented using Hashicorp Vault running in an Intel SGX enclave via the Gramine runtime. +- `teepot-vault`: A crate lib with for the TEE key-value store components: + - `tee-vault-unseal`: An enclave that uses the Vault API to unseal a vault as a proxy. + - `vault-unseal`: A client utility, that talks to `tee-vault-unseal` to unseal a vault. + - `tee-vault-admin`: An enclave that uses the Vault API to administer a vault as a proxy. + - `vault-admin`: A client utility, that talks to `tee-vault-admin` to administer a vault. + - `teepot-read` : A pre-exec utility that reads from the key-value store and passes the key-value pairs as + environment + variables to the enclave. + - `teepot-write` : A pre-exec utility that reads key-values from the environment variables and writes them to the + key-value store. + ## Development ### Prerequisites @@ -77,7 +83,7 @@ $ nix run .#fmt ### Build as the CI would ```shell -$ nix run github:nixos/nixpkgs/nixos-23.11#nixci +$ nix run github:nixos/nixpkgs/nixos-24.11#nixci -- build ``` ### Build and test individual container diff --git a/crates/teepot/tests/data/gpgkey.asc b/assets/gpgkey.asc similarity index 100% rename from crates/teepot/tests/data/gpgkey.asc rename to assets/gpgkey.asc diff --git a/crates/teepot/tests/data/gpgkey.pub b/assets/gpgkey.pub similarity index 100% rename from crates/teepot/tests/data/gpgkey.pub rename to assets/gpgkey.pub diff --git a/bin/tee-ratls-preexec/src/main.rs b/bin/tee-ratls-preexec/src/main.rs index 1fdd12d..e6dfb1c 100644 --- a/bin/tee-ratls-preexec/src/main.rs +++ b/bin/tee-ratls-preexec/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs //! Pre-exec for binary running in a TEE needing attestation of a secret signing key @@ -17,7 +17,7 @@ use std::io::Write; use std::os::unix::process::CommandExt; use std::path::PathBuf; use std::process::Command; -use teepot::server::pki::make_signed_cert; +use teepot::pki::make_signed_cert; use tracing::error; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; diff --git a/bin/tee-self-attestation-test/src/main.rs b/bin/tee-self-attestation-test/src/main.rs index a08353c..ee90314 100644 --- a/bin/tee-self-attestation-test/src/main.rs +++ b/bin/tee-self-attestation-test/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Simple TEE self-attestation test @@ -8,7 +8,7 @@ use anyhow::{Context, Result}; use base64::{engine::general_purpose, Engine as _}; -use teepot::server::attestation::get_quote_and_collateral; +use teepot::quote::attestation::get_quote_and_collateral; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; diff --git a/bin/verify-attestation/Cargo.toml b/bin/verify-attestation/Cargo.toml index ff473d9..8a4e129 100644 --- a/bin/verify-attestation/Cargo.toml +++ b/bin/verify-attestation/Cargo.toml @@ -10,7 +10,4 @@ repository.workspace = true [dependencies] anyhow.workspace = true clap.workspace = true -hex.workspace = true -secp256k1.workspace = true teepot.workspace = true -zksync_basic_types.workspace = true diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index 74e9b7c..c7ae611 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -3,19 +3,14 @@ //! Tool for SGX attestation and batch signature verification -use anyhow::{anyhow, bail, Context, Result}; -use clap::{Args, Parser, Subcommand}; -use core::convert::TryInto; -use hex::encode; -use secp256k1::Message; +use anyhow::{bail, Context, Result}; +use clap::Parser; + use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; use teepot::{ - client::TcbLevel, - ethereum::recover_signer, - prover::reportdata::ReportData, quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, + sgx::TcbLevel, }; -use zksync_basic_types::H256; #[derive(Parser, Debug)] #[command(author = "Matter Labs", version, about = "SGX attestation and batch signature verifier", long_about = None)] @@ -23,9 +18,6 @@ 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, } #[derive(Debug, Clone)] @@ -45,22 +37,6 @@ impl FromStr for ArgSource { } } -#[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: H256, -} - -#[derive(Subcommand, Debug)] -enum SubCommands { - /// Verify a batch signature signed within a TEE enclave. - SignVerify(SignatureArgs), -} - fn main() -> Result<()> { let args = Arguments::parse(); let attestation_quote_bytes = match args.attestation { @@ -75,40 +51,6 @@ fn main() -> Result<()> { }; 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 report_data = ReportData::try_from(quote_verification_result.quote.get_report_data())?; - let ethereum_address_from_quote = match report_data { - ReportData::V1(report_data_v1) => report_data_v1.ethereum_address, - _ => return Err(anyhow!("Unsupported report data version")), - }; - let signature_bytes: &[u8] = &fs::read(&signature_args.signature_file)?; - let root_hash = Message::from_digest_slice(signature_args.root_hash.as_bytes())?; - let ethereum_address_from_signature = recover_signer(&signature_bytes.try_into()?, &root_hash)?; - let verification_successful = ethereum_address_from_signature == ethereum_address_from_quote; - - println!( - "Signature '{}' {}. Ethereum address from attestation quote: {}. Ethereum address from signature: {}.", - encode(signature_bytes), - if verification_successful { - "verified successfully" - } else { - "verification failed" - }, - encode(ethereum_address_from_quote), - encode(ethereum_address_from_signature) - ); Ok(()) } diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index 70e6379..a818dbd 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -21,6 +21,6 @@ tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true url.workspace = true -zksync_basic_types.workspace = true -zksync_types.workspace = true -zksync_web3_decl.workspace = true +zksync_basic_types = "=0.1.0" +zksync_types = "=0.1.0" +zksync_web3_decl = "=0.1.0" diff --git a/bin/verify-era-proof-attestation/src/verification.rs b/bin/verify-era-proof-attestation/src/verification.rs index 5603fb2..4ae892e 100644 --- a/bin/verify-era-proof-attestation/src/verification.rs +++ b/bin/verify-era-proof-attestation/src/verification.rs @@ -9,13 +9,13 @@ use secp256k1::{ Message, SECP256K1, }; use teepot::{ - client::TcbLevel, ethereum::{public_key_to_ethereum_address, recover_signer}, prover::reportdata::ReportData, quote::{ error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult, Report, }, + sgx::TcbLevel, }; use tracing::{debug, info, trace, warn}; use zksync_basic_types::{L1BatchNumber, H256}; diff --git a/crates/teepot-vault/Cargo.toml b/crates/teepot-vault/Cargo.toml new file mode 100644 index 0000000..4564c7d --- /dev/null +++ b/crates/teepot-vault/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "teepot-vault" +description = "TEE secret manager" +license.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +repository.workspace = true + +[dependencies] +actix-http = "3" +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +bytes.workspace = true +clap.workspace = true +const-oid.workspace = true +futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } +hex.workspace = true +intel-tee-quote-verification-rs.workspace = true +pgp.workspace = true +rustls.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +sha2.workspace = true +tdx-attest-rs.workspace = true +teepot.workspace = true +thiserror.workspace = true +tracing.workspace = true +webpki-roots = "0.26.1" +x509-cert.workspace = true + +[dev-dependencies] +base64.workspace = true diff --git a/bin/tee-stress-client/Cargo.toml b/crates/teepot-vault/bin/tee-stress-client/Cargo.toml similarity index 93% rename from bin/tee-stress-client/Cargo.toml rename to crates/teepot-vault/bin/tee-stress-client/Cargo.toml index 1ce3cae..e55b189 100644 --- a/bin/tee-stress-client/Cargo.toml +++ b/crates/teepot-vault/bin/tee-stress-client/Cargo.toml @@ -13,6 +13,7 @@ anyhow.workspace = true clap.workspace = true serde.workspace = true teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true diff --git a/bin/tee-stress-client/src/main.rs b/crates/teepot-vault/bin/tee-stress-client/src/main.rs similarity index 91% rename from bin/tee-stress-client/src/main.rs rename to crates/teepot-vault/bin/tee-stress-client/src/main.rs index f691401..87dddae 100644 --- a/bin/tee-stress-client/src/main.rs +++ b/crates/teepot-vault/bin/tee-stress-client/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs //! Server to handle requests to the Vault TEE @@ -11,14 +11,17 @@ use anyhow::{Context, Result}; use clap::Parser; use serde::{Deserialize, Serialize}; use std::time::Duration; -use teepot::client::vault::VaultConnection; -use teepot::server::attestation::{get_quote_and_collateral, VaultAttestationArgs}; -use teepot::server::pki::make_self_signed_cert; use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot_vault::{ + client::vault::VaultConnection, + server::{ + attestation::{get_quote_and_collateral, VaultAttestationArgs}, + pki::make_self_signed_cert, + }, +}; use tracing::{error, trace}; use tracing_log::LogTracer; -use tracing_subscriber::Registry; -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] diff --git a/crates/teepot/tests/data/stress.json b/crates/teepot-vault/bin/tee-stress-client/src/stress.json similarity index 100% rename from crates/teepot/tests/data/stress.json rename to crates/teepot-vault/bin/tee-stress-client/src/stress.json diff --git a/crates/teepot/tests/data/stress.json.asc b/crates/teepot-vault/bin/tee-stress-client/src/stress.json.asc similarity index 100% rename from crates/teepot/tests/data/stress.json.asc rename to crates/teepot-vault/bin/tee-stress-client/src/stress.json.asc diff --git a/bin/tee-stress-client/tee-stress-client.manifest.template b/crates/teepot-vault/bin/tee-stress-client/tee-stress-client.manifest.template similarity index 100% rename from bin/tee-stress-client/tee-stress-client.manifest.template rename to crates/teepot-vault/bin/tee-stress-client/tee-stress-client.manifest.template diff --git a/bin/tee-vault-admin/Cargo.toml b/crates/teepot-vault/bin/tee-vault-admin/Cargo.toml similarity index 94% rename from bin/tee-vault-admin/Cargo.toml rename to crates/teepot-vault/bin/tee-vault-admin/Cargo.toml index 7fa206c..7ff77a9 100644 --- a/bin/tee-vault-admin/Cargo.toml +++ b/crates/teepot-vault/bin/tee-vault-admin/Cargo.toml @@ -18,6 +18,7 @@ rustls.workspace = true serde_json.workspace = true sha2.workspace = true teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true tracing-actix-web.workspace = true tracing-log.workspace = true diff --git a/bin/tee-vault-admin/src/command.rs b/crates/teepot-vault/bin/tee-vault-admin/src/command.rs similarity index 90% rename from bin/tee-vault-admin/src/command.rs rename to crates/teepot-vault/bin/tee-vault-admin/src/command.rs index 607bca3..ea08299 100644 --- a/bin/tee-vault-admin/src/command.rs +++ b/crates/teepot-vault/bin/tee-vault-admin/src/command.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! post commands @@ -9,12 +9,12 @@ use anyhow::{anyhow, Context, Result}; use awc::http::StatusCode; use sha2::{Digest, Sha256}; use std::sync::Arc; -use teepot::client::vault::VaultConnection; -use teepot::json::http::{ +use teepot_vault::client::vault::VaultConnection; +use teepot_vault::json::http::{ VaultCommandRequest, VaultCommandResponse, VaultCommands, VaultCommandsResponse, }; -use teepot::json::secrets::{AdminConfig, AdminState}; -use teepot::server::{signatures::VerifySig, HttpResponseError, Status}; +use teepot_vault::json::secrets::{AdminConfig, AdminState}; +use teepot_vault::server::{signatures::VerifySig, HttpResponseError, Status}; use tracing::instrument; /// Post command diff --git a/bin/tee-vault-admin/src/digest.rs b/crates/teepot-vault/bin/tee-vault-admin/src/digest.rs similarity index 82% rename from bin/tee-vault-admin/src/digest.rs rename to crates/teepot-vault/bin/tee-vault-admin/src/digest.rs index bd87b02..70ec016 100644 --- a/bin/tee-vault-admin/src/digest.rs +++ b/crates/teepot-vault/bin/tee-vault-admin/src/digest.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! digest @@ -9,9 +9,9 @@ use anyhow::{Context, Result}; use awc::http::StatusCode; use serde_json::json; use std::sync::Arc; -use teepot::client::vault::VaultConnection; -use teepot::json::secrets::AdminState; -use teepot::server::{HttpResponseError, Status}; +use teepot_vault::client::vault::VaultConnection; +use teepot_vault::json::secrets::AdminState; +use teepot_vault::server::{HttpResponseError, Status}; use tracing::instrument; /// Get last digest diff --git a/bin/tee-vault-admin/src/main.rs b/crates/teepot-vault/bin/tee-vault-admin/src/main.rs similarity index 93% rename from bin/tee-vault-admin/src/main.rs rename to crates/teepot-vault/bin/tee-vault-admin/src/main.rs index d8574a9..782a3c2 100644 --- a/bin/tee-vault-admin/src/main.rs +++ b/crates/teepot-vault/bin/tee-vault-admin/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2025 Matter Labs +// Copyright (c) 2023-2024 Matter Labs //! Server to handle requests to the Vault TEE @@ -17,14 +17,14 @@ use digest::get_digest; use rustls::ServerConfig; use sign::post_sign; use std::{net::Ipv6Addr, sync::Arc}; -use teepot::{ +use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot_vault::{ json::http::{SignRequest, VaultCommandRequest, DIGEST_URL}, server::{ attestation::{get_quote_and_collateral, VaultAttestationArgs}, new_json_cfg, pki::make_self_signed_cert, }, - sgx::{parse_tcb_levels, EnumSet, TcbLevel}, }; use tracing::{error, info}; use tracing_actix_web::TracingLogger; @@ -81,6 +81,8 @@ async fn main() -> Result<()> { info!("Starting HTTPS server at port {}", args.port); + info!("Quote verified! Connection secure!"); + let server_state = Arc::new(ServerState { report_data, vault_attestation: args.attestation, @@ -116,9 +118,9 @@ async fn main() -> Result<()> { #[cfg(test)] mod tests { use serde_json::json; - use teepot::json::http::{VaultCommand, VaultCommands}; + use teepot_vault::json::http::{VaultCommand, VaultCommands}; - const TEST_DATA: &str = include_str!("../../../crates/teepot/tests/data/test.json"); + const TEST_DATA: &str = include_str!("../../../tests/data/test.json"); #[test] fn test_vault_commands() { diff --git a/bin/tee-vault-admin/src/sign.rs b/crates/teepot-vault/bin/tee-vault-admin/src/sign.rs similarity index 93% rename from bin/tee-vault-admin/src/sign.rs rename to crates/teepot-vault/bin/tee-vault-admin/src/sign.rs index 973df93..d5b1718 100644 --- a/bin/tee-vault-admin/src/sign.rs +++ b/crates/teepot-vault/bin/tee-vault-admin/src/sign.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! post signing request @@ -9,14 +9,14 @@ use actix_web::web; use anyhow::{anyhow, Context, Result}; use sha2::{Digest, Sha256}; use std::sync::Arc; -use teepot::client::vault::VaultConnection; -use teepot::json::http::{SignRequest, SignRequestData, SignResponse}; -use teepot::json::secrets::{AdminConfig, AdminState, SGXSigningKey}; -use teepot::server::signatures::VerifySig as _; -use teepot::server::{HttpResponseError, Status}; use teepot::sgx::sign::PrivateKey as _; use teepot::sgx::sign::{Author, Signature}; use teepot::sgx::sign::{Body, RS256PrivateKey}; +use teepot_vault::client::vault::VaultConnection; +use teepot_vault::json::http::{SignRequest, SignRequestData, SignResponse}; +use teepot_vault::json::secrets::{AdminConfig, AdminState, SGXSigningKey}; +use teepot_vault::server::signatures::VerifySig as _; +use teepot_vault::server::{HttpResponseError, Status}; use tracing::instrument; /// Sign command diff --git a/bin/tee-vault-unseal/Cargo.toml b/crates/teepot-vault/bin/tee-vault-unseal/Cargo.toml similarity index 93% rename from bin/tee-vault-unseal/Cargo.toml rename to crates/teepot-vault/bin/tee-vault-unseal/Cargo.toml index b803346..d1ab395 100644 --- a/bin/tee-vault-unseal/Cargo.toml +++ b/crates/teepot-vault/bin/tee-vault-unseal/Cargo.toml @@ -15,6 +15,7 @@ clap.workspace = true rustls.workspace = true serde_json.workspace = true teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true diff --git a/bin/tee-vault-unseal/src/admin-policy.hcl b/crates/teepot-vault/bin/tee-vault-unseal/src/admin-policy.hcl similarity index 100% rename from bin/tee-vault-unseal/src/admin-policy.hcl rename to crates/teepot-vault/bin/tee-vault-unseal/src/admin-policy.hcl diff --git a/bin/tee-vault-unseal/src/init.rs b/crates/teepot-vault/bin/tee-vault-unseal/src/init.rs similarity index 94% rename from bin/tee-vault-unseal/src/init.rs rename to crates/teepot-vault/bin/tee-vault-unseal/src/init.rs index 302c5fa..063a696 100644 --- a/bin/tee-vault-unseal/src/init.rs +++ b/crates/teepot-vault/bin/tee-vault-unseal/src/init.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs use crate::{get_vault_status, UnsealServerState, Worker}; use actix_web::error::ErrorBadRequest; @@ -7,10 +7,10 @@ use actix_web::{web, HttpResponse}; use anyhow::{anyhow, Context, Result}; use awc::http::StatusCode; use serde_json::json; -use teepot::client::TeeConnection; -use teepot::json::http::{Init, InitResponse, VaultInitRequest}; -use teepot::json::secrets::AdminConfig; -use teepot::server::{HttpResponseError, Status}; +use teepot_vault::client::TeeConnection; +use teepot_vault::json::http::{Init, InitResponse, VaultInitRequest}; +use teepot_vault::json::secrets::AdminConfig; +use teepot_vault::server::{HttpResponseError, Status}; use tracing::{debug, error, info, instrument, trace}; #[instrument(level = "info", name = "/v1/sys/init", skip_all)] diff --git a/bin/tee-vault-unseal/src/main.rs b/crates/teepot-vault/bin/tee-vault-unseal/src/main.rs similarity index 93% rename from bin/tee-vault-unseal/src/main.rs rename to crates/teepot-vault/bin/tee-vault-unseal/src/main.rs index 65ffb4f..eac2869 100644 --- a/bin/tee-vault-unseal/src/main.rs +++ b/crates/teepot-vault/bin/tee-vault-unseal/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2025 Matter Labs +// Copyright (c) 2023-2024 Matter Labs //! Server to initialize and unseal the Vault TEE. @@ -15,27 +15,19 @@ use awc::Client; use clap::Parser; use init::post_init; use rustls::ServerConfig; -use std::{ - fmt::Debug, - io::Read, - net::Ipv6Addr, - path::PathBuf, - sync::{Arc, RwLock}, - time::Duration, -}; -use teepot::{ - client::{AttestationArgs, TeeConnection}, - json::{ - http::{Init, Unseal}, - secrets::AdminConfig, - }, - server::{ - attestation::{get_quote_and_collateral, VaultAttestationArgs}, - new_json_cfg, - pki::make_self_signed_cert, - }, - sgx::{parse_tcb_levels, EnumSet, TcbLevel}, -}; +use std::fmt::Debug; +use std::io::Read; +use std::net::Ipv6Addr; +use std::path::PathBuf; +use std::sync::{Arc, RwLock}; +use std::time::Duration; +use teepot::pki::make_self_signed_cert; +use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot_vault::client::{AttestationArgs, TeeConnection}; +use teepot_vault::json::http::{Init, Unseal}; +use teepot_vault::json::secrets::AdminConfig; +use teepot_vault::server::attestation::{get_quote_and_collateral, VaultAttestationArgs}; +use teepot_vault::server::new_json_cfg; use tracing::{error, info}; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; diff --git a/bin/tee-vault-unseal/src/unseal.rs b/crates/teepot-vault/bin/tee-vault-unseal/src/unseal.rs similarity index 97% rename from bin/tee-vault-unseal/src/unseal.rs rename to crates/teepot-vault/bin/tee-vault-unseal/src/unseal.rs index 7d2c011..c72bb50 100644 --- a/bin/tee-vault-unseal/src/unseal.rs +++ b/crates/teepot-vault/bin/tee-vault-unseal/src/unseal.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs use crate::{get_vault_status, UnsealServerConfig, UnsealServerState, Worker, VAULT_TOKEN_HEADER}; use actix_web::http::StatusCode; @@ -12,11 +12,11 @@ use std::fs::File; use std::future::Future; use std::io::Read; use std::time::Duration; -use teepot::client::vault::VaultConnection; -use teepot::client::TeeConnection; -use teepot::json::http::Unseal; -use teepot::json::secrets::{AdminConfig, AdminState}; -use teepot::server::{HttpResponseError, Status}; +use teepot_vault::client::vault::VaultConnection; +use teepot_vault::client::TeeConnection; +use teepot_vault::json::http::Unseal; +use teepot_vault::json::secrets::{AdminConfig, AdminState}; +use teepot_vault::server::{HttpResponseError, Status}; use tracing::{debug, error, info, instrument, trace}; #[instrument(level = "info", name = "/v1/sys/unseal", skip_all)] diff --git a/bin/teepot-read/Cargo.toml b/crates/teepot-vault/bin/teepot-read/Cargo.toml similarity index 94% rename from bin/teepot-read/Cargo.toml rename to crates/teepot-vault/bin/teepot-read/Cargo.toml index 5c3c8e2..1e3a8c1 100644 --- a/bin/teepot-read/Cargo.toml +++ b/crates/teepot-vault/bin/teepot-read/Cargo.toml @@ -15,7 +15,7 @@ anyhow.workspace = true awc.workspace = true clap.workspace = true serde_json.workspace = true -teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true diff --git a/bin/teepot-read/src/main.rs b/crates/teepot-vault/bin/teepot-read/src/main.rs similarity index 95% rename from bin/teepot-read/src/main.rs rename to crates/teepot-vault/bin/teepot-read/src/main.rs index 1b1afe2..e98b014 100644 --- a/bin/teepot-read/src/main.rs +++ b/crates/teepot-vault/bin/teepot-read/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Get the secrets from a Vault TEE and pass them as environment variables to a command @@ -12,8 +12,8 @@ use serde_json::Value; use std::collections::HashMap; use std::os::unix::process::CommandExt; use std::process::Command; -use teepot::client::vault::VaultConnection; -use teepot::server::attestation::VaultAttestationArgs; +use teepot_vault::client::vault::VaultConnection; +use teepot_vault::server::attestation::VaultAttestationArgs; use tracing::{debug, info, warn}; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; diff --git a/bin/teepot-write/Cargo.toml b/crates/teepot-vault/bin/teepot-write/Cargo.toml similarity index 94% rename from bin/teepot-write/Cargo.toml rename to crates/teepot-vault/bin/teepot-write/Cargo.toml index a2f6c64..8933de0 100644 --- a/bin/teepot-write/Cargo.toml +++ b/crates/teepot-vault/bin/teepot-write/Cargo.toml @@ -15,7 +15,7 @@ anyhow.workspace = true awc.workspace = true clap.workspace = true serde_json.workspace = true -teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true diff --git a/bin/teepot-write/src/main.rs b/crates/teepot-vault/bin/teepot-write/src/main.rs similarity index 94% rename from bin/teepot-write/src/main.rs rename to crates/teepot-vault/bin/teepot-write/src/main.rs index 04fea08..b7f0c94 100644 --- a/bin/teepot-write/src/main.rs +++ b/crates/teepot-vault/bin/teepot-write/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Write secrets to a Vault TEE from environment variables @@ -9,10 +9,8 @@ use anyhow::{Context, Result}; use clap::Parser; use serde_json::Value; -use std::collections::HashMap; -use std::env; -use teepot::client::vault::VaultConnection; -use teepot::server::attestation::VaultAttestationArgs; +use std::{collections::HashMap, env}; +use teepot_vault::{client::vault::VaultConnection, server::attestation::VaultAttestationArgs}; use tracing::{debug, info, warn}; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; diff --git a/bin/vault-admin/Cargo.toml b/crates/teepot-vault/bin/vault-admin/Cargo.toml similarity index 93% rename from bin/vault-admin/Cargo.toml rename to crates/teepot-vault/bin/vault-admin/Cargo.toml index b9c7e12..270c6fb 100644 --- a/bin/vault-admin/Cargo.toml +++ b/crates/teepot-vault/bin/vault-admin/Cargo.toml @@ -16,4 +16,5 @@ hex.workspace = true pgp.workspace = true serde_json.workspace = true teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true diff --git a/bin/vault-admin/README.md b/crates/teepot-vault/bin/vault-admin/README.md similarity index 95% rename from bin/vault-admin/README.md rename to crates/teepot-vault/bin/vault-admin/README.md index fb9151f..90c0935 100644 --- a/bin/vault-admin/README.md +++ b/crates/teepot-vault/bin/vault-admin/README.md @@ -13,8 +13,8 @@ Verified signature for `81A312C59D679D930FA9E8B06D728F29A2DBABF8` --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ --sgx-allowed-tcb-levels SwHardeningNeeded \ --server https://127.0.0.1:8444 \ - bin/tee-vault-admin/tests/data/test.json \ - bin/tee-vault-admin/tests/data/test.json.asc + crates/teepot-vault/tests/data/test.json \ + crates/teepot-vault/tests/data/test.json.asc 2023-08-04T10:51:14.919941Z INFO vault_admin: Quote verified! Connection secure! 2023-08-04T10:51:14.920430Z INFO tee_client: Getting attestation report diff --git a/bin/vault-admin/src/main.rs b/crates/teepot-vault/bin/vault-admin/src/main.rs similarity index 99% rename from bin/vault-admin/src/main.rs rename to crates/teepot-vault/bin/vault-admin/src/main.rs index 1739313..7e29c21 100644 --- a/bin/vault-admin/src/main.rs +++ b/crates/teepot-vault/bin/vault-admin/src/main.rs @@ -12,16 +12,18 @@ use std::{ path::{Path, PathBuf}, }; use teepot::{ + log::{setup_logging, LogLevelParser}, + sgx::sign::Signature, +}; +use teepot_vault::{ client::{AttestationArgs, TeeConnection}, json::http::{ SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands, VaultCommandsResponse, DIGEST_URL, }, - log::{setup_logging, LogLevelParser}, server::signatures::verify_sig, - sgx::sign::Signature, }; -use tracing::{error, info, level_filters::LevelFilter}; +use tracing::{error, level_filters::LevelFilter}; #[derive(Args, Debug)] struct SendArgs { diff --git a/bin/vault-unseal/Cargo.toml b/crates/teepot-vault/bin/vault-unseal/Cargo.toml similarity index 93% rename from bin/vault-unseal/Cargo.toml rename to crates/teepot-vault/bin/vault-unseal/Cargo.toml index b191a04..ecba7f5 100644 --- a/bin/vault-unseal/Cargo.toml +++ b/crates/teepot-vault/bin/vault-unseal/Cargo.toml @@ -13,7 +13,7 @@ anyhow.workspace = true base64.workspace = true clap.workspace = true serde_json.workspace = true -teepot.workspace = true +teepot-vault.workspace = true tracing.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true diff --git a/bin/vault-unseal/src/main.rs b/crates/teepot-vault/bin/vault-unseal/src/main.rs similarity index 95% rename from bin/vault-unseal/src/main.rs rename to crates/teepot-vault/bin/vault-unseal/src/main.rs index 29e2bc7..c46b1e3 100644 --- a/bin/vault-unseal/src/main.rs +++ b/crates/teepot-vault/bin/vault-unseal/src/main.rs @@ -1,18 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs use anyhow::{anyhow, bail, Context, Result}; use base64::{engine::general_purpose, Engine as _}; use clap::{Args, Parser, Subcommand}; use serde_json::Value; -use std::fs::File; -use std::io::Read; -use teepot::client::{AttestationArgs, TeeConnection}; -use teepot::json::http::{Init, InitResponse, Unseal}; +use std::{fs::File, io::Read}; +use teepot_vault::{ + client::{AttestationArgs, TeeConnection}, + json::http::{Init, InitResponse, Unseal}, +}; use tracing::{error, info, trace, warn}; use tracing_log::LogTracer; -use tracing_subscriber::Registry; -use tracing_subscriber::{fmt, prelude::*, EnvFilter}; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; #[derive(Args, Debug)] pub struct InitArgs { diff --git a/crates/teepot/src/client/mod.rs b/crates/teepot-vault/src/client/mod.rs similarity index 98% rename from crates/teepot/src/client/mod.rs rename to crates/teepot-vault/src/client/mod.rs index dc76066..bf8dfa2 100644 --- a/crates/teepot/src/client/mod.rs +++ b/crates/teepot-vault/src/client/mod.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2025 Matter Labs +// Copyright (c) 2023-2024 Matter Labs //! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs. @@ -8,15 +8,7 @@ pub mod vault; -use crate::{ - quote::Report, - server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}, - sgx::Quote, -}; -pub use crate::{ - quote::{verify_quote_with_collateral, QuoteVerificationResult}, - sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}, -}; +use crate::server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}; use actix_web::http::header; use anyhow::Result; use awc::{Client, Connector}; @@ -33,6 +25,11 @@ use rustls::{ }; use sha2::{Digest, Sha256}; use std::{sync::Arc, time, time::Duration}; +use teepot::{quote::Report, sgx::Quote}; +pub use teepot::{ + quote::{verify_quote_with_collateral, QuoteVerificationResult}, + sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}, +}; use tracing::{debug, error, info, trace, warn}; use x509_cert::{ der::{Decode as _, Encode as _}, diff --git a/crates/teepot/src/client/vault.rs b/crates/teepot-vault/src/client/vault.rs similarity index 99% rename from crates/teepot/src/client/vault.rs rename to crates/teepot-vault/src/client/vault.rs index 2f54cc4..f6dc225 100644 --- a/crates/teepot/src/client/vault.rs +++ b/crates/teepot-vault/src/client/vault.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs. @@ -9,15 +9,8 @@ use super::{AttestationArgs, TeeConnection}; use crate::{ json::http::{AuthRequest, AuthResponse}, - quote::error::QuoteContext, server::{pki::make_self_signed_cert, AnyHowResponseError, HttpResponseError, Status}, }; -pub use crate::{ - quote::{verify_quote_with_collateral, QuoteVerificationResult}, - sgx::{ - parse_tcb_levels, sgx_gramine_get_quote, sgx_ql_qv_result_t, Collateral, EnumSet, TcbLevel, - }, -}; use actix_http::error::PayloadError; use actix_web::{http::header, ResponseError}; use anyhow::{anyhow, bail, Context, Result}; @@ -35,6 +28,13 @@ use std::{ sync::Arc, time, }; +use teepot::quote::error::QuoteContext; +pub use teepot::{ + quote::{verify_quote_with_collateral, QuoteVerificationResult}, + sgx::{ + parse_tcb_levels, sgx_gramine_get_quote, sgx_ql_qv_result_t, Collateral, EnumSet, TcbLevel, + }, +}; use tracing::{debug, error, info, trace}; const VAULT_TOKEN_HEADER: &str = "X-Vault-Token"; diff --git a/crates/teepot/src/json/http.rs b/crates/teepot-vault/src/json/http.rs similarity index 95% rename from crates/teepot/src/json/http.rs rename to crates/teepot-vault/src/json/http.rs index d450906..4713797 100644 --- a/crates/teepot/src/json/http.rs +++ b/crates/teepot-vault/src/json/http.rs @@ -1,15 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Common types for the teepot http JSON API -use crate::sgx::Collateral; use serde::{Deserialize, Serialize}; use serde_json::Value; -use serde_with::base64::Base64; -use serde_with::serde_as; +use serde_with::{base64::Base64, serde_as}; use std::fmt::Display; -use std::sync::Arc; /// The unseal request data #[derive(Debug, Serialize, Deserialize)] @@ -23,15 +20,6 @@ impl Unseal { pub const URL: &'static str = "/v1/sys/unseal"; } -/// The attestation response -#[derive(Debug, Serialize, Deserialize)] -pub struct AttestationResponse { - /// The quote - pub quote: Arc<[u8]>, - /// The collateral - pub collateral: Arc, -} - /// The init request data #[serde_as] #[derive(Debug, Serialize, Deserialize)] diff --git a/crates/teepot/src/json/mod.rs b/crates/teepot-vault/src/json/mod.rs similarity index 100% rename from crates/teepot/src/json/mod.rs rename to crates/teepot-vault/src/json/mod.rs diff --git a/crates/teepot/src/json/secrets.rs b/crates/teepot-vault/src/json/secrets.rs similarity index 92% rename from crates/teepot/src/json/secrets.rs rename to crates/teepot-vault/src/json/secrets.rs index dd1fae5..7e60179 100644 --- a/crates/teepot/src/json/secrets.rs +++ b/crates/teepot-vault/src/json/secrets.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Common types for the teepot secrets JSON API -use crate::sgx::sign::Zeroizing; use serde::{Deserialize, Serialize}; use serde_with::base64::Base64; use serde_with::serde_as; +use teepot::sgx::sign::Zeroizing; /// Configuration for the admin tee #[serde_as] diff --git a/crates/teepot-vault/src/lib.rs b/crates/teepot-vault/src/lib.rs new file mode 100644 index 0000000..d74a0ff --- /dev/null +++ b/crates/teepot-vault/src/lib.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Helper functions to verify Intel SGX enclaves and other TEEs. + +#![deny(missing_docs)] +#![deny(clippy::all)] + +pub mod client; +pub mod json; +pub mod server; +pub mod tdx; + +/// pad a byte slice to a fixed sized array +pub fn pad(input: &[u8]) -> [u8; T] { + let mut output = [0; T]; + let len = input.len(); + if len > T { + output.copy_from_slice(&input[..T]); + } else { + output[..len].copy_from_slice(input); + } + output +} diff --git a/crates/teepot-vault/src/server/attestation.rs b/crates/teepot-vault/src/server/attestation.rs new file mode 100644 index 0000000..8688e03 --- /dev/null +++ b/crates/teepot-vault/src/server/attestation.rs @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Common attestation API for all TEEs + +use crate::client::AttestationArgs; +use clap::Args; +use serde::{Deserialize, Serialize}; + +pub use teepot::{ + quote::{ + attestation::get_quote_and_collateral, error::QuoteContext, get_quote, + verify_quote_with_collateral, QuoteVerificationResult, + }, + sgx::{parse_tcb_levels, Collateral, EnumSet, TcbLevel}, +}; + +/// Options and arguments needed to attest a TEE +#[derive(Args, Debug, Clone, Serialize, Deserialize, Default)] +pub struct VaultAttestationArgs { + /// hex encoded SGX mrsigner of the enclave to attest + #[arg(long, env = "VAULT_SGX_MRSIGNER")] + pub vault_sgx_mrsigner: Option, + /// hex encoded SGX mrenclave of the enclave to attest + #[arg(long, env = "VAULT_SGX_MRENCLAVE")] + pub vault_sgx_mrenclave: Option, + /// URL of the server + #[arg(long, required = true, env = "VAULT_ADDR")] + pub vault_addr: String, + /// allowed TCB levels, comma separated: + /// Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, OutOfDate, OutOfDateConfigNeeded + #[arg(long, value_parser = parse_tcb_levels, env = "VAULT_SGX_ALLOWED_TCB_LEVELS")] + pub vault_sgx_allowed_tcb_levels: Option>, +} + +impl From for AttestationArgs { + fn from(value: VaultAttestationArgs) -> Self { + AttestationArgs { + sgx_mrsigner: value.vault_sgx_mrsigner, + sgx_mrenclave: value.vault_sgx_mrenclave, + server: value.vault_addr, + sgx_allowed_tcb_levels: value.vault_sgx_allowed_tcb_levels, + } + } +} + +impl From<&VaultAttestationArgs> for AttestationArgs { + fn from(value: &VaultAttestationArgs) -> Self { + AttestationArgs { + sgx_mrsigner: value.vault_sgx_mrsigner.clone(), + sgx_mrenclave: value.vault_sgx_mrenclave.clone(), + server: value.vault_addr.clone(), + sgx_allowed_tcb_levels: value.vault_sgx_allowed_tcb_levels, + } + } +} diff --git a/crates/teepot/src/server/mod.rs b/crates/teepot-vault/src/server/mod.rs similarity index 94% rename from crates/teepot/src/server/mod.rs rename to crates/teepot-vault/src/server/mod.rs index 2657e04..bc6c233 100644 --- a/crates/teepot/src/server/mod.rs +++ b/crates/teepot-vault/src/server/mod.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! # tee-server @@ -7,18 +7,19 @@ #![deny(clippy::all)] pub mod attestation; -pub mod pki; pub mod signatures; -use actix_web::http::StatusCode; -use actix_web::web::Bytes; -use actix_web::{error, HttpRequest, HttpResponse}; -use actix_web::{HttpMessage, ResponseError}; +use actix_web::{ + error, http::StatusCode, web::Bytes, HttpMessage, HttpRequest, HttpResponse, ResponseError, +}; use anyhow::anyhow; -use awc::error::{PayloadError, SendRequestError}; -use awc::ClientResponse; +use awc::{ + error::{PayloadError, SendRequestError}, + ClientResponse, +}; use futures_core::Stream; use std::fmt::{Debug, Display, Formatter}; +pub use teepot::pki; use tracing::error; /// Anyhow error with an HTTP status code diff --git a/crates/teepot/src/server/signatures.rs b/crates/teepot-vault/src/server/signatures.rs similarity index 100% rename from crates/teepot/src/server/signatures.rs rename to crates/teepot-vault/src/server/signatures.rs diff --git a/crates/teepot-vault/src/tdx/mod.rs b/crates/teepot-vault/src/tdx/mod.rs new file mode 100644 index 0000000..df787ac --- /dev/null +++ b/crates/teepot-vault/src/tdx/mod.rs @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Intel TDX helper functions. + +pub mod rtmr; + +pub use intel_tee_quote_verification_rs::Collateral; +use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; +pub use teepot::sgx::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot::sgx::QuoteError; + +/// Get a TDX quote +pub fn tgx_get_quote(report_data_bytes: &[u8; 64]) -> Result, QuoteError> { + let mut tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; + tdx_report_data.d.copy_from_slice(report_data_bytes); + + let (error, quote) = tdx_att_get_quote(Some(&tdx_report_data), None, None, 0); + + if error == tdx_attest_error_t::TDX_ATTEST_SUCCESS { + if let Some(quote) = quote { + Ok(quote.into()) + } else { + Err(QuoteError::TdxAttGetQuote { + msg: "tdx_att_get_quote: No quote returned".into(), + inner: error, + }) + } + } else { + Err(error.into()) + } +} diff --git a/crates/teepot-vault/src/tdx/rtmr.rs b/crates/teepot-vault/src/tdx/rtmr.rs new file mode 100644 index 0000000..9d11562 --- /dev/null +++ b/crates/teepot-vault/src/tdx/rtmr.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024-2025 Matter Labs + +//! rtmr event data + +use teepot::sgx::QuoteError; + +/// The actual rtmr event data handled in DCAP +#[repr(C, packed)] +pub struct TdxRtmrEvent { + /// Always 1 + version: u32, + + /// The RTMR that will be extended. As defined in + /// https://github.com/confidential-containers/td-shim/blob/main/doc/tdshim_spec.md#td-measurement + /// we will use RTMR 3 for guest application code and configuration. + rtmr_index: u64, + + /// Data that will be used to extend RTMR + extend_data: [u8; 48usize], + + /// Not used in DCAP + event_type: u32, + + /// Always 0 + event_data_size: u32, + + /// Not used in DCAP + event_data: Vec, +} + +impl Default for TdxRtmrEvent { + fn default() -> Self { + Self { + extend_data: [0; 48], + version: 1, + rtmr_index: 3, + event_type: 0, + event_data_size: 0, + event_data: Vec::new(), + } + } +} + +impl TdxRtmrEvent { + /// use the extend data + pub fn with_extend_data(mut self, extend_data: [u8; 48]) -> Self { + self.extend_data = extend_data; + self + } + + /// extend the rtmr index + pub fn with_rtmr_index(mut self, rtmr_index: u64) -> Self { + self.rtmr_index = rtmr_index; + self + } + + /// extending the index, consuming self + pub fn extend(self) -> Result<(), QuoteError> { + let event: Vec = self.into(); + + match tdx_attest_rs::tdx_att_extend(&event) { + tdx_attest_rs::tdx_attest_error_t::TDX_ATTEST_SUCCESS => Ok(()), + error_code => Err(error_code.into()), + } + } +} + +impl From for Vec { + fn from(val: TdxRtmrEvent) -> Self { + let event_ptr = &val as *const TdxRtmrEvent as *const u8; + let event_data_size = std::mem::size_of::() * val.event_data_size as usize; + let res_size = std::mem::size_of::() * 3 + + std::mem::size_of::() + + std::mem::size_of::<[u8; 48]>() + + event_data_size; + let mut res = vec![0; res_size]; + unsafe { + for (i, chunk) in res.iter_mut().enumerate().take(res_size - event_data_size) { + *chunk = *event_ptr.add(i); + } + } + let event_data = val.event_data; + for i in 0..event_data_size { + res[i + res_size - event_data_size] = event_data[i]; + } + + res + } +} diff --git a/crates/teepot/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc b/crates/teepot-vault/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc similarity index 100% rename from crates/teepot/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc rename to crates/teepot-vault/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc diff --git a/crates/teepot/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 b/crates/teepot-vault/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 similarity index 100% rename from crates/teepot/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 rename to crates/teepot-vault/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 diff --git a/crates/teepot/tests/data/test.json b/crates/teepot-vault/tests/data/test.json similarity index 100% rename from crates/teepot/tests/data/test.json rename to crates/teepot-vault/tests/data/test.json diff --git a/crates/teepot/tests/data/test.json.asc b/crates/teepot-vault/tests/data/test.json.asc similarity index 100% rename from crates/teepot/tests/data/test.json.asc rename to crates/teepot-vault/tests/data/test.json.asc diff --git a/crates/teepot/tests/data/test2.json b/crates/teepot-vault/tests/data/test2.json similarity index 100% rename from crates/teepot/tests/data/test2.json rename to crates/teepot-vault/tests/data/test2.json diff --git a/crates/teepot/tests/data/test2.json.asc b/crates/teepot-vault/tests/data/test2.json.asc similarity index 100% rename from crates/teepot/tests/data/test2.json.asc rename to crates/teepot-vault/tests/data/test2.json.asc diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index 83b7386..8f960c4 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "teepot" -description = "TEE secret manager" +description = "TEE utilities" # no MIT license, because of copied code from: # * https://github.com/enarx/enarx # * https://github.com/enarx/sgx @@ -11,18 +11,13 @@ authors.workspace = true repository.workspace = true [dependencies] -actix-http.workspace = true -actix-web.workspace = true anyhow.workspace = true async-trait.workspace = true -awc.workspace = true bytemuck.workspace = true -bytes.workspace = true clap.workspace = true config.workspace = true const-oid.workspace = true enumset.workspace = true -futures-core.workspace = true getrandom.workspace = true hex.workspace = true intel-tee-quote-verification-rs.workspace = true @@ -34,7 +29,6 @@ opentelemetry-otlp.workspace = true opentelemetry-semantic-conventions.workspace = true opentelemetry_sdk.workspace = true p256.workspace = true -pgp.workspace = true pkcs8.workspace = true reqwest.workspace = true rsa.workspace = true @@ -42,7 +36,6 @@ rustls.workspace = true secp256k1 = { workspace = true, features = ["recovery"] } serde.workspace = true serde_json.workspace = true -serde_with.workspace = true sha2.workspace = true sha3.workspace = true signature.workspace = true @@ -52,7 +45,6 @@ tracing.workspace = true tracing-futures.workspace = true tracing-log.workspace = true tracing-subscriber.workspace = true -webpki-roots.workspace = true x509-cert.workspace = true zeroize.workspace = true @@ -61,4 +53,3 @@ base64.workspace = true testaso.workspace = true tokio.workspace = true tracing-test.workspace = true -zksync_basic_types.workspace = true diff --git a/crates/teepot/src/ethereum/mod.rs b/crates/teepot/src/ethereum/mod.rs index 30c7263..637565a 100644 --- a/crates/teepot/src/ethereum/mod.rs +++ b/crates/teepot/src/ethereum/mod.rs @@ -37,7 +37,6 @@ pub fn public_key_to_ethereum_address(public: &PublicKey) -> [u8; 20] { #[cfg(test)] mod tests { use secp256k1::{Secp256k1, SecretKey}; - use zksync_basic_types::H256; use super::*; @@ -71,10 +70,10 @@ mod tests { assert_eq!(address, expected_address.as_slice()); - // Generate a random root hash, create a message from the hash, and sign the message using + // Take a root hash, create a message from the hash, and sign the message using // the secret key - let root_hash = H256::random(); - let root_hash_bytes = root_hash.as_bytes(); + let root_hash = b"12345678901234567890123456789012"; + let root_hash_bytes = root_hash.as_slice(); let msg_to_sign = Message::from_digest(root_hash_bytes.try_into().unwrap()); let signature = sign_message(&secret_key, msg_to_sign).unwrap(); diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 1860eb3..227eb05 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -6,14 +6,12 @@ #![deny(missing_docs)] #![deny(clippy::all)] -pub mod client; pub mod config; pub mod ethereum; -pub mod json; pub mod log; +pub mod pki; pub mod prover; pub mod quote; -pub mod server; pub mod sgx; pub mod tdx; diff --git a/crates/teepot/src/server/pki.rs b/crates/teepot/src/pki/mod.rs similarity index 100% rename from crates/teepot/src/server/pki.rs rename to crates/teepot/src/pki/mod.rs diff --git a/crates/teepot/src/server/attestation.rs b/crates/teepot/src/quote/attestation.rs similarity index 65% rename from crates/teepot/src/server/attestation.rs rename to crates/teepot/src/quote/attestation.rs index 9cafb4d..f340e7b 100644 --- a/crates/teepot/src/server/attestation.rs +++ b/crates/teepot/src/quote/attestation.rs @@ -1,18 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Common attestation API for all TEEs use crate::{ - client::AttestationArgs, - json::http::AttestationResponse, quote::{ error::QuoteContext, get_quote, verify_quote_with_collateral, QuoteVerificationResult, }, - sgx::{parse_tcb_levels, Collateral, EnumSet, TcbLevel}, + sgx::{Collateral, EnumSet, TcbLevel}, }; use anyhow::{bail, Context, Result}; -use clap::Args; use intel_tee_quote_verification_rs::tee_qv_get_collateral; use serde::{Deserialize, Serialize}; use std::{ @@ -28,6 +25,15 @@ struct Attestation { earliest_expiration_date: i64, } +/// The attestation response +#[derive(Debug, Serialize, Deserialize)] +pub struct AttestationResponse { + /// The quote + pub quote: Arc<[u8]>, + /// The collateral + pub collateral: Arc, +} + /// Returns the quote and collateral for the current TEE. /// /// if `allowed_tcb_levels` is `None`, then any TCB level is accepted. @@ -110,43 +116,3 @@ pub fn get_quote_and_collateral( Ok(AttestationResponse { quote, collateral }) } - -/// Options and arguments needed to attest a TEE -#[derive(Args, Debug, Clone, Serialize, Deserialize, Default)] -pub struct VaultAttestationArgs { - /// hex encoded SGX mrsigner of the enclave to attest - #[arg(long, env = "VAULT_SGX_MRSIGNER")] - pub vault_sgx_mrsigner: Option, - /// hex encoded SGX mrenclave of the enclave to attest - #[arg(long, env = "VAULT_SGX_MRENCLAVE")] - pub vault_sgx_mrenclave: Option, - /// URL of the server - #[arg(long, required = true, env = "VAULT_ADDR")] - pub vault_addr: String, - /// allowed TCB levels, comma separated: - /// Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, OutOfDate, OutOfDateConfigNeeded - #[arg(long, value_parser = parse_tcb_levels, env = "VAULT_SGX_ALLOWED_TCB_LEVELS")] - pub vault_sgx_allowed_tcb_levels: Option>, -} - -impl From for AttestationArgs { - fn from(value: VaultAttestationArgs) -> Self { - AttestationArgs { - sgx_mrsigner: value.vault_sgx_mrsigner, - sgx_mrenclave: value.vault_sgx_mrenclave, - server: value.vault_addr, - sgx_allowed_tcb_levels: value.vault_sgx_allowed_tcb_levels, - } - } -} - -impl From<&VaultAttestationArgs> for AttestationArgs { - fn from(value: &VaultAttestationArgs) -> Self { - AttestationArgs { - sgx_mrsigner: value.vault_sgx_mrsigner.clone(), - sgx_mrenclave: value.vault_sgx_mrenclave.clone(), - server: value.vault_addr.clone(), - sgx_allowed_tcb_levels: value.vault_sgx_allowed_tcb_levels, - } - } -} diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 5f01993..1542282 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -1,10 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs // Parts of it are Copyright (c) 2024 Phala Network // and copied from https://github.com/Phala-Network/dcap-qvl //! Get a quote from a TEE + +pub mod attestation; pub mod error; use crate::{ diff --git a/examples/README.md b/examples/README.md index 10b9fc4..c5a28f3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -11,13 +11,13 @@ $ docker compose up ```bash ❯ cd teepot -❯ gpg --export username@example.com | base64 > gpgkey.pub +❯ gpg --export username@example.com | base64 > assets/gpgkey.pub ❯ export GPG_TTY="$(tty)" ❯ gpg-connect-agent updatestartuptty /bye -❯ RUST_LOG=info cargo run -p vault-unseal -- --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server https://20.172.154.218:8443 init --unseal-threshold 1 -u bin/tee-vault-admin/tests/data/gpgkey.pub --admin-threshold 1 -a bin/tee-vault-admin/tests/data/gpgkey.pub --admin-tee-mrenclave 21c8c1a4dbcce04798f5119eb47203084bc74e564a3c954d1a21172c656cb801 +❯ RUST_LOG=info cargo run -p vault-unseal -- --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server https://20.172.154.218:8443 init --unseal-threshold 1 -u assets/gpgkey.pub --admin-threshold 1 -a assets/gpgkey.pub --admin-tee-mrenclave 21c8c1a4dbcce04798f5119eb47203084bc74e564a3c954d1a21172c656cb801 Finished dev [unoptimized + debuginfo] target(s) in 0.09s - Running `target/debug/vault-unseal --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server 'https://20.172.154.218:8443' init --unseal-threshold 1 -u bin/tee-vault-admin/tests/data/gpgkey.pub --admin-threshold 1 -a bin/tee-vault-admin/tests/data/gpgkey.pub --admin-tee-mrenclave 21c8c1a4dbcce04798f5119eb47203084bc74e564a3c954d1a21172c656cb801` + Running `target/debug/vault-unseal --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server 'https://20.172.154.218:8443' init --unseal-threshold 1 -u assets/gpgkey.pub --admin-threshold 1 -a assets/gpgkey.pub --admin-tee-mrenclave 21c8c1a4dbcce04798f5119eb47203084bc74e564a3c954d1a21172c656cb801` 2023-08-23T14:47:56.902422Z INFO tee_client: Getting attestation report 2023-08-23T14:47:57.340877Z INFO tee_client: Checked or set server certificate public key hash `b4bf52fdb37431c8531fb310be389c2d17ad9bd41d662e10308c9147c007d0d0` 2023-08-23T14:47:57.741599Z INFO tee_client: Verifying attestation report @@ -155,9 +155,9 @@ container. --server https://127.0.0.1:8443 \ init \ --unseal-threshold 1 \ - --unseal-pgp-key-file ./tests/data/gpgkey.pub \ + --unseal-pgp-key-file ./assets/gpgkey.pub \ --admin-threshold 1 \ - --admin-pgp-key-file ./tests/data/gpgkey.pub \ + --admin-pgp-key-file ./assets/gpgkey.pub \ --admin-tee-mrenclave 98a540dd7056584e2009c7cf7374f932fbb8e30a4c66cc815c9809620653f751 ``` diff --git a/packages/teepotCrate/default.nix b/packages/teepotCrate/default.nix index 29dd051..9c3be39 100644 --- a/packages/teepotCrate/default.nix +++ b/packages/teepotCrate/default.nix @@ -37,11 +37,12 @@ let fileset = unions [ # Default files from crane (Rust and cargo files) (craneLib.fileset.commonCargoSources inputs.src) - (fileFilter (file: file.hasExt "hcl") (inputs.src + "/bin")) + (fileFilter (file: file.hasExt "hcl") (inputs.src + "/crates/teepot-vault/bin")) # deny.toml and friends (fileFilter (file: file.hasExt "toml") inputs.src) # Custom test data files (maybeMissing (inputs.src + "/crates/teepot/tests/data")) + (maybeMissing (inputs.src + "/crates/teepot-vault/tests/data")) ]; }; From 3f90e4f80bdbd1fdc25029ff04623ab1eef28707 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 21 Mar 2025 13:11:23 +0100 Subject: [PATCH 062/114] feat(tdx_google): add iproute2 and vector initialization wait - Include iproute2 in the container path for required networking tools. - Add a script to wait for vector to initialize before proceeding. --- packages/tdx_google/container.nix | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/tdx_google/container.nix b/packages/tdx_google/container.nix index 701e9f1..3e8d8a3 100644 --- a/packages/tdx_google/container.nix +++ b/packages/tdx_google/container.nix @@ -15,10 +15,19 @@ User = "root"; EnvironmentFile = "-/run/env/env"; }; - path = [ pkgs.docker pkgs.teepot.teepot.tdx_extend ]; + path = [ pkgs.docker pkgs.teepot.teepot.tdx_extend pkgs.iproute2 ]; script = '' set -eu -o pipefail + # wait for vector to initialize itself + for i in {1..30}; do + if [[ $(ss -H -t -l -n sport = 4318) ]]; then + break + fi + echo "Waiting for vector to initialize itself..." >&2 + sleep 1 + done + DIGEST=''${CONTAINER_DIGEST#sha256:} echo "Measuring $DIGEST" >&2 test -c /dev/tdx_guest && tdx-extend --digest "$DIGEST" --rtmr 3 From e62aff3511238e8843bd2a2a303b9d7311daeeec Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 25 Mar 2025 10:57:33 +0100 Subject: [PATCH 063/114] feat(config): update OTLP endpoint and protocol handling - Change default OTLP endpoint to match the HTTP/JSON spec. - Add dynamic protocol-based exporter configuration. - Support both gRPC and HTTP/JSON transports for logging. Signed-off-by: Harald Hoyer --- crates/teepot/src/config/mod.rs | 36 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/crates/teepot/src/config/mod.rs b/crates/teepot/src/config/mod.rs index 0132c62..100317a 100644 --- a/crates/teepot/src/config/mod.rs +++ b/crates/teepot/src/config/mod.rs @@ -147,8 +147,8 @@ impl Default for TelemetryOtlpConfig { fn default() -> Self { Self { enable: true, - endpoint: "http://127.0.0.1:4317".to_string(), - protocol: "grpc".to_string(), + endpoint: "http://127.0.0.1:4318/v1/logs".to_string(), + protocol: "http/json".to_string(), } } } @@ -269,15 +269,31 @@ fn init_telemetry( ) .build(); - // Configure the OTLP exporter - let logging_provider = SdkLoggerProvider::builder() - .with_batch_exporter( - opentelemetry_otlp::LogExporter::builder() - .with_tonic() + // Parse the protocol from the configuration + let protocol = protocol_from_string(&config.otlp.protocol)?; + + // Configure the OTLP exporter based on the protocol + let exporter_builder = opentelemetry_otlp::LogExporter::builder(); + + // Choose transport based on protocol + let exporter = match protocol { + opentelemetry_otlp::Protocol::Grpc => exporter_builder + .with_tonic() + .with_endpoint(&config.otlp.endpoint) + .with_protocol(protocol) + .build()?, + opentelemetry_otlp::Protocol::HttpBinary | opentelemetry_otlp::Protocol::HttpJson => { + exporter_builder + .with_http() .with_endpoint(&config.otlp.endpoint) - .with_protocol(protocol_from_string(&config.otlp.protocol)?) - .build()?, - ) + .with_protocol(protocol) + .build()? + } + }; + + // Configure the logging provider with the exporter + let logging_provider = SdkLoggerProvider::builder() + .with_batch_exporter(exporter) .with_resource(resource) .build(); From fa2ecee4bddbb91e005e9e766fa9af03172e76fb Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 26 Mar 2025 14:31:16 +0100 Subject: [PATCH 064/114] feat(sha384-extend): enhance SHA384 extend utility with padding and tests - Refactor `sha384-extend` to include digest padding and validation. - Add `extend_sha384` function for hex-string-based digest extension. - Introduce comprehensive test coverage for edge cases and errors. Signed-off-by: Harald Hoyer --- Cargo.lock | 1 + bin/sha384-extend/Cargo.toml | 1 + bin/sha384-extend/src/main.rs | 163 ++++++++++++++++++++++++++++++---- bin/tdx-extend/src/main.rs | 6 +- crates/teepot/src/lib.rs | 13 +-- crates/teepot/src/util/mod.rs | 83 +++++++++++++++++ 6 files changed, 234 insertions(+), 33 deletions(-) create mode 100644 crates/teepot/src/util/mod.rs diff --git a/Cargo.lock b/Cargo.lock index fdb34a6..d5628a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5189,6 +5189,7 @@ dependencies = [ "clap 4.5.30", "hex", "sha2", + "teepot", ] [[package]] diff --git a/bin/sha384-extend/Cargo.toml b/bin/sha384-extend/Cargo.toml index f9c58e6..85e8974 100644 --- a/bin/sha384-extend/Cargo.toml +++ b/bin/sha384-extend/Cargo.toml @@ -12,3 +12,4 @@ anyhow.workspace = true clap.workspace = true hex.workspace = true sha2.workspace = true +teepot.workspace = true diff --git a/bin/sha384-extend/src/main.rs b/bin/sha384-extend/src/main.rs index 2835a3e..f2ace5e 100644 --- a/bin/sha384-extend/src/main.rs +++ b/bin/sha384-extend/src/main.rs @@ -1,7 +1,26 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs -//! Extend the TDX measurement +//! A tool for extending SHA384 digests, commonly used in TPM and TDX operations +//! +//! # Overview +//! This utility implements the extend operation used in Trusted Platform Module (TPM) +//! Platform Configuration Registers (PCRs) and Intel Trust Domain Extensions (TDX) +//! Runtime Measurement Registers (RTMRs). The extend operation combines two SHA384 +//! digests by concatenating and then hashing them. +//! +//! # Usage +//! ```shell +//! sha384-extend [--base ] +//! ``` +//! Where: +//! - `extend-value`: SHA384 digest in hex format to extend with +//! - `initial-value`: Optional initial SHA384 digest in hex format (defaults to "00") +//! +//! # Example +//! ```shell +//! sha384-extend --base 01 26bb0c +//! ``` #![deny(missing_docs)] #![deny(clippy::all)] @@ -9,31 +28,139 @@ use anyhow::{Context, Result}; use clap::Parser; use sha2::Digest; +use teepot::util::pad; -/// Calculate a TDX rtmr or TPM pcr sha384 value by extending it +/// Calculate e.g. a TDX RTMR or TPM PCR SHA384 digest by extending it with another #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Arguments { - /// digest in hex to extend with - #[arg(long)] + /// The SHA384 digest (in hex format) to extend the base value with. + /// Must be a valid hex string that can be padded to 48 bytes (384 bits). extend: String, - /// initial digest in hex - #[arg(long)] - digest: String, + + /// The initial SHA384 digest (in hex format) to extend from. + /// Must be a valid hex string that can be padded to 48 bytes (384 bits). + #[arg(long, default_value = "00", required = false)] + base: String, +} + +/// Extends a base SHA384 digest with another digest +/// +/// # Arguments +/// * `base` - Base hex string to extend from +/// * `extend` - Hex string to extend with +/// +/// # Returns +/// * `Result` - The resulting SHA384 digest as a hex string +/// +/// # Examples +/// ``` +/// let result = extend_sha384("00", "aa").unwrap(); +/// ``` +pub fn extend_sha384(base: &str, extend: &str) -> Result { + let mut hasher = sha2::Sha384::new(); + + hasher.update(pad::<48>(&hex::decode(base).context(format!( + "Failed to decode base digest '{}' - expected hex string", + base + ))?)?); + + hasher.update(pad::<48>(&hex::decode(extend).context(format!( + "Failed to decode extend digest '{}' - expected hex string", + extend + ))?)?); + + Ok(hex::encode(hasher.finalize())) } fn main() -> Result<()> { let args = Arguments::parse(); - - // Parse the digest string as a hex array - let extend_bytes = hex::decode(&args.extend).context("Invalid digest format")?; - let mut digest_bytes = hex::decode(&args.digest).context("Invalid digest format")?; - - digest_bytes.extend(extend_bytes); - - let bytes = sha2::Sha384::digest(&digest_bytes); - let hex = hex::encode(bytes); - + let hex = extend_sha384(&args.base, &args.extend)?; println!("{hex}"); Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_BASE: &str = "00"; + const TEST_EXTEND: &str = "d3a665eb2bf8a6c4e6cee0ccfa663ee4098fc4903725b1823d8d0316126bb0cb"; + const EXPECTED_RESULT: &str = "971fb52f90ec98a234301ca9b8fc30b613c33e3dd9c0cc42dcb8003d4a95d8fb218b75baf028b70a3cabcb947e1ca453"; + + const EXPECTED_RESULT_00: &str = "f57bb7ed82c6ae4a29e6c9879338c592c7d42a39135583e8ccbe3940f2344b0eb6eb8503db0ffd6a39ddd00cd07d8317"; + + #[test] + fn test_extend_sha384_with_test_vectors() { + let result = extend_sha384(TEST_BASE, TEST_EXTEND).unwrap(); + assert_eq!( + result, EXPECTED_RESULT, + "SHA384 extend result didn't match expected value" + ); + + // Test with empty base + let result = extend_sha384("", TEST_EXTEND).unwrap(); + assert_eq!( + result, EXPECTED_RESULT, + "SHA384 extend result didn't match expected value" + ); + + // Test with empty base + let result = extend_sha384("", "").unwrap(); + assert_eq!( + result, EXPECTED_RESULT_00, + "SHA384 extend result didn't match expected value" + ); + } + + #[test] + fn test_extend_sha384_with_invalid_base() { + // Test with invalid hex in base + let result = extend_sha384("not_hex", TEST_EXTEND); + assert!(result.is_err(), "Should fail with invalid base hex"); + + // Test with odd length hex string + let result = extend_sha384("0", TEST_EXTEND); + assert!(result.is_err(), "Should fail with odd-length hex string"); + } + + #[test] + fn test_extend_sha384_with_invalid_extend() { + // Test with invalid hex in extend + let result = extend_sha384(TEST_BASE, "not_hex"); + assert!(result.is_err(), "Should fail with invalid extend hex"); + + // Test with odd length hex string + let result = extend_sha384(TEST_BASE, "0"); + assert!(result.is_err(), "Should fail with odd-length hex string"); + } + + #[test] + fn test_extend_sha384_with_oversized_input() { + // Create a hex string that's too long (more than 48 bytes when decoded) + let oversized = "00".repeat(49); // 49 bytes when decoded + + let result = extend_sha384(TEST_BASE, &oversized); + assert!(result.is_err(), "Should fail with oversized extend value"); + + let result = extend_sha384(&oversized, TEST_EXTEND); + assert!(result.is_err(), "Should fail with oversized base value"); + } + + #[test] + fn test_extend_sha384_idempotent() { + // Test that extending with the same values produces the same result + let result1 = extend_sha384(TEST_BASE, TEST_EXTEND).unwrap(); + let result2 = extend_sha384(TEST_BASE, TEST_EXTEND).unwrap(); + assert_eq!(result1, result2, "Same inputs should produce same output"); + } + + #[test] + fn test_extend_sha384_case_sensitivity() { + // Test that upper and lower case hex strings produce the same result + let upper_extend = TEST_EXTEND.to_uppercase(); + let result1 = extend_sha384(TEST_BASE, TEST_EXTEND).unwrap(); + let result2 = extend_sha384(TEST_BASE, &upper_extend).unwrap(); + assert_eq!(result1, result2, "Case should not affect the result"); + } +} diff --git a/bin/tdx-extend/src/main.rs b/bin/tdx-extend/src/main.rs index 1a4056c..5a43f59 100644 --- a/bin/tdx-extend/src/main.rs +++ b/bin/tdx-extend/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs //! Extend the TDX measurement @@ -10,8 +10,8 @@ use anyhow::{Context, Result}; use clap::Parser; use teepot::{ log::{setup_logging, LogLevelParser}, - pad, tdx::rtmr::TdxRtmrEvent, + util::pad, }; use tracing::{error, level_filters::LevelFilter}; @@ -40,7 +40,7 @@ fn main_with_error() -> Result<()> { // Parse the digest string as a hex array let digest_bytes = hex::decode(&args.digest).context("Invalid digest format")?; - let extend_data: [u8; 48] = pad(&digest_bytes); + let extend_data: [u8; 48] = pad(&digest_bytes).context("Invalid digest length")?; // Extend the TDX measurement with the extend data TdxRtmrEvent::default() diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 1860eb3..89a7ab2 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -16,15 +16,4 @@ pub mod quote; pub mod server; pub mod sgx; pub mod tdx; - -/// pad a byte slice to a fixed sized array -pub fn pad(input: &[u8]) -> [u8; T] { - let mut output = [0; T]; - let len = input.len(); - if len > T { - output.copy_from_slice(&input[..T]); - } else { - output[..len].copy_from_slice(input); - } - output -} +pub mod util; diff --git a/crates/teepot/src/util/mod.rs b/crates/teepot/src/util/mod.rs new file mode 100644 index 0000000..1951142 --- /dev/null +++ b/crates/teepot/src/util/mod.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! utility functions. + +use thiserror::Error; + +/// Errors that can occur when padding byte vectors to fixed-size arrays. +#[derive(Error, Debug)] +pub enum PadError { + /// Indicates that the input vector's length exceeds the target array size. + /// + /// # Fields + /// * `expected` - The target size of the array in bytes + /// * `actual` - The actual length of the input vector in bytes + /// + /// # Example + /// ```rust + /// # use teepot::util::{pad, PadError}; + /// let long_input = vec![1, 2, 3, 4]; + /// let result = pad::<2>(&long_input); + /// assert!(matches!( + /// result, + /// Err(PadError::InputTooLong { expected: 2, actual: 4 }) + /// )); + /// ``` + #[error("Input vector is too long - expected {expected} bytes, got {actual}")] + InputTooLong { + /// The expected length (target array size) + expected: usize, + /// The actual length of the provided input + actual: usize, + }, +} + +/// Pad a byte vector to a fixed-size array by appending zeros. If the input is longer +/// than the target size, returns an error. +/// +/// # Arguments +/// * `input` - Input byte vector to be padded with zeros +/// +/// # Returns +/// * `Result<[u8; T], PadError>` - A fixed-size array of length T, or a PadError if input is too long +/// +/// # Errors +/// Returns `PadError::InputTooLong` if the input vector length exceeds the target array size T, +/// containing both the expected and actual sizes +/// +/// # Examples +/// ```rust +/// # use teepot::util::{pad, PadError}; +/// let input = vec![1, 2, 3]; +/// let padded: [u8; 5] = pad(&input)?; +/// assert_eq!(padded, [1, 2, 3, 0, 0]); +/// +/// // Error case: input too long +/// let long_input = vec![1, 2, 3, 4, 5, 6]; +/// assert!(matches!( +/// pad::<5>(&long_input), +/// Err(PadError::InputTooLong { expected: 5, actual: 6 }) +/// )); +/// # Ok::<(), PadError>(()) +/// ``` +/// +/// # Type Parameters +/// * `T` - The fixed size of the output array in bytes +pub fn pad(input: &[u8]) -> Result<[u8; T], PadError> { + let mut output = [0u8; T]; + match input.len().cmp(&T) { + std::cmp::Ordering::Greater => Err(PadError::InputTooLong { + expected: T, + actual: input.len(), + }), + std::cmp::Ordering::Equal => { + output.copy_from_slice(input); + Ok(output) + } + std::cmp::Ordering::Less => { + output[..input.len()].copy_from_slice(input); + Ok(output) + } + } +} From e27b5da85612640c5c25aed9252661ae98d5c997 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 19 Mar 2025 10:37:37 +0100 Subject: [PATCH 065/114] fix(tee-key-preexec): add context to file write operations - Add context to `std::fs::write` calls to improve error tracing. - Ensures better debugging by attaching filenames to potential errors. Signed-off-by: Harald Hoyer --- bin/tee-key-preexec/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 3eeb8b9..5d62361 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -58,17 +58,17 @@ fn main_with_error() -> Result<()> { .extend()?; // save quote to file - std::fs::write(TEE_QUOTE_FILE, quote)?; + std::fs::write(TEE_QUOTE_FILE, quote).context(TEE_QUOTE_FILE)?; teepot::quote::TEEType::TDX.to_string() } Ok((tee_type, quote)) => { // save quote to file - std::fs::write(TEE_QUOTE_FILE, quote)?; + std::fs::write(TEE_QUOTE_FILE, quote).context(TEE_QUOTE_FILE)?; tee_type.to_string() } Err(e) => { error!("Failed to get quote: {}", e); - std::fs::write(TEE_QUOTE_FILE, [])?; + std::fs::write(TEE_QUOTE_FILE, []).context(TEE_QUOTE_FILE)?; "none".to_string() } }; From 3257f316b5111b49ddc8ee47e2ff0b723f474b5d Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 2 Apr 2025 16:27:24 +0200 Subject: [PATCH 066/114] feat(ci): switch to GitHub Container Registry for images Updated the workflow to push container images to GitHub Container Registry instead of Docker Hub. Added a login step for GHCR and updated image tagging and pushing commands accordingly. Signed-off-by: Harald Hoyer --- .github/workflows/nix.yml | 33 ++++++++++--------- assets/gcloud-deploy.sh | 2 +- bin/tee-self-attestation-test/README.md | 18 +++++----- examples/README.md | 10 +++--- examples/k8s/vault-1-pod.yaml | 4 +-- examples/k8s/vault-2-pod.yaml | 4 +-- examples/k8s/vault-3-pod.yaml | 4 +-- examples/k8s/vault-unseal-pod-0.yaml | 2 +- examples/k8s/vault-unseal-pod-1.yaml | 2 +- examples/k8s/vault-unseal-pod-2.yaml | 2 +- systems/x86_64-linux/tdxtest/default.nix | 2 +- .../v1/instance/attributes/container_image | 2 +- 12 files changed, 43 insertions(+), 42 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index f17c396..ceaa93c 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -2,10 +2,10 @@ name: nix on: pull_request: - branches: [ "main" ] + branches: ["main"] push: - branches: [ "main" ] - tags: [ "*" ] + branches: ["main"] + tags: ["*"] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -34,7 +34,7 @@ jobs: build: needs: check - runs-on: [ matterlabs-default-infra-runners ] + runs-on: [matterlabs-default-infra-runners] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - uses: cachix/install-nix-action@v30 @@ -56,7 +56,7 @@ jobs: push_to_docker: needs: build - runs-on: [ matterlabs-default-infra-runners ] + runs-on: [matterlabs-default-infra-runners] concurrency: group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.config.nixpackage }} cancel-in-progress: true @@ -90,11 +90,12 @@ jobs: cache: tee-pot token: ${{ secrets.ATTIC_TOKEN }} - - name: Log in to Docker Hub - uses: docker/login-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: - username: ${{ secrets.DOCKERHUB_USER }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Load container id: build @@ -106,21 +107,21 @@ jobs: - name: Push container run: | - echo "Pushing image ${{ steps.build.outputs.IMAGE_TAG }} to Docker Hub" - docker tag "${{ steps.build.outputs.IMAGE_TAG }}" matterlabsrobot/"${{ steps.build.outputs.IMAGE_TAG }}" - docker push matterlabsrobot/"${{ steps.build.outputs.IMAGE_TAG }}" + echo "Pushing image ${{ steps.build.outputs.IMAGE_TAG }} to GitHub Container Registry" + docker tag "${{ steps.build.outputs.IMAGE_TAG }}" "ghcr.io/${{ github.repository_owner }}"/"${{ steps.build.outputs.IMAGE_TAG }}" + docker push "ghcr.io/${{ github.repository_owner }}"/"${{ steps.build.outputs.IMAGE_TAG }}" - name: Tag container as latest if: ${{ github.event_name == 'push' }} run: | - docker tag "${{ steps.build.outputs.IMAGE_TAG }}" matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:latest" - docker push matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:latest" + docker tag "${{ steps.build.outputs.IMAGE_TAG }}" "ghcr.io/${{ github.repository_owner }}"/"${{ steps.build.outputs.IMAGE_NAME }}:latest" + docker push "ghcr.io/${{ github.repository_owner }}"/"${{ steps.build.outputs.IMAGE_NAME }}:latest" - name: Tag container with tag if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} run: | - docker tag "${{ steps.build.outputs.IMAGE_TAG }}" matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:$GITHUB_REF_NAME" - docker push matterlabsrobot/"${{ steps.build.outputs.IMAGE_NAME }}:$GITHUB_REF_NAME" + docker tag "${{ steps.build.outputs.IMAGE_TAG }}" "ghcr.io/${{ github.repository_owner }}"/"${{ steps.build.outputs.IMAGE_NAME }}:$GITHUB_REF_NAME" + docker push "ghcr.io/${{ github.repository_owner }}"/"${{ steps.build.outputs.IMAGE_NAME }}:$GITHUB_REF_NAME" - name: Generate build ID for Flux Image Automation id: flux diff --git a/assets/gcloud-deploy.sh b/assets/gcloud-deploy.sh index 7eeaa06..5d6e6bf 100755 --- a/assets/gcloud-deploy.sh +++ b/assets/gcloud-deploy.sh @@ -45,6 +45,6 @@ gcloud compute instances create tdx-pilot \ --maintenance-policy=TERMINATE \ --image-project=tdx-pilot \ --project tdx-pilot \ - --metadata=container_hub="docker.io",container_image="matterlabsrobot/test-tdx:117p5y281limw0w7b03v802ij00c5gzw" \ + --metadata=container_hub="docker.io",container_image="ghcr.io/matter-labs/test-tdx:117p5y281limw0w7b03v802ij00c5gzw" \ --metadata-from-file=container_config=$BASE_DIR/config.json \ --image tdx-img-f-"${NO}" diff --git a/bin/tee-self-attestation-test/README.md b/bin/tee-self-attestation-test/README.md index 233938f..d7ea174 100644 --- a/bin/tee-self-attestation-test/README.md +++ b/bin/tee-self-attestation-test/README.md @@ -1,6 +1,6 @@ # self-attestation-test -Optionally build and load the containers (remove the `matterlabsrobot/` repo from the commands below then) +Optionally build and load the containers (remove the `ghcr.io/matter-labs/` repo from the commands below then) ```bash $ nix build -L .#container-verify-attestation-sgx && docker load -i result @@ -12,9 +12,9 @@ $ nix build -L .#container-self-attestation-test-sgx-azure && docker load -i res ```bash ❯ docker run -i --init --rm --privileged --device /dev/sgx_enclave \ - matterlabsrobot/teepot-self-attestation-test-sgx-azure:latest \ + ghcr.io/matter-labs/teepot-self-attestation-test-sgx-azure:latest \ | base64 -d --ignore-garbage \ - | docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest - + | docker run -i --rm ghcr.io/matter-labs/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... @@ -31,9 +31,9 @@ reportdata: 00000000000000000000000000000000000000000000000000000000000000000000 ```bash ❯ docker run -i --init --rm --privileged --device /dev/sgx_enclave \ - matterlabsrobot/teepot-self-attestation-test-sgx-dcap:latest \ + ghcr.io/matter-labs/teepot-self-attestation-test-sgx-dcap:latest \ | base64 -d --ignore-garbage \ - | docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest - + | docker run -i --rm ghcr.io/matter-labs/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... @@ -48,9 +48,9 @@ On an outdated machine, this might look like this: ```bash ❯ docker run -i --init --rm --privileged --device /dev/sgx_enclave \ - matterlabsrobot/teepot-self-attestation-test-sgx-dcap:latest \ + ghcr.io/matter-labs/teepot-self-attestation-test-sgx-dcap:latest \ | base64 -d --ignore-garbage \ - | docker run -i --rm matterlabsrobot/verify-attestation-sgx:latest - + | docker run -i --rm ghcr.io/matter-labs/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... @@ -73,9 +73,9 @@ reportdata: 00000000000000000000000000000000000000000000000000000000000000000000 ```bash ❯ podman run -i --rm --group-add=keep-groups -v /var/run/aesmd:/var/run/aesmd -v /dev/sgx_enclave:/dev/sgx_enclave \ - matterlabsrobot/teepot-self-attestation-test-sgx-dcap:latest \ + ghcr.io/matter-labs/teepot-self-attestation-test-sgx-dcap:latest \ | base64 -d --ignore-garbage \ | podman run -i --rm --net host \ -v /etc/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf \ - matterlabsrobot/verify-attestation-sgx-dcap:latest + ghcr.io/matter-labs/verify-attestation-sgx-dcap:latest ``` diff --git a/examples/README.md b/examples/README.md index c5a28f3..c4ad6c0 100644 --- a/examples/README.md +++ b/examples/README.md @@ -121,7 +121,7 @@ Passphrase: Find out the `mr_enclave` value of the teepot-vault-admin-sgx-azure enclave and extract the sigstruct file: ```bash -❯ docker run -v .:/mnt --pull always -it matterlabsrobot/teepot-vault-admin-sgx-azure:latest 'gramine-sgx-sigstruct-view teepot-vault-admin-sgx-azure.sig; cp teepot-vault-admin-sgx-azure.sig /mnt' +❯ docker run -v .:/mnt --pull always -it ghcr.io/matter-labs/teepot-vault-admin-sgx-azure:latest 'gramine-sgx-sigstruct-view teepot-vault-admin-sgx-azure.sig; cp teepot-vault-admin-sgx-azure.sig /mnt' [...] Attributes: mr_signer: c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d @@ -226,18 +226,18 @@ Next is to sign the admin tee with the vault-admin tool: ``` Then replace `teepot-vault-admin-sgx-azure.sig` with `teepot-vault-admin-sgx-azure-new.sig` in the container -image `matterlabsrobot/teepot-vault-admin-sgx-azure:latest` with this Dockerfile: +image `ghcr.io/matter-labs/teepot-vault-admin-sgx-azure:latest` with this Dockerfile: ```Dockerfile -FROM matterlabsrobot/teepot-vault-admin-sgx-azure:latest +FROM ghcr.io/matter-labs/teepot-vault-admin-sgx-azure:latest COPY teepot-vault-admin-sgx-azure-new.sig /app/teepot-vault-admin-sgx-azure.sig ``` Build and push the new image: ```bash -❯ docker build -t matterlabsrobot/teepot-vault-admin-sgx-azure-signed:latest . -❯ docker push matterlabsrobot/teepot-vault-admin-sgx-azure-signed:latest +❯ docker build -t ghcr.io/matter-labs/teepot-vault-admin-sgx-azure-signed:latest . +❯ docker push ghcr.io/matter-labs/teepot-vault-admin-sgx-azure-signed:latest ``` Delete the old vault-admin pod and start the new one: diff --git a/examples/k8s/vault-1-pod.yaml b/examples/k8s/vault-1-pod.yaml index 2e3f181..8f36550 100644 --- a/examples/k8s/vault-1-pod.yaml +++ b/examples/k8s/vault-1-pod.yaml @@ -27,7 +27,7 @@ spec: imagePullSecrets: - name: docker-regcred containers: - - image: matterlabsrobot/teepot-vault-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-sgx-azure:latest name: vault imagePullPolicy: Always env: @@ -62,7 +62,7 @@ spec: volumeMounts: - mountPath: /opt/vault/data name: data-1 - - image: matterlabsrobot/teepot-vault-unseal-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-unseal-sgx-azure:latest name: vault-unseal imagePullPolicy: Always env: diff --git a/examples/k8s/vault-2-pod.yaml b/examples/k8s/vault-2-pod.yaml index dd69d42..69b8d72 100644 --- a/examples/k8s/vault-2-pod.yaml +++ b/examples/k8s/vault-2-pod.yaml @@ -27,7 +27,7 @@ spec: imagePullSecrets: - name: docker-regcred containers: - - image: matterlabsrobot/teepot-vault-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-sgx-azure:latest name: vault imagePullPolicy: Always env: @@ -62,7 +62,7 @@ spec: volumeMounts: - mountPath: /opt/vault/data name: data-2 - - image: matterlabsrobot/teepot-vault-unseal-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-unseal-sgx-azure:latest name: vault-unseal imagePullPolicy: Always env: diff --git a/examples/k8s/vault-3-pod.yaml b/examples/k8s/vault-3-pod.yaml index fb740ce..3854ef1 100644 --- a/examples/k8s/vault-3-pod.yaml +++ b/examples/k8s/vault-3-pod.yaml @@ -27,7 +27,7 @@ spec: imagePullSecrets: - name: docker-regcred containers: - - image: matterlabsrobot/teepot-vault-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-sgx-azure:latest name: vault imagePullPolicy: Always env: @@ -62,7 +62,7 @@ spec: volumeMounts: - mountPath: /opt/vault/data name: data-3 - - image: matterlabsrobot/teepot-vault-unseal-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-unseal-sgx-azure:latest name: vault-unseal imagePullPolicy: Always env: diff --git a/examples/k8s/vault-unseal-pod-0.yaml b/examples/k8s/vault-unseal-pod-0.yaml index d358c11..0363bfd 100644 --- a/examples/k8s/vault-unseal-pod-0.yaml +++ b/examples/k8s/vault-unseal-pod-0.yaml @@ -11,7 +11,7 @@ spec: operator: Exists effect: NoSchedule containers: - - image: matterlabsrobot/teepot-vault-unseal-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-unseal-sgx-azure:latest name: vault-unseal imagePullPolicy: Always env: diff --git a/examples/k8s/vault-unseal-pod-1.yaml b/examples/k8s/vault-unseal-pod-1.yaml index 8fdbafb..6c7d222 100644 --- a/examples/k8s/vault-unseal-pod-1.yaml +++ b/examples/k8s/vault-unseal-pod-1.yaml @@ -11,7 +11,7 @@ spec: operator: Exists effect: NoSchedule containers: - - image: matterlabsrobot/teepot-vault-unseal-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-unseal-sgx-azure:latest name: vault-unseal imagePullPolicy: Always env: diff --git a/examples/k8s/vault-unseal-pod-2.yaml b/examples/k8s/vault-unseal-pod-2.yaml index 0b4150c..a0c9575 100644 --- a/examples/k8s/vault-unseal-pod-2.yaml +++ b/examples/k8s/vault-unseal-pod-2.yaml @@ -11,7 +11,7 @@ spec: operator: Exists effect: NoSchedule containers: - - image: matterlabsrobot/teepot-vault-unseal-sgx-azure:latest + - image: ghcr.io/matter-labs/teepot-vault-unseal-sgx-azure:latest name: vault-unseal imagePullPolicy: Always env: diff --git a/systems/x86_64-linux/tdxtest/default.nix b/systems/x86_64-linux/tdxtest/default.nix index 668d840..f8c425e 100644 --- a/systems/x86_64-linux/tdxtest/default.nix +++ b/systems/x86_64-linux/tdxtest/default.nix @@ -29,7 +29,7 @@ systemd.services.docker_start_container = { # environment = { - # CONTAINER_IMAGE = "matterlabsrobot/tdx-test:pnj1ryxxb8gbzk9wh18s9bcqrzr1z9ff"; + # CONTAINER_IMAGE = "ghcr.io/matter-labs/tdx-test:pnj1ryxxb8gbzk9wh18s9bcqrzr1z9ff"; # CONTAINER_HUB = "docker.io"; # CONTAINER_TOKEN = ""; # CONTAINER_USER = ""; diff --git a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image index 8b18200..6049602 100644 --- a/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image +++ b/systems/x86_64-linux/tdxtest/web-root/computeMetadata/v1/instance/attributes/container_image @@ -1 +1 @@ -matterlabsrobot/tdx-test:81hgl91s5hj0sb83c7ij9acf2s5qjvb5 +ghcr.io/matter-labs/tdx-test:81hgl91s5hj0sb83c7ij9acf2s5qjvb5 From 8596e0dc6a85616211d919d4f9c8828f5b641b71 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 4 Apr 2025 14:00:09 +0200 Subject: [PATCH 067/114] fix(teepot-vault): remove leftover `tdx` module Signed-off-by: Harald Hoyer --- crates/teepot-vault/src/lib.rs | 1 - crates/teepot-vault/src/tdx/mod.rs | 32 ---------- crates/teepot-vault/src/tdx/rtmr.rs | 90 ----------------------------- 3 files changed, 123 deletions(-) delete mode 100644 crates/teepot-vault/src/tdx/mod.rs delete mode 100644 crates/teepot-vault/src/tdx/rtmr.rs diff --git a/crates/teepot-vault/src/lib.rs b/crates/teepot-vault/src/lib.rs index d74a0ff..91fa082 100644 --- a/crates/teepot-vault/src/lib.rs +++ b/crates/teepot-vault/src/lib.rs @@ -9,7 +9,6 @@ pub mod client; pub mod json; pub mod server; -pub mod tdx; /// pad a byte slice to a fixed sized array pub fn pad(input: &[u8]) -> [u8; T] { diff --git a/crates/teepot-vault/src/tdx/mod.rs b/crates/teepot-vault/src/tdx/mod.rs deleted file mode 100644 index df787ac..0000000 --- a/crates/teepot-vault/src/tdx/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2025 Matter Labs - -//! Intel TDX helper functions. - -pub mod rtmr; - -pub use intel_tee_quote_verification_rs::Collateral; -use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; -pub use teepot::sgx::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; -use teepot::sgx::QuoteError; - -/// Get a TDX quote -pub fn tgx_get_quote(report_data_bytes: &[u8; 64]) -> Result, QuoteError> { - let mut tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; - tdx_report_data.d.copy_from_slice(report_data_bytes); - - let (error, quote) = tdx_att_get_quote(Some(&tdx_report_data), None, None, 0); - - if error == tdx_attest_error_t::TDX_ATTEST_SUCCESS { - if let Some(quote) = quote { - Ok(quote.into()) - } else { - Err(QuoteError::TdxAttGetQuote { - msg: "tdx_att_get_quote: No quote returned".into(), - inner: error, - }) - } - } else { - Err(error.into()) - } -} diff --git a/crates/teepot-vault/src/tdx/rtmr.rs b/crates/teepot-vault/src/tdx/rtmr.rs deleted file mode 100644 index 9d11562..0000000 --- a/crates/teepot-vault/src/tdx/rtmr.rs +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024-2025 Matter Labs - -//! rtmr event data - -use teepot::sgx::QuoteError; - -/// The actual rtmr event data handled in DCAP -#[repr(C, packed)] -pub struct TdxRtmrEvent { - /// Always 1 - version: u32, - - /// The RTMR that will be extended. As defined in - /// https://github.com/confidential-containers/td-shim/blob/main/doc/tdshim_spec.md#td-measurement - /// we will use RTMR 3 for guest application code and configuration. - rtmr_index: u64, - - /// Data that will be used to extend RTMR - extend_data: [u8; 48usize], - - /// Not used in DCAP - event_type: u32, - - /// Always 0 - event_data_size: u32, - - /// Not used in DCAP - event_data: Vec, -} - -impl Default for TdxRtmrEvent { - fn default() -> Self { - Self { - extend_data: [0; 48], - version: 1, - rtmr_index: 3, - event_type: 0, - event_data_size: 0, - event_data: Vec::new(), - } - } -} - -impl TdxRtmrEvent { - /// use the extend data - pub fn with_extend_data(mut self, extend_data: [u8; 48]) -> Self { - self.extend_data = extend_data; - self - } - - /// extend the rtmr index - pub fn with_rtmr_index(mut self, rtmr_index: u64) -> Self { - self.rtmr_index = rtmr_index; - self - } - - /// extending the index, consuming self - pub fn extend(self) -> Result<(), QuoteError> { - let event: Vec = self.into(); - - match tdx_attest_rs::tdx_att_extend(&event) { - tdx_attest_rs::tdx_attest_error_t::TDX_ATTEST_SUCCESS => Ok(()), - error_code => Err(error_code.into()), - } - } -} - -impl From for Vec { - fn from(val: TdxRtmrEvent) -> Self { - let event_ptr = &val as *const TdxRtmrEvent as *const u8; - let event_data_size = std::mem::size_of::() * val.event_data_size as usize; - let res_size = std::mem::size_of::() * 3 - + std::mem::size_of::() - + std::mem::size_of::<[u8; 48]>() - + event_data_size; - let mut res = vec![0; res_size]; - unsafe { - for (i, chunk) in res.iter_mut().enumerate().take(res_size - event_data_size) { - *chunk = *event_ptr.add(i); - } - } - let event_data = val.event_data; - for i in 0..event_data_size { - res[i + res_size - event_data_size] = event_data[i]; - } - - res - } -} From 1e853f653a142a61bc67d272c88de5da84249b42 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 2 Apr 2025 15:37:33 +0200 Subject: [PATCH 068/114] refactor(quote): move TCB level logic to a dedicated module - Extracted `TcbLevel` functionality from `sgx` module to `quote::tcblevel`. - Updated all references to import `TcbLevel` and related utilities from `quote::tcblevel`. - Updated copyright headers to reflect the new year range. Signed-off-by: Harald Hoyer --- bin/verify-attestation/src/main.rs | 6 +++--- crates/teepot-vault/bin/tee-stress-client/src/main.rs | 2 +- crates/teepot-vault/bin/tee-vault-admin/src/main.rs | 4 ++-- crates/teepot-vault/bin/tee-vault-unseal/src/main.rs | 4 ++-- crates/teepot-vault/src/client/mod.rs | 7 ++++--- crates/teepot-vault/src/client/vault.rs | 7 ++++--- crates/teepot-vault/src/server/attestation.rs | 7 +++++-- crates/teepot/src/pki/mod.rs | 2 -- crates/teepot/src/quote/attestation.rs | 10 +++++----- crates/teepot/src/quote/mod.rs | 1 + crates/teepot/src/{sgx => quote}/tcblevel.rs | 9 ++++++--- crates/teepot/src/sgx/mod.rs | 4 +--- crates/teepot/src/tdx/mod.rs | 3 +-- 13 files changed, 35 insertions(+), 31 deletions(-) rename crates/teepot/src/{sgx => quote}/tcblevel.rs (96%) diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index c7ae611..3eee26f 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -7,9 +7,9 @@ use anyhow::{bail, Context, Result}; use clap::Parser; use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; -use teepot::{ - quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, - sgx::TcbLevel, +use teepot::quote::{ + error, tcblevel::TcbLevel, tee_qv_get_collateral, verify_quote_with_collateral, + QuoteVerificationResult, }; #[derive(Parser, Debug)] diff --git a/crates/teepot-vault/bin/tee-stress-client/src/main.rs b/crates/teepot-vault/bin/tee-stress-client/src/main.rs index 87dddae..a937869 100644 --- a/crates/teepot-vault/bin/tee-stress-client/src/main.rs +++ b/crates/teepot-vault/bin/tee-stress-client/src/main.rs @@ -11,7 +11,7 @@ use anyhow::{Context, Result}; use clap::Parser; use serde::{Deserialize, Serialize}; use std::time::Duration; -use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot::quote::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; use teepot_vault::{ client::vault::VaultConnection, server::{ diff --git a/crates/teepot-vault/bin/tee-vault-admin/src/main.rs b/crates/teepot-vault/bin/tee-vault-admin/src/main.rs index 782a3c2..08ef10e 100644 --- a/crates/teepot-vault/bin/tee-vault-admin/src/main.rs +++ b/crates/teepot-vault/bin/tee-vault-admin/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Server to handle requests to the Vault TEE @@ -17,7 +17,7 @@ use digest::get_digest; use rustls::ServerConfig; use sign::post_sign; use std::{net::Ipv6Addr, sync::Arc}; -use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot::quote::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; use teepot_vault::{ json::http::{SignRequest, VaultCommandRequest, DIGEST_URL}, server::{ diff --git a/crates/teepot-vault/bin/tee-vault-unseal/src/main.rs b/crates/teepot-vault/bin/tee-vault-unseal/src/main.rs index eac2869..9498699 100644 --- a/crates/teepot-vault/bin/tee-vault-unseal/src/main.rs +++ b/crates/teepot-vault/bin/tee-vault-unseal/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Server to initialize and unseal the Vault TEE. @@ -22,7 +22,7 @@ use std::path::PathBuf; use std::sync::{Arc, RwLock}; use std::time::Duration; use teepot::pki::make_self_signed_cert; -use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use teepot::quote::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; use teepot_vault::client::{AttestationArgs, TeeConnection}; use teepot_vault::json::http::{Init, Unseal}; use teepot_vault::json::secrets::AdminConfig; diff --git a/crates/teepot-vault/src/client/mod.rs b/crates/teepot-vault/src/client/mod.rs index bf8dfa2..8235f8e 100644 --- a/crates/teepot-vault/src/client/mod.rs +++ b/crates/teepot-vault/src/client/mod.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs. @@ -25,11 +25,12 @@ use rustls::{ }; use sha2::{Digest, Sha256}; use std::{sync::Arc, time, time::Duration}; -use teepot::{quote::Report, sgx::Quote}; pub use teepot::{ + quote::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, quote::{verify_quote_with_collateral, QuoteVerificationResult}, - sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}, + sgx::sgx_ql_qv_result_t, }; +use teepot::{quote::Report, sgx::Quote}; use tracing::{debug, error, info, trace, warn}; use x509_cert::{ der::{Decode as _, Encode as _}, diff --git a/crates/teepot-vault/src/client/vault.rs b/crates/teepot-vault/src/client/vault.rs index f6dc225..462d47d 100644 --- a/crates/teepot-vault/src/client/vault.rs +++ b/crates/teepot-vault/src/client/vault.rs @@ -30,10 +30,11 @@ use std::{ }; use teepot::quote::error::QuoteContext; pub use teepot::{ - quote::{verify_quote_with_collateral, QuoteVerificationResult}, - sgx::{ - parse_tcb_levels, sgx_gramine_get_quote, sgx_ql_qv_result_t, Collateral, EnumSet, TcbLevel, + quote::{ + tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, + verify_quote_with_collateral, QuoteVerificationResult, }, + sgx::{sgx_gramine_get_quote, sgx_ql_qv_result_t, Collateral}, }; use tracing::{debug, error, info, trace}; diff --git a/crates/teepot-vault/src/server/attestation.rs b/crates/teepot-vault/src/server/attestation.rs index 8688e03..c710f96 100644 --- a/crates/teepot-vault/src/server/attestation.rs +++ b/crates/teepot-vault/src/server/attestation.rs @@ -9,10 +9,13 @@ use serde::{Deserialize, Serialize}; pub use teepot::{ quote::{ - attestation::get_quote_and_collateral, error::QuoteContext, get_quote, + attestation::get_quote_and_collateral, + error::QuoteContext, + get_quote, + tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, verify_quote_with_collateral, QuoteVerificationResult, }, - sgx::{parse_tcb_levels, Collateral, EnumSet, TcbLevel}, + sgx::Collateral, }; /// Options and arguments needed to attest a TEE diff --git a/crates/teepot/src/pki/mod.rs b/crates/teepot/src/pki/mod.rs index b7e28d0..bed0cf6 100644 --- a/crates/teepot/src/pki/mod.rs +++ b/crates/teepot/src/pki/mod.rs @@ -2,9 +2,7 @@ // Copyright (c) 2023-2025 Matter Labs //! Create a private key and a signed and self-signed certificates - use crate::quote::{error::QuoteContext, get_quote}; -pub use crate::sgx::{parse_tcb_levels, sgx_ql_qv_result_t, EnumSet, TcbLevel}; use anyhow::{Context, Result}; use const_oid::{ db::rfc5280::{ID_KP_CLIENT_AUTH, ID_KP_SERVER_AUTH}, diff --git a/crates/teepot/src/quote/attestation.rs b/crates/teepot/src/quote/attestation.rs index f340e7b..a41c8de 100644 --- a/crates/teepot/src/quote/attestation.rs +++ b/crates/teepot/src/quote/attestation.rs @@ -3,11 +3,11 @@ //! Common attestation API for all TEEs -use crate::{ - quote::{ - error::QuoteContext, get_quote, verify_quote_with_collateral, QuoteVerificationResult, - }, - sgx::{Collateral, EnumSet, TcbLevel}, +use crate::quote::{ + error::QuoteContext, + get_quote, + tcblevel::{EnumSet, TcbLevel}, + verify_quote_with_collateral, Collateral, QuoteVerificationResult, }; use anyhow::{bail, Context, Result}; use intel_tee_quote_verification_rs::tee_qv_get_collateral; diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 1542282..321aa08 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -8,6 +8,7 @@ pub mod attestation; pub mod error; +pub mod tcblevel; use crate::{ quote::error::{QuoteContext as _, QuoteError}, diff --git a/crates/teepot/src/sgx/tcblevel.rs b/crates/teepot/src/quote/tcblevel.rs similarity index 96% rename from crates/teepot/src/sgx/tcblevel.rs rename to crates/teepot/src/quote/tcblevel.rs index 2e05c92..f7b7990 100644 --- a/crates/teepot/src/sgx/tcblevel.rs +++ b/crates/teepot/src/quote/tcblevel.rs @@ -1,12 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Intel SGX Enclave TCB level wrapper use enumset::EnumSetType; use intel_tee_quote_verification_rs::sgx_ql_qv_result_t; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; +use serde::{Deserialize, Serialize}; +use std::{ + fmt::{Display, Formatter}, + str::FromStr, +}; pub use enumset::EnumSet; diff --git a/crates/teepot/src/sgx/mod.rs b/crates/teepot/src/sgx/mod.rs index 9ae67c6..d5dba44 100644 --- a/crates/teepot/src/sgx/mod.rs +++ b/crates/teepot/src/sgx/mod.rs @@ -1,12 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs // Copyright (c) The Enarx Project Developers https://github.com/enarx/sgx //! Intel SGX Enclave report structures. pub mod sign; -pub mod tcblevel; use crate::quote::error::QuoteContext; pub use crate::quote::error::QuoteError; @@ -17,7 +16,6 @@ use std::{ io::{Read, Write}, mem, }; -pub use tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; /// Structure of a quote #[derive(Copy, Clone, Debug, AnyBitPattern)] diff --git a/crates/teepot/src/tdx/mod.rs b/crates/teepot/src/tdx/mod.rs index 09d6e4c..321c2d7 100644 --- a/crates/teepot/src/tdx/mod.rs +++ b/crates/teepot/src/tdx/mod.rs @@ -1,11 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Intel TDX helper functions. pub mod rtmr; -pub use crate::sgx::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; use crate::sgx::QuoteError; pub use intel_tee_quote_verification_rs::Collateral; use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; From 2605e2ae3a415b13529a0e8f31fb53fd51bcea5d Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 2 Apr 2025 16:03:01 +0200 Subject: [PATCH 069/114] refactor(verify-era-proof-attestation): modularize and restructure proof verification logic - Split `verify-era-proof-attestation` into modular subcomponents for maintainability. - Moved client, proof handling, and core types into dedicated modules. --- Cargo.lock | 1856 +++-------------- Cargo.toml | 1 - bin/verify-era-proof-attestation/Cargo.toml | 14 +- bin/verify-era-proof-attestation/README.md | 76 + .../examples/attestation_policy.yaml | 31 + bin/verify-era-proof-attestation/src/args.rs | 95 - .../src/client.rs | 45 - .../src/client/http.rs | 66 + .../src/client/json_rpc.rs | 58 + .../src/client/mod.rs | 12 + .../src/client/retry.rs | 107 + .../src/core/config.rs | 455 ++++ .../src/core/constants.rs | 19 + .../src/core/mod.rs | 12 + .../src/core/types.rs | 101 + bin/verify-era-proof-attestation/src/error.rs | 103 + bin/verify-era-proof-attestation/src/main.rs | 270 +-- .../src/processor/batch_processor.rs | 118 ++ .../src/processor/continuous_processor.rs | 95 + .../src/processor/mod.rs | 65 + .../src/processor/one_shot_processor.rs | 79 + bin/verify-era-proof-attestation/src/proof.rs | 172 -- .../src/proof/fetcher.rs | 139 ++ .../src/proof/mod.rs | 9 + .../src/proof/parsing.rs | 277 +++ .../src/proof/types.rs | 83 + .../src/verification.rs | 208 -- .../src/verification/attestation.rs | 35 + .../src/verification/batch.rs | 141 ++ .../src/verification/mod.rs | 14 + .../src/verification/policy.rs | 212 ++ .../src/verification/reporting.rs | 93 + .../src/verification/signature.rs | 157 ++ crates/teepot/src/quote/tcblevel.rs | 4 +- 34 files changed, 2918 insertions(+), 2304 deletions(-) create mode 100644 bin/verify-era-proof-attestation/README.md create mode 100644 bin/verify-era-proof-attestation/examples/attestation_policy.yaml delete mode 100644 bin/verify-era-proof-attestation/src/args.rs delete mode 100644 bin/verify-era-proof-attestation/src/client.rs create mode 100644 bin/verify-era-proof-attestation/src/client/http.rs create mode 100644 bin/verify-era-proof-attestation/src/client/json_rpc.rs create mode 100644 bin/verify-era-proof-attestation/src/client/mod.rs create mode 100644 bin/verify-era-proof-attestation/src/client/retry.rs create mode 100644 bin/verify-era-proof-attestation/src/core/config.rs create mode 100644 bin/verify-era-proof-attestation/src/core/constants.rs create mode 100644 bin/verify-era-proof-attestation/src/core/mod.rs create mode 100644 bin/verify-era-proof-attestation/src/core/types.rs create mode 100644 bin/verify-era-proof-attestation/src/error.rs create mode 100644 bin/verify-era-proof-attestation/src/processor/batch_processor.rs create mode 100644 bin/verify-era-proof-attestation/src/processor/continuous_processor.rs create mode 100644 bin/verify-era-proof-attestation/src/processor/mod.rs create mode 100644 bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs delete mode 100644 bin/verify-era-proof-attestation/src/proof.rs create mode 100644 bin/verify-era-proof-attestation/src/proof/fetcher.rs create mode 100644 bin/verify-era-proof-attestation/src/proof/mod.rs create mode 100644 bin/verify-era-proof-attestation/src/proof/parsing.rs create mode 100644 bin/verify-era-proof-attestation/src/proof/types.rs delete mode 100644 bin/verify-era-proof-attestation/src/verification.rs create mode 100644 bin/verify-era-proof-attestation/src/verification/attestation.rs create mode 100644 bin/verify-era-proof-attestation/src/verification/batch.rs create mode 100644 bin/verify-era-proof-attestation/src/verification/mod.rs create mode 100644 bin/verify-era-proof-attestation/src/verification/policy.rs create mode 100644 bin/verify-era-proof-attestation/src/verification/reporting.rs create mode 100644 bin/verify-era-proof-attestation/src/verification/signature.rs diff --git a/Cargo.lock b/Cargo.lock index e12e690..08b0c8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ "actix-tls", "actix-utils", "ahash", - "base64 0.22.1", + "base64", "bitflags 2.8.0", "brotli", "bytes", @@ -434,7 +434,7 @@ dependencies = [ "actix-service", "actix-tls", "actix-utils", - "base64 0.22.1", + "base64", "bytes", "cfg-if", "cookie", @@ -481,34 +481,6 @@ dependencies = [ "paste", ] -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower 0.4.13", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.9" @@ -516,11 +488,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "bytes", "futures-util", "http 1.2.0", - "http-body 1.0.1", + "http-body", "http-body-util", "itoa", "matchit", @@ -530,29 +502,12 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower 0.5.2", "tower-layer", "tower-service", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.5" @@ -563,12 +518,12 @@ dependencies = [ "bytes", "futures-util", "http 1.2.0", - "http-body 1.0.1", + "http-body", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower-layer", "tower-service", ] @@ -585,27 +540,15 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base16ct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -618,26 +561,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "beef" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" -dependencies = [ - "serde", -] - -[[package]] -name = "bigdecimal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "bindgen" version = "0.59.2" @@ -656,7 +579,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "which", ] @@ -678,7 +601,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.98", "which", @@ -701,18 +624,12 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.98", "which", ] -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bitcoin-io" version = "0.1.3" @@ -957,11 +874,9 @@ checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", - "js-sys", "num-traits", "serde", - "wasm-bindgen", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1027,7 +942,7 @@ version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.98", @@ -1066,8 +981,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" dependencies = [ "const-oid", - "der 0.7.9", - "spki 0.7.3", + "der", + "spki", "x509-cert", ] @@ -1098,10 +1013,19 @@ dependencies = [ "serde", "serde_json", "toml", - "winnow 0.7.3", + "winnow", "yaml-rust2", ] +[[package]] +name = "const-decoder" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b381abde2cdc1bc3817e394b24e05667a2dc89f37570cbd34d9c397d99e56e3f" +dependencies = [ + "compile-fmt", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -1200,39 +1124,12 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - [[package]] name = "crunchy" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - [[package]] name = "crypto-bigint" version = "0.5.5" @@ -1256,6 +1153,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.98", +] + [[package]] name = "ctr" version = "0.9.2" @@ -1371,26 +1278,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "serde", - "uuid", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - [[package]] name = "der" version = "0.7.9" @@ -1471,18 +1358,18 @@ dependencies = [ [[package]] name = "derive_more" -version = "1.0.0-beta.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "1.0.0-beta.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", @@ -1531,10 +1418,10 @@ dependencies = [ "digest", "num-bigint-dig", "num-traits", - "pkcs8 0.10.2", - "rfc6979 0.4.0", + "pkcs8", + "rfc6979", "sha2", - "signature 2.2.0", + "signature", "zeroize", ] @@ -1563,30 +1450,18 @@ dependencies = [ "subtle", ] -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der 0.6.1", - "elliptic-curve 0.12.3", - "rfc6979 0.3.1", - "signature 1.6.4", -] - [[package]] name = "ecdsa" version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.7.9", + "der", "digest", - "elliptic-curve 0.13.8", - "rfc6979 0.4.0", - "signature 2.2.0", - "spki 0.7.3", + "elliptic-curve", + "rfc6979", + "signature", + "spki", ] [[package]] @@ -1595,8 +1470,8 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8 0.10.2", - "signature 2.2.0", + "pkcs8", + "signature", ] [[package]] @@ -1619,43 +1494,23 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct 0.1.1", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest", - "ff 0.12.1", - "generic-array", - "group 0.12.1", - "pkcs8 0.9.0", - "rand_core", - "sec1 0.3.0", - "subtle", - "zeroize", -] - [[package]] name = "elliptic-curve" version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.5", + "base16ct", + "crypto-bigint", "digest", - "ff 0.13.0", + "ff", "generic-array", - "group 0.13.0", + "group", "hkdf", "pem-rfc7468 0.7.0", - "pkcs8 0.10.2", + "pkcs8", "rand_core", - "sec1 0.7.3", + "sec1", "subtle", "zeroize", ] @@ -1788,16 +1643,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - [[package]] name = "ff" version = "0.13.0" @@ -1814,18 +1659,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "findshlibs" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" -dependencies = [ - "cc", - "lazy_static", - "libc", - "winapi", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -1838,12 +1671,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flagset" version = "0.4.6" @@ -2032,7 +1859,7 @@ dependencies = [ "cfg-if", "libc", "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2059,15 +1886,15 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "gloo-net" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" dependencies = [ "futures-channel", "futures-core", "futures-sink", "gloo-utils", - "http 0.2.12", + "http 1.2.0", "js-sys", "pin-project", "serde", @@ -2115,24 +1942,13 @@ dependencies = [ "uuid", ] -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff 0.12.1", - "rand_core", - "subtle", -] - [[package]] name = "group" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff 0.13.0", + "ff", "rand_core", "subtle", ] @@ -2205,12 +2021,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -2268,17 +2078,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - [[package]] name = "http" version = "0.2.12" @@ -2301,17 +2100,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2331,7 +2119,7 @@ dependencies = [ "bytes", "futures-util", "http 1.2.0", - "http-body 1.0.1", + "http-body", "pin-project-lite", ] @@ -2353,30 +2141,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.6.0" @@ -2388,7 +2152,7 @@ dependencies = [ "futures-util", "h2 0.4.8", "http 1.2.0", - "http-body 1.0.1", + "http-body", "httparse", "httpdate", "itoa", @@ -2406,7 +2170,7 @@ checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", - "hyper 1.6.0", + "hyper", "hyper-util", "log", "rustls", @@ -2416,44 +2180,19 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.32", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "hyper-timeout" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.6.0", + "hyper", "hyper-util", "pin-project-lite", "tokio", "tower-service", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper 0.14.32", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -2462,7 +2201,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.6.0", + "hyper", "hyper-util", "native-tls", "tokio", @@ -2480,8 +2219,8 @@ dependencies = [ "futures-channel", "futures-util", "http 1.2.0", - "http-body 1.0.1", - "hyper 1.6.0", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -2762,15 +2501,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -2836,15 +2566,15 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.23.2" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" +checksum = "834af00800e962dee8f7bfc0f60601de215e73e78e5497d733a2919da837d3c8" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-http-client", "jsonrpsee-proc-macros", - "jsonrpsee-types 0.23.2", + "jsonrpsee-types", "jsonrpsee-wasm-client", "jsonrpsee-ws-client", "tracing", @@ -2852,11 +2582,11 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.23.2" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" +checksum = "def0fd41e2f53118bd1620478d12305b2c75feef57ea1f93ef70568c98081b7e" dependencies = [ - "base64 0.22.1", + "base64", "futures-channel", "futures-util", "gloo-net", @@ -2877,22 +2607,20 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.23.2" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +checksum = "76637f6294b04e747d68e69336ef839a3493ca62b35bf488ead525f7da75c5bb" dependencies = [ - "anyhow", "async-trait", - "beef", "bytes", "futures-timer", "futures-util", "http 1.2.0", - "http-body 1.0.1", + "http-body", "http-body-util", - "jsonrpsee-types 0.23.2", + "jsonrpsee-types", "pin-project", - "rustc-hash", + "rustc-hash 2.1.1", "serde", "serde_json", "thiserror 1.0.69", @@ -2904,18 +2632,18 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.23.2" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" +checksum = "87c24e981ad17798bbca852b0738bfb7b94816ed687bd0d5da60bfa35fa0fdc3" dependencies = [ "async-trait", - "base64 0.22.1", - "http-body 1.0.1", - "hyper 1.6.0", + "base64", + "http-body", + "hyper", "hyper-rustls", "hyper-util", "jsonrpsee-core", - "jsonrpsee-types 0.23.2", + "jsonrpsee-types", "rustls", "rustls-platform-verifier", "serde", @@ -2929,12 +2657,12 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.23.2" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" +checksum = "5e65763c942dfc9358146571911b0cd1c361c2d63e2d2305622d40d36376ca80" dependencies = [ - "heck 0.5.0", - "proc-macro-crate 3.2.0", + "heck", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.98", @@ -2942,22 +2670,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.23.2" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" -dependencies = [ - "beef", - "http 1.2.0", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.24.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6" +checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" dependencies = [ "http 1.2.0", "serde", @@ -2967,40 +2682,28 @@ dependencies = [ [[package]] name = "jsonrpsee-wasm-client" -version = "0.23.2" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4727ac037f834c6f04c0912cada7532dbddb54e92fbc64e33d6cb8c24af313c9" +checksum = "42e41af42ca39657313748174d02766e5287d3a57356f16756dbd8065b933977" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types 0.23.2", + "jsonrpsee-types", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.23.2" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" +checksum = "6f4f3642a292f5b76d8a16af5c88c16a0860f2ccc778104e5c848b28183d9538" dependencies = [ "http 1.2.0", "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types 0.23.2", + "jsonrpsee-types", "url", ] -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", - "sha2", -] - [[package]] name = "k256" version = "0.13.4" @@ -3008,11 +2711,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "ecdsa", + "elliptic-curve", "once_cell", "sha2", - "signature 2.2.0", + "signature", ] [[package]] @@ -3058,7 +2761,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3067,26 +2770,6 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" -[[package]] -name = "linkme" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566336154b9e58a4f055f6dd4cbab62c7dc0826ce3c0a04e63b2d2ecd784cdae" -dependencies = [ - "linkme-impl", -] - -[[package]] -name = "linkme-impl" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3132,44 +2815,6 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" -[[package]] -name = "logos" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" -dependencies = [ - "logos-derive", -] - -[[package]] -name = "logos-codegen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" -dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax 0.6.29", - "syn 2.0.98", -] - -[[package]] -name = "logos-derive" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" -dependencies = [ - "logos-codegen", -] - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - [[package]] name = "matchers" version = "0.1.0" @@ -3201,29 +2846,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "miette" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" -dependencies = [ - "miette-derive", - "once_cell", - "thiserror 1.0.69", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "mime" version = "0.3.17" @@ -3257,12 +2879,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "mutually_exclusive_features" version = "0.1.0" @@ -3306,20 +2922,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -3328,7 +2930,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "serde", ] [[package]] @@ -3349,16 +2950,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", - "serde", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -3385,18 +2976,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -3407,34 +2986,13 @@ dependencies = [ "libm", ] -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive 0.6.1", -] - [[package]] name = "num_enum" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "num_enum_derive 0.7.3", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 2.0.98", + "num_enum_derive", ] [[package]] @@ -3443,7 +3001,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.98", @@ -3526,16 +3084,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" -dependencies = [ - "opentelemetry_api", - "opentelemetry_sdk 0.20.0", -] - [[package]] name = "opentelemetry" version = "0.28.0" @@ -3557,26 +3105,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c513c7af3bec30113f3d4620134ff923295f1e9c580fda2b8abe0831f925ddc0" dependencies = [ "log", - "opentelemetry 0.28.0", + "opentelemetry", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] -[[package]] -name = "opentelemetry-http" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7594ec0e11d8e33faf03530a4c49af7064ebba81c1480e01be67d90b356508b" -dependencies = [ - "async-trait", - "bytes", - "http 0.2.12", - "opentelemetry_api", - "reqwest 0.11.27", -] - [[package]] name = "opentelemetry-http" version = "0.28.0" @@ -3586,32 +3121,11 @@ dependencies = [ "async-trait", "bytes", "http 1.2.0", - "opentelemetry 0.28.0", - "reqwest 0.12.12", + "opentelemetry", + "reqwest", "tracing", ] -[[package]] -name = "opentelemetry-otlp" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275" -dependencies = [ - "async-trait", - "futures-core", - "http 0.2.12", - "opentelemetry-http 0.9.0", - "opentelemetry-proto 0.3.0", - "opentelemetry-semantic-conventions 0.12.0", - "opentelemetry_api", - "opentelemetry_sdk 0.20.0", - "prost 0.11.9", - "reqwest 0.11.27", - "thiserror 1.0.69", - "tokio", - "tonic 0.9.2", -] - [[package]] name = "opentelemetry-otlp" version = "0.28.0" @@ -3621,49 +3135,28 @@ dependencies = [ "async-trait", "futures-core", "http 1.2.0", - "opentelemetry 0.28.0", - "opentelemetry-http 0.28.0", - "opentelemetry-proto 0.28.0", - "opentelemetry_sdk 0.28.0", - "prost 0.13.5", - "reqwest 0.12.12", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "reqwest", "thiserror 2.0.11", "tokio", - "tonic 0.12.3", + "tonic", "tracing", ] -[[package]] -name = "opentelemetry-proto" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" -dependencies = [ - "opentelemetry_api", - "opentelemetry_sdk 0.20.0", - "prost 0.11.9", - "tonic 0.9.2", -] - [[package]] name = "opentelemetry-proto" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f8870d3024727e99212eb3bb1762ec16e255e3e6f58eeb3dc8db1aa226746d" dependencies = [ - "opentelemetry 0.28.0", - "opentelemetry_sdk 0.28.0", - "prost 0.13.5", - "tonic 0.12.3", -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" -dependencies = [ - "opentelemetry 0.20.0", + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", ] [[package]] @@ -3672,45 +3165,6 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fb3a2f78c2d55362cd6c313b8abedfbc0142ab3c2676822068fd2ab7d51f9b7" -[[package]] -name = "opentelemetry_api" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b" -dependencies = [ - "futures-channel", - "futures-util", - "indexmap 1.9.3", - "js-sys", - "once_cell", - "pin-project-lite", - "thiserror 1.0.69", - "urlencoding", -] - -[[package]] -name = "opentelemetry_sdk" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "once_cell", - "opentelemetry_api", - "ordered-float 3.9.2", - "percent-encoding", - "rand", - "regex", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tokio-stream", -] - [[package]] name = "opentelemetry_sdk" version = "0.28.0" @@ -3722,7 +3176,7 @@ dependencies = [ "futures-executor", "futures-util", "glob", - "opentelemetry 0.28.0", + "opentelemetry", "percent-encoding", "rand", "serde_json", @@ -3732,35 +3186,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ordered-float" -version = "3.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" -dependencies = [ - "num-traits", -] - -[[package]] -name = "os_info" -version = "3.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a604e53c24761286860eba4e2c8b23a0161526476b1de520139d69cdb85a6b5" -dependencies = [ - "log", - "serde", - "windows-sys 0.52.0", -] - [[package]] name = "overload" version = "0.1.1" @@ -3773,8 +3198,8 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "ecdsa", + "elliptic-curve", "primeorder", "sha2", ] @@ -3785,8 +3210,8 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "ecdsa", + "elliptic-curve", "primeorder", "sha2", ] @@ -3797,9 +3222,9 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" dependencies = [ - "base16ct 0.2.0", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "base16ct", + "ecdsa", + "elliptic-curve", "primeorder", "rand_core", "sha2", @@ -3827,7 +3252,7 @@ version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.98", @@ -3853,7 +3278,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3887,11 +3312,11 @@ checksum = "c04c052a5cf901a229d69fb8804b04c8017c143712529c6e8277aac243fc2989" dependencies = [ "chrono", "cms", - "der 0.7.9", + "der", "digest", "num-traits", "pem-rfc7468 1.0.0-rc.2", - "reqwest 0.12.12", + "reqwest", "rsa", "sha1", "sha2", @@ -3928,16 +3353,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.7.1", -] - [[package]] name = "pgp" version = "0.15.0" @@ -3948,7 +3363,7 @@ dependencies = [ "aes-gcm", "aes-kw", "argon2", - "base64 0.22.1", + "base64", "bitfield", "block-padding", "blowfish", @@ -3964,27 +3379,27 @@ dependencies = [ "crc24", "curve25519-dalek", "derive_builder", - "derive_more 1.0.0-beta.6", + "derive_more 1.0.0", "des", "digest", "dsa", "eax", - "ecdsa 0.16.9", + "ecdsa", "ed25519-dalek", - "elliptic-curve 0.13.8", + "elliptic-curve", "flate2", "generic-array", "hex", "hkdf", "idea", "iter-read", - "k256 0.13.4", + "k256", "log", "md-5", "nom", "num-bigint-dig", "num-traits", - "num_enum 0.7.3", + "num_enum", "ocb3", "p256", "p384", @@ -3996,7 +3411,7 @@ dependencies = [ "sha1-checked", "sha2", "sha3", - "signature 2.2.0", + "signature", "smallvec", "thiserror 2.0.11", "twofish", @@ -4042,19 +3457,9 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der 0.7.9", - "pkcs8 0.10.2", - "spki 0.7.3", -] - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki 0.6.0", + "der", + "pkcs8", + "spki", ] [[package]] @@ -4063,8 +3468,8 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.7.9", - "spki 0.7.3", + "der", + "spki", ] [[package]] @@ -4116,7 +3521,7 @@ version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve 0.13.8", + "elliptic-curve", ] [[package]] @@ -4132,23 +3537,13 @@ dependencies = [ "uint", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.24", + "toml_edit", ] [[package]] @@ -4183,26 +3578,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive 0.12.6", -] - [[package]] name = "prost" version = "0.13.5" @@ -4210,54 +3585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive 0.13.5", -] - -[[package]] -name = "prost-build" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" -dependencies = [ - "bytes", - "heck 0.5.0", - "itertools 0.12.1", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost 0.12.6", - "prost-types", - "regex", - "syn 2.0.98", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools 0.12.1", - "proc-macro2", - "quote", - "syn 2.0.98", + "prost-derive", ] [[package]] @@ -4273,67 +3601,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "prost-reflect" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057237efdb71cf4b3f9396302a3d6599a92fa94063ba537b66130980ea9909f3" -dependencies = [ - "base64 0.21.7", - "logos", - "miette", - "once_cell", - "prost 0.12.6", - "prost-types", - "serde", - "serde-value", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost 0.12.6", -] - -[[package]] -name = "protox" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bb76c5f6221de491fe2c8f39b106330bbd9762c6511119c07940e10eb9ff11" -dependencies = [ - "bytes", - "miette", - "prost 0.12.6", - "prost-reflect", - "prost-types", - "protox-parse", - "thiserror 1.0.69", -] - -[[package]] -name = "protox-parse" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4581f441c58863525a3e6bec7b8de98188cf75239a56c725a3e7288450a33f" -dependencies = [ - "logos", - "miette", - "prost-types", - "thiserror 1.0.69", -] - -[[package]] -name = "quick-protobuf" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" -dependencies = [ - "byteorder", -] - [[package]] name = "quote" version = "1.0.38" @@ -4438,53 +3705,13 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-tls 0.5.0", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration 0.5.1", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - [[package]] name = "reqwest" version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", "futures-channel", @@ -4492,11 +3719,11 @@ dependencies = [ "futures-util", "h2 0.4.8", "http 1.2.0", - "http-body 1.0.1", + "http-body", "http-body-util", - "hyper 1.6.0", + "hyper", "hyper-rustls", - "hyper-tls 0.6.0", + "hyper-tls", "hyper-util", "ipnet", "js-sys", @@ -4506,12 +3733,12 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.2.0", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", - "system-configuration 0.6.1", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tower 0.5.2", @@ -4523,17 +3750,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac", - "zeroize", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -4589,11 +3805,11 @@ dependencies = [ "num-integer", "num-traits", "pkcs1", - "pkcs8 0.10.2", + "pkcs8", "rand_core", "sha2", - "signature 2.2.0", - "spki 0.7.3", + "signature", + "spki", "subtle", "zeroize", ] @@ -4624,6 +3840,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -4675,21 +3897,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.2.0", + "rustls-pemfile", "rustls-pki-types", "schannel", "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -4780,30 +3993,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct 0.1.1", - "der 0.6.1", - "generic-array", - "pkcs8 0.9.0", - "subtle", - "zeroize", -] - [[package]] name = "sec1" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct 0.2.0", - "der 0.7.9", + "base16ct", + "der", "generic-array", - "pkcs8 0.10.2", + "pkcs8", "subtle", "zeroize", ] @@ -4848,9 +4047,9 @@ dependencies = [ [[package]] name = "secrecy" -version = "0.8.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" dependencies = [ "zeroize", ] @@ -4891,114 +4090,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" -[[package]] -name = "sentry" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce4b57f1b521f674df7a1d200be8ff5d74e3712020ee25b553146657b5377d5" -dependencies = [ - "httpdate", - "native-tls", - "reqwest 0.11.27", - "sentry-backtrace", - "sentry-contexts", - "sentry-core", - "sentry-debug-images", - "sentry-panic", - "sentry-tracing", - "tokio", - "ureq", -] - -[[package]] -name = "sentry-backtrace" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cc8d4e04a73de8f718dc703943666d03f25d3e9e4d0fb271ca0b8c76dfa00e" -dependencies = [ - "backtrace", - "once_cell", - "regex", - "sentry-core", -] - -[[package]] -name = "sentry-contexts" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6436c1bad22cdeb02179ea8ef116ffc217797c028927def303bc593d9320c0d1" -dependencies = [ - "hostname", - "libc", - "os_info", - "rustc_version", - "sentry-core", - "uname", -] - -[[package]] -name = "sentry-core" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901f761681f97db3db836ef9e094acdd8756c40215326c194201941947164ef1" -dependencies = [ - "once_cell", - "rand", - "sentry-types", - "serde", - "serde_json", -] - -[[package]] -name = "sentry-debug-images" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdb263e73d22f39946f6022ed455b7561b22ff5553aca9be3c6a047fa39c328" -dependencies = [ - "findshlibs", - "once_cell", - "sentry-core", -] - -[[package]] -name = "sentry-panic" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fbf1c163f8b6a9d05912e1b272afa27c652e8b47ea60cb9a57ad5e481eea99" -dependencies = [ - "sentry-backtrace", - "sentry-core", -] - -[[package]] -name = "sentry-tracing" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82eabcab0a047040befd44599a1da73d3adb228ff53b5ed9795ae04535577704" -dependencies = [ - "sentry-backtrace", - "sentry-core", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "sentry-types" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da956cca56e0101998c8688bc65ce1a96f00673a0e58e663664023d4c7911e82" -dependencies = [ - "debugid", - "hex", - "rand", - "serde", - "serde_json", - "thiserror 1.0.69", - "time", - "url", - "uuid", -] - [[package]] name = "serde" version = "1.0.218" @@ -5008,16 +4099,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float 2.10.1", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.218" @@ -5068,6 +4149,7 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ + "hex", "serde", "serde_with_macros 1.5.2", ] @@ -5078,7 +4160,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "indexmap 1.9.3", @@ -5160,17 +4242,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha2_ce" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca2daa77078f4ddff27e75c4bf59e4c2697525f56dbb3c842d34a5d1f2b04a2" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha3" version = "0.10.8" @@ -5192,16 +4263,6 @@ dependencies = [ "teepot", ] -[[package]] -name = "sha3_ce" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c9a08202c50378d8a07a5f458193a5f542d2828ac6640263dbc0c2533ea25e" -dependencies = [ - "digest", - "keccak", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -5226,16 +4287,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core", -] - [[package]] name = "signature" version = "2.2.0" @@ -5283,7 +4334,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures", "httparse", @@ -5298,16 +4349,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - [[package]] name = "spki" version = "0.7.3" @@ -5315,7 +4356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der 0.7.9", + "der", ] [[package]] @@ -5350,24 +4391,24 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.24.1" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "rustversion", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] @@ -5398,12 +4439,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5424,17 +4459,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys 0.5.0", -] - [[package]] name = "system-configuration" version = "0.6.1" @@ -5443,17 +4467,7 @@ checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.8.0", "core-foundation", - "system-configuration-sys 0.6.0", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", + "system-configuration-sys", ] [[package]] @@ -5520,7 +4534,7 @@ dependencies = [ "secp256k1 0.30.0", "teepot", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5533,7 +4547,7 @@ dependencies = [ "rsa", "teepot", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", "x509-cert", ] @@ -5544,10 +4558,10 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "base64 0.22.1", + "base64", "teepot", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5562,7 +4576,7 @@ dependencies = [ "teepot", "teepot-vault", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5583,7 +4597,7 @@ dependencies = [ "teepot-vault", "tracing", "tracing-actix-web", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5600,7 +4614,7 @@ dependencies = [ "teepot", "teepot-vault", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5610,7 +4624,7 @@ version = "0.3.0" dependencies = [ "anyhow", "async-trait", - "base64 0.22.1", + "base64", "bytemuck", "clap 4.5.30", "config", @@ -5620,14 +4634,14 @@ dependencies = [ "hex", "num-integer", "num-traits", - "opentelemetry 0.28.0", + "opentelemetry", "opentelemetry-appender-tracing", - "opentelemetry-otlp 0.28.0", - "opentelemetry-semantic-conventions 0.28.0", - "opentelemetry_sdk 0.28.0", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", "p256", - "pkcs8 0.10.2", - "reqwest 0.12.12", + "pkcs8", + "reqwest", "rsa", "rustls", "secp256k1 0.30.0", @@ -5635,7 +4649,7 @@ dependencies = [ "serde_json", "sha2", "sha3", - "signature 2.2.0", + "signature", "tdx-attest-rs", "teepot-tee-quote-verification-rs", "testaso", @@ -5643,7 +4657,7 @@ dependencies = [ "tokio", "tracing", "tracing-futures", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", "tracing-test", "x509-cert", @@ -5661,7 +4675,7 @@ dependencies = [ "serde_json", "teepot-vault", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5681,7 +4695,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "base64 0.22.1", + "base64", "bytes", "clap 4.5.30", "const-oid", @@ -5713,7 +4727,7 @@ dependencies = [ "serde_json", "teepot-vault", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -5904,16 +4918,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.5.0" @@ -5979,7 +4983,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.24", + "toml_edit", ] [[package]] @@ -5991,17 +4995,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.7.1", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.24" @@ -6012,35 +5005,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.3", -] - -[[package]] -name = "tonic" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" -dependencies = [ - "async-trait", - "axum 0.6.20", - "base64 0.21.7", - "bytes", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-timeout 0.4.1", - "percent-encoding", - "pin-project", - "prost 0.11.9", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", + "winnow", ] [[package]] @@ -6051,19 +5016,19 @@ checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum 0.7.9", - "base64 0.22.1", + "axum", + "base64", "bytes", "h2 0.4.8", "http 1.2.0", - "http-body 1.0.1", + "http-body", "http-body-util", - "hyper 1.6.0", - "hyper-timeout 0.5.2", + "hyper", + "hyper-timeout", "hyper-util", "percent-encoding", "pin-project", - "prost 0.13.5", + "prost", "socket2", "tokio", "tokio-stream", @@ -6102,7 +5067,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -6176,17 +5141,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -6198,22 +5152,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-opentelemetry" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75327c6b667828ddc28f5e3f169036cb793c3f588d83bf0f262a7f062ffed3c8" -dependencies = [ - "once_cell", - "opentelemetry 0.20.0", - "opentelemetry_sdk 0.20.0", - "smallvec", - "tracing", - "tracing-core", - "tracing-log 0.1.4", - "tracing-subscriber", -] - [[package]] name = "tracing-serde" version = "0.2.0" @@ -6239,10 +5177,9 @@ dependencies = [ "sharded-slab", "smallvec", "thread_local", - "time", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", "tracing-serde", ] @@ -6300,15 +5237,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "uname" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" -dependencies = [ - "libc", -] - [[package]] name = "unicode-ident" version = "1.0.17" @@ -6349,19 +5277,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64 0.22.1", - "log", - "native-tls", - "once_cell", - "url", -] - [[package]] name = "url" version = "2.5.4" @@ -6374,12 +5289,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf16_iter" version = "1.0.5" @@ -6399,7 +5308,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" dependencies = [ "getrandom 0.3.1", - "serde", ] [[package]] @@ -6430,12 +5338,12 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "base64 0.22.1", + "base64", "clap 4.5.30", "serde_json", "teepot-vault", "tracing", - "tracing-log 0.2.0", + "tracing-log", "tracing-subscriber", ] @@ -6464,15 +5372,19 @@ dependencies = [ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ - "anyhow", + "bytes", "clap 4.5.30", + "enumset", "hex", - "jsonrpsee-types 0.24.8", - "reqwest 0.12.12", + "jsonrpsee-types", + "reqwest", "secp256k1 0.30.0", "serde", + "serde_json", "serde_with 3.12.0", + "serde_yaml", "teepot", + "thiserror 2.0.11", "tokio", "tracing", "tracing-subscriber", @@ -6490,36 +5402,23 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vise" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229baafe01d5177b63c6ee1def80d8e39a2365e64caf69ddb05a57594b15647c" +checksum = "90ade36f3548b1524396f4de7b36f4f210c8a01dfab568eb2bff466af64eb6e5" dependencies = [ "compile-fmt", + "ctor", "elsa", - "linkme", "once_cell", "prometheus-client", "vise-macros", ] -[[package]] -name = "vise-exporter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23981b18d697026f5430249ab01ba739ef2edc463e400042394331cb2bb63494" -dependencies = [ - "hyper 0.14.32", - "once_cell", - "tokio", - "tracing", - "vise", -] - [[package]] name = "vise-macros" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb19c33cd5f04dcf4e767635e058a998edbc2b7fca32ade0a4a1cea0f8e9b34" +checksum = "6a511871dc5de990a3b2a0e715facfbc5da848c0c0395597a1415029fb7c250a" dependencies = [ "proc-macro2", "quote", @@ -6699,7 +5598,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -6710,7 +5609,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -6719,7 +5618,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -6729,16 +5628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -6747,7 +5637,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -6756,22 +5646,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -6780,46 +5655,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -6832,63 +5689,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.3" @@ -6898,16 +5722,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wit-bindgen-rt" version = "0.33.0" @@ -6957,10 +5771,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" dependencies = [ "const-oid", - "der 0.7.9", + "der", "sha1", - "signature 2.2.0", - "spki 0.7.3", + "signature", + "spki", "tls_codec", ] @@ -7084,64 +5898,23 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "zk_evm" -version = "0.133.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af08e9284686a1b0c89ec4931eb915ac0729367f1247abd06164874fe738106" -dependencies = [ - "anyhow", - "lazy_static", - "num", - "serde", - "serde_json", - "static_assertions", - "zk_evm_abstractions", - "zkevm_opcode_defs", -] - -[[package]] -name = "zk_evm_abstractions" -version = "0.140.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be696258861eba4e6625a5665084b2266720bb67f4ba69819469700ac5c6a401" -dependencies = [ - "anyhow", - "num_enum 0.6.1", - "serde", - "static_assertions", - "zkevm_opcode_defs", -] - -[[package]] -name = "zkevm_opcode_defs" -version = "0.132.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0769f7b27d8fb06e715da3290c575cac5d04d10a557faef180e847afce50ac4" -dependencies = [ - "bitflags 2.8.0", - "blake2", - "ethereum-types", - "k256 0.11.6", - "lazy_static", - "sha2_ce", - "sha3_ce", -] - [[package]] name = "zksync_basic_types" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4e4a41a89d72763b860245ea3a323ac0f6b7b9289a07b481f47168f2973171" +checksum = "2d7c1c35e9886151899e0636967b60f65b3bccd18f1e3ba71a98859e9d53bfab" dependencies = [ "anyhow", "chrono", + "const-decoder", "ethabi", "hex", - "num_enum 0.7.3", + "num_enum", + "secrecy", "serde", "serde_json", "serde_with 1.14.0", + "sha2", "strum", "thiserror 1.0.69", "tiny-keccak", @@ -7150,9 +5923,9 @@ dependencies = [ [[package]] name = "zksync_concurrency" -version = "0.1.0-rc.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1af85d9a31c534a29877c88474cf5f1c46ad25f7c48efff61ea40f4aa83c5459" +checksum = "cec98400a9e8ba02bfd029eacfe7d6fb7b85b8ef00de59d6bb119d29cc9f7442" dependencies = [ "anyhow", "once_cell", @@ -7169,15 +5942,14 @@ dependencies = [ [[package]] name = "zksync_config" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "663261a7c6064c6d52eafa254057b0d96493280ef28f5fb14efe90faa73aff25" +checksum = "91cf4af6d7e83c9ed0422a36c603b8bf84079ab510d295fda74f95ce49f62388" dependencies = [ "anyhow", "rand", "secrecy", "serde", - "url", "zksync_basic_types", "zksync_concurrency", "zksync_consensus_utils", @@ -7186,9 +5958,9 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" -version = "0.1.0-rc.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "587de103f745d0b88b49a9fb98cb002c4b7ce6ad042e17845091dce67b8aa984" +checksum = "f2f9fa69ef68e6a1955a1d7b33077103fb6d106b560fec0d599c6de268f5be03" dependencies = [ "anyhow", "rand", @@ -7198,24 +5970,24 @@ dependencies = [ [[package]] name = "zksync_contracts" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "facdc0d63d452d1a7992e0dae773d6f73e4c2a5fda29c2b5119b8ee2be71d98a" +checksum = "48199dbf89c06eb242ba1c5f1d8d66dbefb1a8b6c41f08201b084cd56b08ceb5" dependencies = [ "envy", - "ethabi", "hex", "once_cell", "serde", "serde_json", + "zksync_basic_types", "zksync_utils", ] [[package]] name = "zksync_crypto_primitives" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cf6a098fa3e479285f8bad8d4f9ef4852bbd13e2d5f7c8e652ce6c50899453" +checksum = "cd63cde705950e4dd9d1f5b3a532d2d8304e7af27efd197bd67c15f4d0954ab7" dependencies = [ "anyhow", "blake2", @@ -7227,155 +5999,85 @@ dependencies = [ "sha2", "thiserror 1.0.69", "zksync_basic_types", - "zksync_utils", +] + +[[package]] +name = "zksync_da_client" +version = "27.0.0-non-semver-compat" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8889a7e5d7f003424cd476b28f4a8e8632aee6371209a84dc301df1f646405" +dependencies = [ + "anyhow", + "async-trait", + "serde", ] [[package]] name = "zksync_mini_merkle_tree" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b34e4e287bc40bf7f6c3ef9bb075401755614b27c64bdf67ac243658ee607b" +checksum = "0816cec4ccc46ca86e9f31507e3112e6036a99aa29e38b4f13d2fe70da14efc4" dependencies = [ "once_cell", "zksync_basic_types", "zksync_crypto_primitives", ] -[[package]] -name = "zksync_protobuf" -version = "0.1.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86baa84d8bbbbeea269c0f99aca88364e4fd2a08e6ae7051ff87317132b4ef9" -dependencies = [ - "anyhow", - "bit-vec", - "once_cell", - "prost 0.12.6", - "prost-reflect", - "quick-protobuf", - "rand", - "serde", - "serde_json", - "serde_yaml", - "zksync_concurrency", - "zksync_consensus_utils", - "zksync_protobuf_build", -] - -[[package]] -name = "zksync_protobuf_build" -version = "0.1.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f221ce83f4622c3d8732d09f4461d116d7b10f1cc9d1d1cd014c1fa836c168e6" -dependencies = [ - "anyhow", - "heck 0.5.0", - "prettyplease", - "proc-macro2", - "prost-build", - "prost-reflect", - "protox", - "quote", - "syn 2.0.98", -] - [[package]] name = "zksync_system_constants" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b9f2537f81bddfb67af6e6ae3f1df216e552e89170edd0ed8aa0e0e58fb9d" +checksum = "b5f8e8c2887e282651cc354affe217b749b0c3a31200bdf8c597a9a467056255" dependencies = [ "once_cell", "zksync_basic_types", - "zksync_utils", ] [[package]] name = "zksync_types" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463b6b22f788347b746b276b1f4420173e5570d533d5fd10a5d1e9ca1d01c1f3" +checksum = "edf281daa468c05be17029d42693b6e1f0ad946f44ff44bc448d377f18d45b15" dependencies = [ "anyhow", - "bigdecimal", + "async-trait", "blake2", "chrono", - "derive_more 1.0.0-beta.6", + "derive_more 1.0.0", "hex", - "itertools 0.10.5", - "num", - "num_enum 0.7.3", + "num_enum", "once_cell", - "prost 0.12.6", "rlp", - "secp256k1 0.27.0", "serde", "serde_json", - "strum", + "serde_with 1.14.0", "thiserror 1.0.69", "tracing", "zksync_basic_types", - "zksync_config", "zksync_contracts", "zksync_crypto_primitives", + "zksync_da_client", "zksync_mini_merkle_tree", - "zksync_protobuf", - "zksync_protobuf_build", "zksync_system_constants", - "zksync_utils", ] [[package]] name = "zksync_utils" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2046c95fbcca2789cdfd133a4111197739b45504d887f9ff17e4e8706bcaabaf" +checksum = "858ae870fc2b2b6af07de7cbb3e9b09418774d42d25d380dd0bfc01009767258" dependencies = [ "anyhow", - "bigdecimal", - "futures", - "hex", - "itertools 0.10.5", - "num", "once_cell", - "reqwest 0.12.12", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tracing", - "zk_evm", - "zksync_basic_types", - "zksync_vlog", -] - -[[package]] -name = "zksync_vlog" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff02e5df2e986592b916077f210b28a35e63d947936f99431041ad79289306e8" -dependencies = [ - "anyhow", - "chrono", - "opentelemetry 0.20.0", - "opentelemetry-otlp 0.13.0", - "opentelemetry-semantic-conventions 0.12.0", - "sentry", - "serde", "serde_json", "tokio", - "tracing", - "tracing-opentelemetry", - "tracing-subscriber", - "vise", - "vise-exporter", ] [[package]] name = "zksync_web3_decl" -version = "0.1.0" +version = "27.0.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a6342270ad3220b287b01675875c450c365e4a4495c84a2f2376e7f18f973f" +checksum = "b938259cc07b01c56a54d6ec24939cda621c39f0a4d7c294daa883e95445d0aa" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 717d8b0..508f166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ gpt = "4.0.0" 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.3.0" } intel-tee-quote-verification-sys = { version = "0.2.1" } -jsonrpsee-types = { version = "0.24", default-features = false } num-integer = "0.1.46" num-traits = "0.2.18" opentelemetry = { version = "0.28.0", features = ["default", "logs"] } diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index a818dbd..533a3dc 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -8,19 +8,23 @@ repository.workspace = true version.workspace = true [dependencies] -anyhow.workspace = true +bytes.workspace = true clap.workspace = true +enumset.workspace = true hex.workspace = true -jsonrpsee-types.workspace = true +jsonrpsee-types = "0.24" reqwest.workspace = true secp256k1.workspace = true serde.workspace = true +serde_json.workspace = true serde_with = { workspace = true, features = ["hex"] } +serde_yaml = "0.9.33" teepot.workspace = true +thiserror.workspace = true tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true url.workspace = true -zksync_basic_types = "=0.1.0" -zksync_types = "=0.1.0" -zksync_web3_decl = "=0.1.0" +zksync_basic_types = "27.0.0-non-semver-compat" +zksync_types = "27.0.0-non-semver-compat" +zksync_web3_decl = "27.0.0-non-semver-compat" diff --git a/bin/verify-era-proof-attestation/README.md b/bin/verify-era-proof-attestation/README.md new file mode 100644 index 0000000..00e6728 --- /dev/null +++ b/bin/verify-era-proof-attestation/README.md @@ -0,0 +1,76 @@ +# Era Proof Attestation Verifier + +This tool verifies the SGX/TDX attestations and signatures for zkSync Era L1 batches. + +## Usage + +Basic usage with attestation policy provided from a YAML file: + +```bash +verify-era-proof-attestation --rpc https://mainnet.era.zksync.io \ + --continuous 493220 \ + --attestation-policy-file examples/attestation_policy.yaml \ + --log-level info +``` + +## Attestation Policy Configuration + +You can specify the attestation policy either through command-line arguments or by providing a YAML configuration file. + +### Command-line Arguments + +The following command-line arguments are available: + +- `--batch`, `-n `: The batch number or range of batch numbers to verify the attestation and signature (e.g., " + 42" or "42-45"). Mutually exclusive with `--continuous`. +- `--continuous `: Continuous mode: keep verifying new batches starting from the specified batch number + until interrupted. Mutually exclusive with `--batch`. +- `--rpc `: URL of the RPC server to query for the batch attestation and signature. +- `--chain `: Chain ID of the network to query (default: L2ChainId::default()). +- `--rate-limit `: Rate limit between requests in milliseconds (default: 0). +- `--log-level `: Log level for the log output. Valid values are: `off`, `error`, `warn`, `info`, `debug`, + `trace` (default: `warn`). +- `--attestation-policy-file `: Path to a YAML file containing attestation policy configuration. This overrides + any attestation policy settings provided via command line options. + +Either `--batch` or `--continuous` mode must be specified. + +### YAML Configuration File + +The attestation policy is loaded from a YAML file using the `--attestation-policy-file` option. + +Example YAML configuration file: + +```yaml +sgx: + mrenclaves: + - a2caa7055e333f69c3e46ca7ba65b135a86c90adfde2afb356e05075b7818b3c + - 36eeb64cc816f80a1cf5818b26710f360714b987d3799e757cbefba7697b9589 + - 4a8b79e5123f4dbf23453d583cb8e5dcf4d19a6191a0be6dd85b7b3052c32faf + - 1498845b3f23667356cc49c38cae7b4ac234621a5b85fdd5c52b5f5d12703ec9 + - 1b2374631bb2572a0e05b3be8b5cdd23c42e9d7551e1ef200351cae67c515a65 + - 6fb19e47d72a381a9f3235c450f8c40f01428ce19a941f689389be3eac24f42a + - b610fd1d749775cc3de88beb84afe8bb79f55a19100db12d76f6a62ac576e35d + - a0b1b069b01bdcf3c1517ef8d4543794a27ed4103e464be7c4afdc6136b42d66 + - 71e2a11a74b705082a7286b2008f812f340c0e4de19f8b151baa347eda32d057 + - d5a0bf8932d9a3d7af6d9405d4c6de7dcb7b720bb5510666b4396fc58ee58bb2 + allowed_tcb_levels: + - Ok + - SwHardeningNeeded + allowed_advisory_ids: + - INTEL-SA-00615 +tdx: + mrs: + - - 2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525 + - 3300980705adf09d28b707b79699d9874892164280832be2c386a715b6e204e0897fb564a064f810659207ba862b304f + - c08ab64725566bcc8a6fb1c79e2e64744fcff1594b8f1f02d716fb66592ecd5de94933b2bc54ffbbc43a52aab7eb1146 + - 092a4866a9e6a1672d7439a5d106fbc6eb57b738d5bfea5276d41afa2551824365fdd66700c1ce9c0b20542b9f9d5945 + - 971fb52f90ec98a234301ca9b8fc30b613c33e3dd9c0cc42dcb8003d4a95d8fb218b75baf028b70a3cabcb947e1ca453 + - - 2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525 + - 3300980705adf09d28b707b79699d9874892164280832be2c386a715b6e204e0897fb564a064f810659207ba862b304f + - c08ab64725566bcc8a6fb1c79e2e64744fcff1594b8f1f02d716fb66592ecd5de94933b2bc54ffbbc43a52aab7eb1146 + - 092a4866a9e6a1672d7439a5d106fbc6eb57b738d5bfea5276d41afa2551824365fdd66700c1ce9c0b20542b9f9d5945 + - f57bb7ed82c6ae4a29e6c9879338c592c7d42a39135583e8ccbe3940f2344b0eb6eb8503db0ffd6a39ddd00cd07d8317 + allowed_tcb_levels: + - Ok +``` diff --git a/bin/verify-era-proof-attestation/examples/attestation_policy.yaml b/bin/verify-era-proof-attestation/examples/attestation_policy.yaml new file mode 100644 index 0000000..cfb6a34 --- /dev/null +++ b/bin/verify-era-proof-attestation/examples/attestation_policy.yaml @@ -0,0 +1,31 @@ +sgx: + mrenclaves: + - a2caa7055e333f69c3e46ca7ba65b135a86c90adfde2afb356e05075b7818b3c + - 36eeb64cc816f80a1cf5818b26710f360714b987d3799e757cbefba7697b9589 + - 4a8b79e5123f4dbf23453d583cb8e5dcf4d19a6191a0be6dd85b7b3052c32faf + - 1498845b3f23667356cc49c38cae7b4ac234621a5b85fdd5c52b5f5d12703ec9 + - 1b2374631bb2572a0e05b3be8b5cdd23c42e9d7551e1ef200351cae67c515a65 + - 6fb19e47d72a381a9f3235c450f8c40f01428ce19a941f689389be3eac24f42a + - b610fd1d749775cc3de88beb84afe8bb79f55a19100db12d76f6a62ac576e35d + - a0b1b069b01bdcf3c1517ef8d4543794a27ed4103e464be7c4afdc6136b42d66 + - 71e2a11a74b705082a7286b2008f812f340c0e4de19f8b151baa347eda32d057 + - d5a0bf8932d9a3d7af6d9405d4c6de7dcb7b720bb5510666b4396fc58ee58bb2 + allowed_tcb_levels: + - Ok + - SwHardeningNeeded + allowed_advisory_ids: + - INTEL-SA-00615 +tdx: + mrs: + - - 2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525 + - 3300980705adf09d28b707b79699d9874892164280832be2c386a715b6e204e0897fb564a064f810659207ba862b304f + - c08ab64725566bcc8a6fb1c79e2e64744fcff1594b8f1f02d716fb66592ecd5de94933b2bc54ffbbc43a52aab7eb1146 + - 092a4866a9e6a1672d7439a5d106fbc6eb57b738d5bfea5276d41afa2551824365fdd66700c1ce9c0b20542b9f9d5945 + - 971fb52f90ec98a234301ca9b8fc30b613c33e3dd9c0cc42dcb8003d4a95d8fb218b75baf028b70a3cabcb947e1ca453 + - - 2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525 + - 3300980705adf09d28b707b79699d9874892164280832be2c386a715b6e204e0897fb564a064f810659207ba862b304f + - c08ab64725566bcc8a6fb1c79e2e64744fcff1594b8f1f02d716fb66592ecd5de94933b2bc54ffbbc43a52aab7eb1146 + - 092a4866a9e6a1672d7439a5d106fbc6eb57b738d5bfea5276d41afa2551824365fdd66700c1ce9c0b20542b9f9d5945 + - f57bb7ed82c6ae4a29e6c9879338c592c7d42a39135583e8ccbe3940f2344b0eb6eb8503db0ffd6a39ddd00cd07d8317 + allowed_tcb_levels: + - Ok diff --git a/bin/verify-era-proof-attestation/src/args.rs b/bin/verify-era-proof-attestation/src/args.rs deleted file mode 100644 index cea2a1c..0000000 --- a/bin/verify-era-proof-attestation/src/args.rs +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs - -use anyhow::{anyhow, Result}; -use clap::{ArgGroup, Args, Parser}; -use std::time::Duration; -use teepot::log::LogLevelParser; -use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; -use tracing_subscriber::filter::LevelFilter; -use url::Url; -use zksync_basic_types::L1BatchNumber; -use zksync_types::L2ChainId; - -#[derive(Parser, Debug, Clone)] -#[command(author = "Matter Labs", version, about = "SGX attestation and batch signature verifier", long_about = None)] -#[clap(group( - ArgGroup::new("mode") - .required(true) - .args(&["batch_range", "continuous"]), -))] -pub struct Arguments { - /// Log level for the log output. - /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` - #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] - pub log_level: LevelFilter, - /// The batch number or range of batch numbers to verify the attestation and signature (e.g., - /// "42" or "42-45"). This option is mutually exclusive with the `--continuous` mode. - #[clap(short = 'n', long = "batch", value_parser = parse_batch_range)] - pub batch_range: Option<(L1BatchNumber, L1BatchNumber)>, - /// Continuous mode: keep verifying new batches until interrupted. This option is mutually - /// exclusive with the `--batch` option. - #[clap(long, value_name = "FIRST_BATCH")] - pub continuous: Option, - /// URL of the RPC server to query for the batch attestation and signature. - #[clap(long = "rpc")] - pub rpc_url: Url, - /// Chain ID of the network to query. - #[clap(long = "chain", default_value_t = L2ChainId::default().as_u64())] - pub chain_id: u64, - /// Rate limit between requests in milliseconds. - #[clap(long, default_value = "0", value_parser = parse_duration)] - pub rate_limit: Duration, - /// Criteria for valid attestation policy. Invalid proofs will be rejected. - #[clap(flatten)] - pub attestation_policy: AttestationPolicyArgs, -} - -/// Attestation policy implemented as a set of criteria that must be met by SGX attestation. -#[derive(Args, Debug, Clone)] -pub struct AttestationPolicyArgs { - /// Comma-separated list of allowed hex-encoded SGX mrsigners. Batch attestation must consist of - /// one of these mrsigners. If the list is empty, the mrsigner check is skipped. - #[arg(long = "mrsigners")] - pub sgx_mrsigners: Option, - /// Comma-separated list of allowed hex-encoded SGX mrenclaves. Batch attestation must consist - /// of one of these mrenclaves. If the list is empty, the mrenclave check is skipped. - #[arg(long = "mrenclaves")] - pub sgx_mrenclaves: Option, - /// Comma-separated list of allowed TCB levels. If the list is empty, the TCB level check is - /// skipped. Allowed values: Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, - /// OutOfDate, OutOfDateConfigNeeded. - #[arg(long, value_parser = parse_tcb_levels, default_value = "Ok")] - pub sgx_allowed_tcb_levels: EnumSet, -} - -fn parse_batch_range(s: &str) -> Result<(L1BatchNumber, L1BatchNumber)> { - let parse = |s: &str| { - s.parse::() - .map(L1BatchNumber::from) - .map_err(|e| anyhow!(e)) - }; - match s.split_once('-') { - Some((start, end)) => { - let (start, end) = (parse(start)?, parse(end)?); - if start > end { - Err(anyhow!( - "Start batch number ({}) must be less than or equal to end batch number ({})", - start, - end - )) - } else { - Ok((start, end)) - } - } - None => { - let batch_number = parse(s)?; - Ok((batch_number, batch_number)) - } - } -} - -fn parse_duration(s: &str) -> Result { - let millis = s.parse()?; - Ok(Duration::from_millis(millis)) -} diff --git a/bin/verify-era-proof-attestation/src/client.rs b/bin/verify-era-proof-attestation/src/client.rs deleted file mode 100644 index 6746e38..0000000 --- a/bin/verify-era-proof-attestation/src/client.rs +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs - -use anyhow::{anyhow, Context, Result}; -use url::Url; -use zksync_basic_types::{L1BatchNumber, H256}; -use zksync_types::L2ChainId; -use zksync_web3_decl::{ - client::{Client as NodeClient, L2}, - error::ClientRpcContext, - namespaces::ZksNamespaceClient, -}; - -pub trait JsonRpcClient { - async fn get_root_hash(&self, batch_number: L1BatchNumber) -> Result; - // TODO implement get_tee_proofs(batch_number, tee_type) once https://crates.io/crates/zksync_web3_decl crate is updated -} - -pub struct MainNodeClient(NodeClient); - -impl MainNodeClient { - pub fn new(rpc_url: Url, chain_id: u64) -> Result { - let node_client = NodeClient::http(rpc_url.into()) - .context("failed creating JSON-RPC client for main node")? - .for_network( - L2ChainId::try_from(chain_id) - .map_err(anyhow::Error::msg)? - .into(), - ) - .build(); - - Ok(MainNodeClient(node_client)) - } -} - -impl JsonRpcClient for MainNodeClient { - async fn get_root_hash(&self, batch_number: L1BatchNumber) -> Result { - self.0 - .get_l1_batch_details(batch_number) - .rpc_context("get_l1_batch_details") - .await? - .and_then(|res| res.base.root_hash) - .ok_or_else(|| anyhow!("No root hash found for batch #{}", batch_number)) - } -} diff --git a/bin/verify-era-proof-attestation/src/client/http.rs b/bin/verify-era-proof-attestation/src/client/http.rs new file mode 100644 index 0000000..c23b9c7 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/client/http.rs @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! HTTP client for making requests to external services + +use reqwest::Client; +use serde::{de::DeserializeOwned, Serialize}; +use std::time::Duration; +use url::Url; + +use crate::{ + core::DEFAULT_HTTP_REQUEST_TIMEOUT, + error::{Error, Result}, +}; + +/// Client for making HTTP requests +#[derive(Clone)] +pub struct HttpClient { + client: Client, +} + +impl HttpClient { + /// Create a new HTTP client with default configuration + pub fn new() -> Self { + let client = Client::builder() + .timeout(Duration::from_secs(DEFAULT_HTTP_REQUEST_TIMEOUT)) + .build() + .expect("Failed to create HTTP client"); + + Self { client } + } + + /// Make a POST request to the specified URL with the provided body + pub async fn post(&self, url: &Url, body: T) -> Result { + let response = self.client.post(url.clone()).json(&body).send().await?; + self.handle_response(response).await + } + + /// Send a JSON request and parse the response + pub async fn send_json( + &self, + url: &Url, + body: T, + ) -> Result { + let response_text = self.post(url, body).await?; + let response: R = serde_json::from_str(&response_text) + .map_err(|e| Error::JsonRpcInvalidResponse(e.to_string()))?; + + Ok(response) + } + + /// Handle the HTTP response + async fn handle_response(&self, response: reqwest::Response) -> Result { + let status = response.status(); + let body = response.text().await?; + + if status.is_success() { + Ok(body) + } else { + Err(Error::Http { + status_code: status.as_u16(), + message: body, + }) + } + } +} diff --git a/bin/verify-era-proof-attestation/src/client/json_rpc.rs b/bin/verify-era-proof-attestation/src/client/json_rpc.rs new file mode 100644 index 0000000..a9417ff --- /dev/null +++ b/bin/verify-era-proof-attestation/src/client/json_rpc.rs @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use url::Url; +use zksync_basic_types::{L1BatchNumber, H256}; +use zksync_types::L2ChainId; +use zksync_web3_decl::{ + client::{Client as NodeClient, L2}, + error::ClientRpcContext, + namespaces::ZksNamespaceClient, +}; + +use crate::error; + +/// Trait for interacting with the JSON-RPC API +pub trait JsonRpcClient { + /// Get the root hash for a specific batch + async fn get_root_hash(&self, batch_number: L1BatchNumber) -> error::Result; + // TODO implement get_tee_proofs(batch_number, tee_type) once https://crates.io/crates/zksync_web3_decl crate is updated +} + +/// Client for interacting with the main node +pub struct MainNodeClient(NodeClient); + +impl MainNodeClient { + /// Create a new client for the main node + pub fn new(rpc_url: Url, chain_id: u64) -> error::Result { + let chain_id = L2ChainId::try_from(chain_id) + .map_err(|e| error::Error::Internal(format!("Invalid chain ID: {}", e)))?; + + let node_client = NodeClient::http(rpc_url.into()) + .map_err(|e| { + error::Error::Internal(format!("Failed to create JSON-RPC client: {}", e)) + })? + .for_network(chain_id.into()) + .build(); + + Ok(MainNodeClient(node_client)) + } +} + +impl JsonRpcClient for MainNodeClient { + async fn get_root_hash(&self, batch_number: L1BatchNumber) -> error::Result { + let batch_details = self + .0 + .get_l1_batch_details(batch_number) + .rpc_context("get_l1_batch_details") + .await + .map_err(|e| error::Error::JsonRpc(format!("Failed to get batch details: {}", e)))? + .ok_or_else(|| { + error::Error::JsonRpc(format!("No details found for batch #{}", batch_number)) + })?; + + batch_details.base.root_hash.ok_or_else(|| { + error::Error::JsonRpc(format!("No root hash found for batch #{}", batch_number)) + }) + } +} diff --git a/bin/verify-era-proof-attestation/src/client/mod.rs b/bin/verify-era-proof-attestation/src/client/mod.rs new file mode 100644 index 0000000..3c070e6 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/client/mod.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Client modules for external API communication + +mod http; +mod json_rpc; +mod retry; + +pub use http::HttpClient; +pub use json_rpc::{JsonRpcClient, MainNodeClient}; +pub use retry::{RetryConfig, RetryHelper}; diff --git a/bin/verify-era-proof-attestation/src/client/retry.rs b/bin/verify-era-proof-attestation/src/client/retry.rs new file mode 100644 index 0000000..12c7855 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/client/retry.rs @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Retry mechanism for handling transient failures + +use std::time::Duration; +use tokio::time::sleep; + +use crate::{ + core::{DEFAULT_RETRY_DELAY_MS, MAX_PROOF_FETCH_RETRIES}, + error::{Error, Result}, +}; + +/// Configuration for retry behavior +#[derive(Debug, Clone)] +pub struct RetryConfig { + /// Maximum number of retry attempts + pub max_attempts: u32, + /// Delay between retry attempts + pub delay: Duration, + /// Whether to use exponential backoff + pub use_exponential_backoff: bool, +} + +impl Default for RetryConfig { + fn default() -> Self { + Self { + max_attempts: MAX_PROOF_FETCH_RETRIES, + delay: Duration::from_millis(DEFAULT_RETRY_DELAY_MS), + use_exponential_backoff: true, + } + } +} + +/// Helper for executing operations with retries +pub struct RetryHelper { + config: RetryConfig, +} + +impl RetryHelper { + /// Create a new retry helper with the given configuration + pub fn new(config: RetryConfig) -> Self { + Self { config } + } + + /// Execute an operation with retries + pub async fn execute(&self, operation_name: &str, operation: F) -> Result + where + F: Fn() -> Fut, + Fut: std::future::Future>, + { + let mut attempt = 0; + let mut last_error; + + loop { + attempt += 1; + tracing::debug!( + "Executing operation '{}' (attempt {}/{})", + operation_name, + attempt, + self.config.max_attempts + ); + + match operation().await { + Ok(result) => { + tracing::debug!( + "Operation '{}' succeeded on attempt {}", + operation_name, + attempt + ); + return Ok(result); + } + Err(Error::Interrupted) => return Err(Error::Interrupted), + Err(e) => { + last_error = e; + + if attempt >= self.config.max_attempts { + tracing::warn!( + "Operation '{}' failed after {} attempts. Giving up.", + operation_name, + attempt + ); + break; + } + + let delay = if self.config.use_exponential_backoff { + self.config.delay.mul_f32(2.0_f32.powi(attempt as i32 - 1)) + } else { + self.config.delay + }; + + tracing::warn!( + "Operation '{}' failed on attempt {}: {}. Retrying in {:?}...", + operation_name, + attempt, + last_error, + delay + ); + + sleep(delay).await; + } + } + } + + Err(last_error) + } +} diff --git a/bin/verify-era-proof-attestation/src/core/config.rs b/bin/verify-era-proof-attestation/src/core/config.rs new file mode 100644 index 0000000..8132ddc --- /dev/null +++ b/bin/verify-era-proof-attestation/src/core/config.rs @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Configuration settings for the verification process + +use crate::{ + core::{SGX_HASH_SIZE, TDX_HASH_SIZE}, + error, +}; +use bytes::{Bytes, BytesMut}; +use clap::{ArgGroup, Parser}; +use enumset::EnumSet; +use serde::{Deserialize, Serialize}; +use std::{collections::HashSet, fs, ops::Deref, path::PathBuf, str::FromStr, time::Duration}; +use teepot::{log::LogLevelParser, quote::tcblevel::TcbLevel}; +use tracing_subscriber::filter::LevelFilter; +use url::Url; +use zksync_basic_types::{tee_types::TeeType, L1BatchNumber}; +use zksync_types::L2ChainId; + +/// Primary configuration for the verification process +#[derive(Parser, Debug, Clone)] +#[command(author = "Matter Labs", version, about = "SGX attestation and batch signature verifier", long_about = None +)] +#[clap(group( + ArgGroup::new("mode") + .required(true) + .args(&["batch_range", "continuous"]), +))] +pub struct VerifierConfigArgs { + /// Log level for the log output. + /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` + #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] + pub log_level: LevelFilter, + + /// The batch number or range of batch numbers to verify the attestation and signature (e.g., + /// "42" or "42-45"). This option is mutually exclusive with the `--continuous` mode. + #[clap(short = 'n', long = "batch", value_parser = parse_batch_range)] + pub batch_range: Option<(L1BatchNumber, L1BatchNumber)>, + + /// Continuous mode: keep verifying new batches until interrupted. This option is mutually + /// exclusive with the `--batch` option. + #[clap(long, value_name = "FIRST_BATCH")] + pub continuous: Option, + + /// URL of the RPC server to query for the batch attestation and signature. + #[clap(long = "rpc")] + pub rpc_url: Url, + + /// Chain ID of the network to query. + #[clap(long = "chain", default_value_t = L2ChainId::default().as_u64())] + pub chain_id: u64, + + /// Rate limit between requests in milliseconds. + #[clap(long, default_value = "0", value_parser = parse_duration)] + pub rate_limit: Duration, + + /// Path to a YAML file containing attestation policy configuration. + /// This overrides any attestation policy settings provided via command line options. + #[clap(long = "attestation-policy-file")] + pub attestation_policy_file: Option, + + /// Comma separated list of Tee types to process + #[clap(long)] + pub tee_types: TeeTypes, +} + +/// Attestation policy implemented as a set of criteria that must be met by SGX attestation. +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct SgxAttestationPolicyConfig { + /// List of allowed hex-encoded SGX mrsigners. Batch attestation must consist of + /// one of these mrsigners. If the list is empty, the mrsigner check is skipped. + #[serde(default)] + pub mrsigners: Option>, + + /// List of allowed hex-encoded SGX mrenclaves. Batch attestation must consist + /// of one of these mrenclaves. If the list is empty, the mrenclave check is skipped. + #[serde(default)] + pub mrenclaves: Option>, + + /// List of allowed SGX TCB levels. If the list is empty, the TCB level check is + /// skipped. Allowed values: Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, + /// OutOfDate, OutOfDateConfigNeeded. + #[serde(default = "default_tcb_levels")] + pub allowed_tcb_levels: EnumSet, + + /// List of allowed SGX Advisories. If the list is empty, theAdvisories check is skipped. + #[serde(default)] + pub allowed_advisory_ids: Option>, +} + +/// Attestation policy implemented as a set of criteria that must be met by TDX attestation. +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct TdxAttestationPolicyConfig { + /// List of allowed hex-encoded TDX mrs. Batch attestation must consist + /// of one of these mrs. If the list is empty, the mrs check is skipped. + #[serde(default)] + pub mrs: Option>, + + /// List of allowed SGX TCB levels. If the list is empty, the TCB level check is + /// skipped. Allowed values: Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, + /// OutOfDate, OutOfDateConfigNeeded. + #[serde(default = "default_tcb_levels")] + pub allowed_tcb_levels: EnumSet, + + /// List of allowed TDX Advisories. If the list is empty, theAdvisories check is skipped. + #[serde(default)] + pub allowed_advisory_ids: Option>, +} + +/// Attestation policy implemented as a set of criteria that must be met by SGX or TDX attestation. +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct AttestationPolicyConfig { + /// SGX attestation policy + pub sgx: SgxAttestationPolicyConfig, + /// TDX attestation policy + pub tdx: TdxAttestationPolicyConfig, +} + +#[derive(Debug, Clone)] +pub struct AttestationPolicy { + pub sgx_mrsigners: Option>, + pub sgx_mrenclaves: Option>, + pub sgx_allowed_tcb_levels: EnumSet, + pub sgx_allowed_advisory_ids: Option>, + pub tdx_allowed_tcb_levels: EnumSet, + pub tdx_mrs: Option>, + pub tdx_allowed_advisory_ids: Option>, +} + +/// Default TCB levels used for Serde deserialization +fn default_tcb_levels() -> EnumSet { + let mut set = EnumSet::new(); + set.insert(TcbLevel::Ok); + set +} + +// TODO: +// When moving this binary to the `zksync-era` repo, we +// should be using `EnumSet` but this requires +// #[derive(EnumSetType, Debug, Serialize, Deserialize)] +// #[enumset(serialize_repr = "list")] +// for `TeeType` +#[derive(Clone, Debug)] +pub struct TeeTypes(HashSet); + +impl FromStr for TeeTypes { + type Err = error::Error; + + fn from_str(s: &str) -> Result { + let mut hs = HashSet::new(); + let tee_strs: Vec<&str> = s.split(',').collect(); + for tee_str in tee_strs { + match tee_str.to_ascii_lowercase().as_str() { + "sgx" => { + hs.insert(TeeType::Sgx); + } + "tdx" => { + hs.insert(TeeType::Tdx); + } + _ => { + return Err(error::Error::internal("Unknown TEE type")); + } + } + } + Ok(Self(hs)) + } +} +impl Default for TeeTypes { + fn default() -> Self { + Self(HashSet::from([TeeType::Sgx, TeeType::Tdx])) + } +} + +impl Deref for TeeTypes { + type Target = HashSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Debug, Clone)] +pub struct VerifierConfig { + pub args: VerifierConfigArgs, + pub policy: AttestationPolicy, +} + +impl VerifierConfig { + pub fn new(args: VerifierConfigArgs) -> error::Result { + let policy = if let Some(path) = &args.attestation_policy_file { + let policy_content = fs::read_to_string(path).map_err(|e| { + error::Error::internal(format!("Failed to read attestation policy file: {}", e)) + })?; + + let policy_config: AttestationPolicyConfig = serde_yaml::from_str(&policy_content) + .map_err(|e| { + error::Error::internal(format!( + "Failed to parse attestation policy file: {}", + e + )) + })?; + + tracing::info!("Loaded attestation policy from file: {:?}", path); + policy_config + } else { + AttestationPolicyConfig::default() + }; + + let policy = AttestationPolicy { + sgx_mrsigners: decode_hex_vec_option(policy.sgx.mrsigners, SGX_HASH_SIZE)?, + sgx_mrenclaves: decode_hex_vec_option(policy.sgx.mrenclaves, SGX_HASH_SIZE)?, + sgx_allowed_tcb_levels: policy.sgx.allowed_tcb_levels, + sgx_allowed_advisory_ids: policy.sgx.allowed_advisory_ids, + tdx_allowed_tcb_levels: policy.tdx.allowed_tcb_levels, + tdx_mrs: decode_tdx_mrs(policy.tdx.mrs, TDX_HASH_SIZE)?, + tdx_allowed_advisory_ids: policy.tdx.allowed_advisory_ids, + }; + + if policy.sgx_mrsigners.is_none() && policy.sgx_mrenclaves.is_none() { + tracing::error!( + "Neither `--sgx-mrenclaves` nor `--sgx-mrsigners` specified. Any code could have produced the SGX proof." + ); + } + + if policy.tdx_mrs.is_none() { + tracing::error!( + "`--tdxmrs` not specified. Any code could have produced the TDX proof." + ); + } + + Ok(Self { args, policy }) + } +} + +// Helper function to decode a vector of hex strings +fn decode_hex_vec_option( + hex_strings: Option>, + bytes_length: usize, +) -> Result>, hex::FromHexError> { + hex_strings + .map(|strings| { + strings + .into_iter() + .map(|s| { + if s.len() > (bytes_length * 2) { + return Err(hex::FromHexError::InvalidStringLength); + } + hex::decode(s).map(Bytes::from) + }) + .collect::, _>>() + }) + .transpose() +} + +// Improved decode_tdx_mrs function +fn decode_tdx_mrs( + tdx_mrs_opt: Option>, + bytes_length: usize, +) -> Result>, hex::FromHexError> { + match tdx_mrs_opt { + None => Ok(None), + Some(mrs_array) => { + let result = mrs_array + .into_iter() + .map(|strings| decode_and_combine_mrs(strings, bytes_length)) + .collect::, _>>()?; + Ok(Some(result)) + } + } +} + +// Helper function to decode and combine MRs +fn decode_and_combine_mrs( + strings: [String; 5], + bytes_length: usize, +) -> Result { + let mut buffer = BytesMut::with_capacity(bytes_length * 5); + + for s in &strings { + if s.len() > (bytes_length * 2) { + return Err(hex::FromHexError::InvalidStringLength); + } + let decoded = hex::decode(s)?; + buffer.extend(decoded); + } + + Ok(buffer.freeze()) +} + +/// Parse a batch range from a string like "42" or "42-45" +fn parse_batch_range(s: &str) -> error::Result<(L1BatchNumber, L1BatchNumber)> { + let parse = |s: &str| { + s.parse::() + .map(L1BatchNumber::from) + .map_err(|e| error::Error::internal(format!("Can't convert batch {s} to number: {e}"))) + }; + match s.split_once('-') { + Some((start, end)) => { + let (start, end) = (parse(start)?, parse(end)?); + if start > end { + Err(error::Error::InvalidBatchRange(s.into())) + } else { + Ok((start, end)) + } + } + None => { + let batch_number = parse(s)?; + Ok((batch_number, batch_number)) + } + } +} + +/// Parse a duration from a millisecond string +fn parse_duration(s: &str) -> error::Result { + let millis = s + .parse() + .map_err(|e| error::Error::internal(format!("Can't convert {s} to duration: {e}")))?; + Ok(Duration::from_millis(millis)) +} + +#[cfg(test)] +mod test { + use super::*; + use std::{env, fs, path::PathBuf}; + use teepot::quote::tcblevel::TcbLevel; + + #[test] + fn test_load_attestation_policy_from_yaml() { + // Create a temporary directory for the test + let temp_dir = env::temp_dir().join("test_attestation_policy"); + fs::create_dir_all(&temp_dir).expect("Failed to create temp directory"); + + // Create a temporary YAML file + let yaml_path = temp_dir.join("policy.yaml"); + let yaml_content = r#" +sgx: + mrenclaves: + - a2caa7055e333f69c3e46ca7ba65b135a86c90adfde2afb356e05075b7818b3c + - 36eeb64cc816f80a1cf5818b26710f360714b987d3799e757cbefba7697b9589 + allowed_tcb_levels: + - Ok + - SwHardeningNeeded +tdx: + mrs: + - - 2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525 + - 3300980705adf09d28b707b79699d9874892164280832be2c386a715b6e204e0897fb564a064f810659207ba862b304f + - c08ab64725566bcc8a6fb1c79e2e64744fcff1594b8f1f02d716fb66592ecd5de94933b2bc54ffbbc43a52aab7eb1146 + - 092a4866a9e6a1672d7439a5d106fbc6eb57b738d5bfea5276d41afa2551824365fdd66700c1ce9c0b20542b9f9d5945 + - 971fb52f90ec98a234301ca9b8fc30b613c33e3dd9c0cc42dcb8003d4a95d8fb218b75baf028b70a3cabcb947e1ca453 +"#; + fs::write(&yaml_path, yaml_content).expect("Failed to write YAML file"); + + // Create a minimal config + let config = VerifierConfig::new(VerifierConfigArgs { + log_level: LevelFilter::INFO, + batch_range: Some((L1BatchNumber(1), L1BatchNumber(10))), + continuous: None, + rpc_url: Url::parse("http://localhost:8545").unwrap(), + chain_id: 270, + rate_limit: Duration::from_millis(0), + attestation_policy_file: Some(yaml_path.clone()), + tee_types: Default::default(), + }) + .expect("Failed to load attestation policy"); + + // Verify that the attestation policy was loaded correctly + assert_eq!(config.policy.sgx_mrsigners, None); + assert_eq!( + config.policy.sgx_mrenclaves, + Some(vec![ + Bytes::from( + hex::decode("a2caa7055e333f69c3e46ca7ba65b135a86c90adfde2afb356e05075b7818b3c") + .unwrap(), + ), + Bytes::from( + hex::decode("36eeb64cc816f80a1cf5818b26710f360714b987d3799e757cbefba7697b9589") + .unwrap(), + ), + ]) + ); + assert!(config.policy.sgx_allowed_tcb_levels.contains(TcbLevel::Ok)); + assert!(config + .policy + .sgx_allowed_tcb_levels + .contains(TcbLevel::SwHardeningNeeded)); + assert_eq!( + config.policy.tdx_mrs, + Some(vec![Bytes::from( + hex::decode(concat!( + "2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525", + "3300980705adf09d28b707b79699d9874892164280832be2c386a715b6e204e0897fb564a064f810659207ba862b304f", + "c08ab64725566bcc8a6fb1c79e2e64744fcff1594b8f1f02d716fb66592ecd5de94933b2bc54ffbbc43a52aab7eb1146", + "092a4866a9e6a1672d7439a5d106fbc6eb57b738d5bfea5276d41afa2551824365fdd66700c1ce9c0b20542b9f9d5945", + "971fb52f90ec98a234301ca9b8fc30b613c33e3dd9c0cc42dcb8003d4a95d8fb218b75baf028b70a3cabcb947e1ca453" + )).unwrap()), + ]) + ); + + // Clean up + fs::remove_file(yaml_path).expect("Failed to remove temp YAML file"); + fs::remove_dir_all(temp_dir).expect("Failed to remove temp directory"); + } + + #[test] + fn test_invalid_yaml_file_path() { + // Create a minimal config with a non-existent YAML file path + let result = VerifierConfig::new(VerifierConfigArgs { + log_level: LevelFilter::INFO, + batch_range: Some((L1BatchNumber(1), L1BatchNumber(10))), + continuous: None, + rpc_url: Url::parse("http://localhost:8545").unwrap(), + chain_id: 270, + rate_limit: Duration::from_millis(0), + attestation_policy_file: Some(PathBuf::from("/non/existent/path.yaml")), + tee_types: Default::default(), + }); + assert!(result.is_err()); + } + + #[test] + fn test_invalid_yaml_content() { + // Create a temporary directory for the test + let temp_dir = env::temp_dir().join("test_invalid_yaml"); + fs::create_dir_all(&temp_dir).expect("Failed to create temp directory"); + + // Create a temporary YAML file with invalid content + let yaml_path = temp_dir.join("invalid_policy.yaml"); + let yaml_content = r#" +sgx_mrsigners: 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef +invalid_key: "some value" +allowed_tcb_levels: + - Invalid + - ConfigNeeded +"#; + fs::write(&yaml_path, yaml_content).expect("Failed to write YAML file"); + + // Create a minimal config + let result = VerifierConfig::new(VerifierConfigArgs { + log_level: LevelFilter::INFO, + batch_range: Some((L1BatchNumber(1), L1BatchNumber(10))), + continuous: None, + rpc_url: Url::parse("http://localhost:8545").unwrap(), + chain_id: 270, + rate_limit: Duration::from_millis(0), + attestation_policy_file: Some(yaml_path.clone()), + tee_types: Default::default(), + }); + assert!(result.is_err()); + + // Clean up + fs::remove_file(yaml_path).expect("Failed to remove temp YAML file"); + fs::remove_dir_all(temp_dir).expect("Failed to remove temp directory"); + } +} diff --git a/bin/verify-era-proof-attestation/src/core/constants.rs b/bin/verify-era-proof-attestation/src/core/constants.rs new file mode 100644 index 0000000..488f240 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/core/constants.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Constants used throughout the application + +/// Maximum number of retry attempts for fetching proofs +pub const MAX_PROOF_FETCH_RETRIES: u32 = 3; + +/// Default delay between retries (in milliseconds) +pub const DEFAULT_RETRY_DELAY_MS: u64 = 1000; + +/// Default timeout for HTTP requests (in seconds) +pub const DEFAULT_HTTP_REQUEST_TIMEOUT: u64 = 30; + +/// SGX hash size in bytes +pub const SGX_HASH_SIZE: usize = 32; + +/// TDX hash size in bytes +pub const TDX_HASH_SIZE: usize = 48; diff --git a/bin/verify-era-proof-attestation/src/core/mod.rs b/bin/verify-era-proof-attestation/src/core/mod.rs new file mode 100644 index 0000000..de76247 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/core/mod.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Core components for Era proof attestation verification + +mod config; +mod constants; +mod types; + +pub use config::*; +pub use constants::*; +pub use types::*; diff --git a/bin/verify-era-proof-attestation/src/core/types.rs b/bin/verify-era-proof-attestation/src/core/types.rs new file mode 100644 index 0000000..11636c2 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/core/types.rs @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Common type definitions used throughout the application + +use std::fmt; +use zksync_basic_types::L1BatchNumber; + +/// Represents the operating mode of the verifier +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VerifierMode { + /// Run on a single batch or range of batches and then exit + OneShot { + /// Starting batch number + start_batch: L1BatchNumber, + /// Ending batch number + end_batch: L1BatchNumber, + }, + /// Run continuously starting from a specific batch, until interrupted + Continuous { + /// Starting batch number + start_batch: L1BatchNumber, + }, +} + +impl fmt::Display for VerifierMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + VerifierMode::OneShot { + start_batch, + end_batch, + } => { + if start_batch == end_batch { + write!(f, "one-shot mode (batch {})", start_batch) + } else { + write!(f, "one-shot mode (batches {}-{})", start_batch, end_batch) + } + } + VerifierMode::Continuous { start_batch } => { + write!(f, "continuous mode (starting from batch {})", start_batch) + } + } + } +} + +/// Result of proof verification for a single batch +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VerificationResult { + /// All proofs for the batch were verified successfully + Success, + /// Some proofs for the batch failed verification + PartialSuccess { + /// Number of successfully verified proofs + verified_count: u32, + /// Number of proofs that failed verification + unverified_count: u32, + }, + /// No proofs for the batch were verified successfully + Failure, + /// Verification was interrupted before completion + Interrupted, + /// No proofs were found for the batch + NoProofsFound, +} + +impl VerificationResult { + /// Check if the majority of the proofs was verified successfully + pub fn is_successful(&self) -> bool { + match self { + VerificationResult::Success => true, + VerificationResult::PartialSuccess { + verified_count, + unverified_count, + } => verified_count > unverified_count, + VerificationResult::Failure => false, + VerificationResult::Interrupted => false, + VerificationResult::NoProofsFound => false, + } + } +} + +impl fmt::Display for VerificationResult { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + VerificationResult::Success => write!(f, "Success"), + VerificationResult::PartialSuccess { + verified_count, + unverified_count, + } => { + write!( + f, + "Partial Success ({} verified, {} failed)", + verified_count, unverified_count + ) + } + VerificationResult::Failure => write!(f, "Failure"), + VerificationResult::Interrupted => write!(f, "Interrupted"), + VerificationResult::NoProofsFound => write!(f, "No Proofs Found"), + } + } +} diff --git a/bin/verify-era-proof-attestation/src/error.rs b/bin/verify-era-proof-attestation/src/error.rs new file mode 100644 index 0000000..ced5a6a --- /dev/null +++ b/bin/verify-era-proof-attestation/src/error.rs @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Error types for the verification process + +use teepot::sgx::QuoteError; +use thiserror::Error; +use zksync_basic_types::L1BatchNumber; + +/// Result type used throughout the application +pub type Result = std::result::Result; + +/// Error types that can occur during verification +#[derive(Error, Debug)] +pub enum Error { + /// Error fetching proof + #[error("Failed to fetch proof for batch {batch_number}: {reason}")] + ProofFetch { + /// Batch number that caused the error + batch_number: L1BatchNumber, + /// Reason for the error + reason: String, + }, + + /// Error communicating with the HTTP server + #[error("HTTP request failed with status {status_code}: {message}")] + Http { + /// HTTP status code + status_code: u16, + /// Error message + message: String, + }, + + /// Error communicating with the JSON-RPC server + #[error("JSON-RPC error: {0}")] + JsonRpc(String), + + /// JSON-RPC response has an invalid format + #[error("JSON-RPC response has an invalid format")] + JsonRpcInvalidResponse(String), + + /// Invalid batch range + #[error("Invalid batch range: {0}")] + InvalidBatchRange(String), + + /// Error verifying attestation + #[error(transparent)] + AttestationVerification(#[from] QuoteError), + + /// Error verifying signature + #[error("Signature verification failed: {0}")] + SignatureVerification(String), + + /// Attestation policy violation + #[error("Attestation policy violation: {0}")] + PolicyViolation(String), + + /// Operation interrupted + #[error("Operation interrupted")] + Interrupted, + + #[error(transparent)] + FromHex(#[from] hex::FromHexError), + + /// Internal error + #[error("Internal error: {0}")] + Internal(String), +} + +/// Utility functions for working with errors +impl Error { + /// Create a new proof fetch error + pub fn proof_fetch(batch_number: L1BatchNumber, reason: impl Into) -> Self { + Self::ProofFetch { + batch_number, + reason: reason.into(), + } + } + + /// Create a new policy violation error + pub fn policy_violation(reason: impl Into) -> Self { + Self::PolicyViolation(reason.into()) + } + + /// Create a new signature verification error + pub fn signature_verification(reason: impl Into) -> Self { + Self::SignatureVerification(reason.into()) + } + + /// Create a new internal error + pub fn internal(reason: impl Into) -> Self { + Self::Internal(reason.into()) + } +} + +impl From for Error { + fn from(value: reqwest::Error) -> Self { + Self::Http { + status_code: value.status().map(|v| v.as_u16()).unwrap_or(0), + message: value.to_string(), + } + } +} diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index b1388aa..9fa03ae 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -1,221 +1,91 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Tool for SGX attestation and batch signature verification, both continuous and one-shot -mod args; mod client; +mod core; +mod error; +mod processor; mod proof; mod verification; -use crate::verification::{ - log_quote_verification_summary, verify_attestation_quote, verify_batch_proof, -}; -use anyhow::Result; -use args::{Arguments, AttestationPolicyArgs}; use clap::Parser; -use client::MainNodeClient; -use proof::get_proofs; -use reqwest::Client; -use teepot::log::setup_logging; +use error::Result; use tokio::{signal, sync::watch}; -use tracing::{debug, error, info, trace, warn}; -use url::Url; -use zksync_basic_types::L1BatchNumber; + +use crate::{ + core::{VerifierConfig, VerifierConfigArgs}, + error::Error, + processor::ProcessorFactory, +}; #[tokio::main] async fn main() -> Result<()> { - let args = Arguments::parse(); - tracing::subscriber::set_global_default(setup_logging( - env!("CARGO_CRATE_NAME"), - &args.log_level, - )?)?; + // Parse command-line arguments + let config = VerifierConfig::new(VerifierConfigArgs::parse())?; - validate_arguments(&args)?; + // Initialize logging + tracing::subscriber::set_global_default( + teepot::log::setup_logging(env!("CARGO_CRATE_NAME"), &config.args.log_level) + .map_err(|e| Error::internal(e.to_string()))?, + ) + .map_err(|e| Error::internal(e.to_string()))?; + + // Create processor based on config + let (processor, mode) = ProcessorFactory::create(config.clone())?; + + // Set up stop channel let (stop_sender, stop_receiver) = watch::channel(false); - let mut process_handle = tokio::spawn(verify_batches_proofs(stop_receiver, args)); + + // Log startup information + tracing::info!("Starting verification in {}", mode); + + // Spawn processing task + let mut process_handle = tokio::spawn(async move { processor.run(stop_receiver).await }); + + // Wait for processing to complete or for stop signal tokio::select! { - ret = &mut process_handle => { return ret?; }, + result = &mut process_handle => { + match result { + Ok(Ok(verification_results)) => { + tracing::info!("Verification completed successfully"); + + let total_batches = verification_results.len(); + let successful_batches = verification_results.iter() + .filter(|(_, result)| result.is_successful()) + .count(); + + tracing::info!( + "Verified {} batches: {} succeeded, {} failed", + total_batches, + successful_batches, + total_batches - successful_batches + ); + + Ok(()) + }, + Ok(Err(e)) => { + tracing::error!("Verification failed: {}", e); + Err(e) + }, + Err(e) => { + tracing::error!("Task panicked: {}", e); + Err(Error::internal(format!("Task panicked: {}", e))) + } + } + }, _ = signal::ctrl_c() => { - tracing::info!("Stop signal received, shutting down"); + tracing::info!("Stop signal received, shutting down gracefully..."); stop_sender.send(true).ok(); - // Wait for process_batches to complete gracefully - process_handle.await??; + + // Wait for processor to complete gracefully + match process_handle.await { + Ok(_) => tracing::info!("Processor stopped gracefully"), + Err(e) => tracing::error!("Error stopping processor: {}", e), + } + + Ok(()) } } - - Ok(()) -} - -fn validate_arguments(args: &Arguments) -> Result<()> { - if args.attestation_policy.sgx_mrsigners.is_none() - && args.attestation_policy.sgx_mrenclaves.is_none() - { - error!("Neither `--sgx-mrenclaves` nor `--sgx-mrsigners` specified. Any code could have produced the proof."); - } - - Ok(()) -} - -/// Verify all TEE proofs for all batches starting from the given batch number up to the specified -/// batch number, if a range is provided. Otherwise, continue verifying batches until the stop -/// signal is received. -async fn verify_batches_proofs( - mut stop_receiver: watch::Receiver, - args: Arguments, -) -> Result<()> { - let node_client = MainNodeClient::new(args.rpc_url.clone(), args.chain_id)?; - let http_client = Client::new(); - let first_batch_number = match args.batch_range { - Some((first_batch_number, _)) => first_batch_number, - None => args - .continuous - .expect("clap::ArgGroup should guarantee batch range or continuous option is set"), - }; - let end_batch_number = args - .batch_range - .map_or(u32::MAX, |(_, end_batch_number)| end_batch_number.0); - let mut unverified_batches_count: u32 = 0; - let mut last_processed_batch_number = first_batch_number.0; - - for current_batch_number in first_batch_number.0..=end_batch_number { - if *stop_receiver.borrow() { - tracing::warn!("Stop signal received, shutting down"); - break; - } - - trace!("Verifying TEE proofs for batch #{}", current_batch_number); - - let all_verified = verify_batch_proofs( - &mut stop_receiver, - current_batch_number.into(), - &args.rpc_url, - &http_client, - &node_client, - &args.attestation_policy, - ) - .await?; - - if !all_verified { - unverified_batches_count += 1; - } - - if current_batch_number < end_batch_number { - tokio::time::timeout(args.rate_limit, stop_receiver.changed()) - .await - .ok(); - } - - last_processed_batch_number = current_batch_number; - } - - let verified_batches_count = - last_processed_batch_number + 1 - first_batch_number.0 - unverified_batches_count; - - if unverified_batches_count > 0 { - if verified_batches_count == 0 { - error!( - "All {} batches failed verification!", - unverified_batches_count - ); - } else { - error!( - "Some batches failed verification! Unverified batches: {}. Verified batches: {}.", - unverified_batches_count, verified_batches_count - ); - } - } else { - info!( - "All {} batches verified successfully!", - verified_batches_count - ); - } - - Ok(()) -} - -/// Verify all TEE proofs for the given batch number. Note that each batch number can potentially -/// have multiple proofs of the same TEE type. -async fn verify_batch_proofs( - stop_receiver: &mut watch::Receiver, - batch_number: L1BatchNumber, - rpc_url: &Url, - http_client: &Client, - node_client: &MainNodeClient, - attestation_policy: &AttestationPolicyArgs, -) -> Result { - let proofs = get_proofs(stop_receiver, batch_number, http_client, rpc_url).await?; - let batch_no = batch_number.0; - let mut total_proofs_count: u32 = 0; - let mut unverified_proofs_count: u32 = 0; - - for proof in proofs - .into_iter() - // only support SGX proofs for now - .filter(|proof| proof.tee_type.eq_ignore_ascii_case("sgx")) - { - let batch_no = proof.l1_batch_number; - - total_proofs_count += 1; - let tee_type = proof.tee_type.to_uppercase(); - - if proof - .status - .map_or(false, |s| s.eq_ignore_ascii_case("permanently_ignored")) - { - trace!( - batch_no, - tee_type, - "Proof is marked as permanently ignored. Skipping." - ); - continue; - } - trace!(batch_no, tee_type, proof.proved_at, "Verifying proof."); - - let attestation = proof.attestation.unwrap_or_default(); - debug!(batch_no, "Verifying quote ({} bytes)...", attestation.len()); - let quote_verification_result = verify_attestation_quote(&attestation)?; - let verified_successfully = verify_batch_proof( - "e_verification_result, - attestation_policy, - node_client, - &proof.signature.unwrap_or_default(), - L1BatchNumber(proof.l1_batch_number), - ) - .await?; - - log_quote_verification_summary("e_verification_result); - - if verified_successfully { - info!( - batch_no, - proof.proved_at, tee_type, "Verification succeeded.", - ); - } else { - unverified_proofs_count += 1; - warn!(batch_no, proof.proved_at, tee_type, "Verification failed!",); - } - } - - let verified_proofs_count = total_proofs_count - unverified_proofs_count; - if unverified_proofs_count > 0 { - if verified_proofs_count == 0 { - error!( - batch_no, - "All {} proofs failed verification!", unverified_proofs_count - ); - } else { - warn!( - batch_no, - "Some proofs failed verification. Unverified proofs: {}. Verified proofs: {}.", - unverified_proofs_count, - verified_proofs_count - ); - } - } - - // if at least one proof is verified, consider the batch verified - let is_batch_verified = verified_proofs_count > 0; - - Ok(is_batch_verified) } diff --git a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs new file mode 100644 index 0000000..f7520c2 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Core functionality for processing individual batches + +use crate::error; +use tokio::sync::watch; +use zksync_basic_types::L1BatchNumber; + +use crate::{ + client::{HttpClient, MainNodeClient, RetryConfig}, + core::{VerificationResult, VerifierConfig}, + proof::ProofFetcher, + verification::{BatchVerifier, VerificationReporter}, +}; + +/// Responsible for processing individual batches +pub struct BatchProcessor { + config: VerifierConfig, + proof_fetcher: ProofFetcher, + batch_verifier: BatchVerifier, +} + +impl BatchProcessor { + /// Create a new batch processor with the given configuration + pub fn new(config: VerifierConfig) -> error::Result { + // Initialize clients and fetchers + let node_client = MainNodeClient::new(config.args.rpc_url.clone(), config.args.chain_id)?; + let http_client = HttpClient::new(); + let retry_config = RetryConfig::default(); + let proof_fetcher = + ProofFetcher::new(http_client, config.args.rpc_url.clone(), retry_config); + let batch_verifier = BatchVerifier::new(node_client, config.policy.clone()); + Ok(Self { + config, + proof_fetcher, + batch_verifier, + }) + } + + /// Process a single batch and return the verification result + pub async fn process_batch( + &self, + stop_receiver: &mut watch::Receiver, + batch_number: L1BatchNumber, + ) -> error::Result { + if *stop_receiver.borrow() { + tracing::info!("Stop signal received, shutting down"); + return Ok(VerificationResult::Interrupted); + } + + tracing::trace!("Verifying TEE proofs for batch #{}", batch_number.0); + + // Fetch proofs for the current batch across different TEE types + let mut proofs = Vec::new(); + for tee_type in self.config.args.tee_types.iter() { + match self + .proof_fetcher + .get_proofs(stop_receiver, batch_number, tee_type) + .await + { + Ok(batch_proofs) => proofs.extend(batch_proofs), + Err(error::Error::Interrupted) => return Err(error::Error::Interrupted), + Err(e) => { + tracing::error!( + "Failed to fetch proofs for TEE type {:?} at batch {}: {:#}", + tee_type, + batch_number.0, + e + ); + continue; + } + } + } + + if proofs.is_empty() { + tracing::warn!("No proofs found for batch #{}", batch_number.0); + return Ok(VerificationResult::NoProofsFound); + } + + // Verify proofs for the current batch + let verification_result = self + .batch_verifier + .verify_batch_proofs(stop_receiver, batch_number, proofs) + .await?; + + let result = if verification_result.total_count == 0 { + VerificationResult::NoProofsFound + } else if verification_result.verified_count == verification_result.total_count { + VerificationResult::Success + } else if verification_result.verified_count > 0 { + VerificationResult::PartialSuccess { + verified_count: verification_result.verified_count, + unverified_count: verification_result.unverified_count, + } + } else { + VerificationResult::Failure + }; + + tracing::debug!("Batch #{} verification result: {}", batch_number.0, result); + + // Apply rate limiting between batches if needed + if !matches!(result, VerificationResult::Interrupted) + && self.config.args.rate_limit.as_millis() > 0 + { + tokio::time::timeout(self.config.args.rate_limit, stop_receiver.changed()) + .await + .ok(); + } + + Ok(result) + } + + /// Log the overall verification results + pub fn log_overall_results(success_count: u32, failure_count: u32) { + VerificationReporter::log_overall_verification_results(success_count, failure_count); + } +} diff --git a/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs b/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs new file mode 100644 index 0000000..4e66ce0 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Continuous batch processor for ongoing verification of new batches + +use tokio::sync::watch; +use zksync_basic_types::L1BatchNumber; + +use crate::{ + core::{VerificationResult, VerifierConfig}, + error, + processor::BatchProcessor, +}; + +/// Processes batches continuously until stopped +pub struct ContinuousProcessor { + batch_processor: BatchProcessor, + start_batch: L1BatchNumber, +} + +impl ContinuousProcessor { + /// Create a new continuous processor that starts from the given batch + pub fn new(config: VerifierConfig, start_batch: L1BatchNumber) -> error::Result { + let batch_processor = BatchProcessor::new(config)?; + + Ok(Self { + batch_processor, + start_batch, + }) + } + + /// Run the processor until stopped + pub async fn run( + &self, + mut stop_receiver: watch::Receiver, + ) -> error::Result> { + tracing::info!( + "Starting continuous verification from batch {}", + self.start_batch.0 + ); + + let mut results = Vec::new(); + let mut success_count = 0; + let mut failure_count = 0; + let mut current_batch = self.start_batch.0; + + // Continue processing batches until stopped or reaching maximum batch number + while !*stop_receiver.borrow() { + let batch = L1BatchNumber(current_batch); + match self + .batch_processor + .process_batch(&mut stop_receiver, batch) + .await + { + Ok(result) => { + match result { + VerificationResult::Success => success_count += 1, + VerificationResult::PartialSuccess { .. } => success_count += 1, + VerificationResult::Failure => failure_count += 1, + VerificationResult::Interrupted => { + results.push((current_batch, result)); + break; + } + VerificationResult::NoProofsFound => { + // In continuous mode, we might hit batches that don't have proofs yet + // Wait a bit longer before retrying + if !*stop_receiver.borrow() { + tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; + // Don't increment batch number, try again + continue; + } + } + } + + results.push((current_batch, result)); + } + Err(e) => { + tracing::error!("Error processing batch {}: {}", current_batch, e); + results.push((current_batch, VerificationResult::Failure)); + failure_count += 1; + } + } + + // Move to the next batch + current_batch = current_batch + .checked_add(1) + .ok_or(error::Error::internal("Maximum batch number reached"))?; + } + + // Log overall results + BatchProcessor::log_overall_results(success_count, failure_count); + + Ok(results) + } +} diff --git a/bin/verify-era-proof-attestation/src/processor/mod.rs b/bin/verify-era-proof-attestation/src/processor/mod.rs new file mode 100644 index 0000000..449f694 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/processor/mod.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Processing logic for batch verification + +mod batch_processor; +mod continuous_processor; +mod one_shot_processor; + +pub use batch_processor::BatchProcessor; +pub use continuous_processor::ContinuousProcessor; +pub use one_shot_processor::OneShotProcessor; + +use crate::{ + core::{VerificationResult, VerifierConfig, VerifierMode}, + error::Result, +}; +use tokio::sync::watch; + +// Using an enum instead of a trait because async functions in traits can't be used in trait objects +/// Processor variants for different verification modes +pub enum ProcessorType { + /// One-shot processor for processing a specific range of batches + OneShot(OneShotProcessor), + /// Continuous processor for monitoring new batches + Continuous(ContinuousProcessor), +} + +impl ProcessorType { + /// Run the processor until completion or interruption + pub async fn run( + &self, + stop_receiver: watch::Receiver, + ) -> Result> { + match self { + ProcessorType::OneShot(processor) => processor.run(stop_receiver).await, + ProcessorType::Continuous(processor) => processor.run(stop_receiver).await, + } + } +} + +/// Factory for creating the appropriate processor based on configuration +pub struct ProcessorFactory; + +impl ProcessorFactory { + /// Create a new processor based on the provided configuration + pub fn create(config: VerifierConfig) -> Result<(ProcessorType, VerifierMode)> { + let mode = if let Some((start, end)) = config.args.batch_range { + let processor = OneShotProcessor::new(config.clone(), start, end)?; + let mode = VerifierMode::OneShot { + start_batch: start, + end_batch: end, + }; + (ProcessorType::OneShot(processor), mode) + } else if let Some(start) = config.args.continuous { + let processor = ContinuousProcessor::new(config.clone(), start)?; + let mode = VerifierMode::Continuous { start_batch: start }; + (ProcessorType::Continuous(processor), mode) + } else { + unreachable!("Clap ArgGroup should ensure either batch_range or continuous is set") + }; + + Ok(mode) + } +} diff --git a/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs b/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs new file mode 100644 index 0000000..469e9de --- /dev/null +++ b/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! One-shot batch processor for verifying a single batch or a range of batches + +use crate::error; +use tokio::sync::watch; +use zksync_basic_types::L1BatchNumber; + +use crate::{ + core::{VerificationResult, VerifierConfig}, + processor::BatchProcessor, +}; + +/// Processes a specific range of batches and then exits +pub struct OneShotProcessor { + batch_processor: BatchProcessor, + start_batch: L1BatchNumber, + end_batch: L1BatchNumber, +} + +impl OneShotProcessor { + /// Create a new one-shot processor for the given batch range + pub fn new( + config: VerifierConfig, + start_batch: L1BatchNumber, + end_batch: L1BatchNumber, + ) -> error::Result { + let batch_processor = BatchProcessor::new(config)?; + + Ok(Self { + batch_processor, + start_batch, + end_batch, + }) + } + + /// Run the processor until completion or interruption + pub async fn run( + &self, + mut stop_receiver: watch::Receiver, + ) -> error::Result> { + tracing::info!( + "Starting one-shot verification of batches {} to {}", + self.start_batch.0, + self.end_batch.0 + ); + + let mut results = Vec::new(); + let mut success_count = 0; + let mut failure_count = 0; + + for batch_number in self.start_batch.0..=self.end_batch.0 { + let batch = L1BatchNumber(batch_number); + let result = self + .batch_processor + .process_batch(&mut stop_receiver, batch) + .await?; + + match result { + VerificationResult::Success => success_count += 1, + VerificationResult::PartialSuccess { .. } => success_count += 1, + VerificationResult::Failure => failure_count += 1, + VerificationResult::Interrupted => { + results.push((batch_number, result)); + break; + } + VerificationResult::NoProofsFound => {} + } + + results.push((batch_number, result)); + } + + // Log overall results + BatchProcessor::log_overall_results(success_count, failure_count); + + Ok(results) + } +} diff --git a/bin/verify-era-proof-attestation/src/proof.rs b/bin/verify-era-proof-attestation/src/proof.rs deleted file mode 100644 index 3ee9990..0000000 --- a/bin/verify-era-proof-attestation/src/proof.rs +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs - -use anyhow::{bail, Result}; -use jsonrpsee_types::error::ErrorObject; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use serde_with::{hex::Hex, serde_as}; -use std::time::Duration; -use tokio::sync::watch; -use tracing::{error, warn}; -use url::Url; -use zksync_basic_types::L1BatchNumber; - -#[derive(Debug, Serialize, Deserialize)] -pub struct GetProofsRequest { - pub jsonrpc: String, - pub id: u32, - pub method: String, - pub params: (L1BatchNumber, String), -} - -pub async fn get_proofs( - stop_receiver: &mut watch::Receiver, - batch_number: L1BatchNumber, - http_client: &Client, - rpc_url: &Url, -) -> Result> { - let mut proofs_request = GetProofsRequest::new(batch_number); - let mut retries = 0; - let mut backoff = Duration::from_secs(1); - let max_backoff = Duration::from_secs(128); - let retry_backoff_multiplier: f32 = 2.0; - - while !*stop_receiver.borrow() { - let proofs = proofs_request - .send(stop_receiver, http_client, rpc_url) - .await?; - - if !proofs.is_empty() - && proofs.iter().all(|proof| { - !proof.status.as_ref().map_or(false, |s| { - s.eq_ignore_ascii_case("failed") | s.eq_ignore_ascii_case("picked_by_prover") - }) - }) - { - return Ok(proofs); - } - - retries += 1; - warn!( - batch_no = batch_number.0, retries, - "No TEE proofs found for batch #{}. They may not be ready yet. Retrying in {} milliseconds.", - batch_number, backoff.as_millis(), - ); - - tokio::time::timeout(backoff, stop_receiver.changed()) - .await - .ok(); - - backoff = std::cmp::min(backoff.mul_f32(retry_backoff_multiplier), max_backoff); - } - - Ok(vec![]) -} - -impl GetProofsRequest { - pub fn new(batch_number: L1BatchNumber) -> Self { - GetProofsRequest { - jsonrpc: "2.0".to_string(), - id: 1, - method: "unstable_getTeeProofs".to_string(), - params: (batch_number, "sgx".to_string()), - } - } - - pub async fn send( - &mut self, - stop_receiver: &mut watch::Receiver, - http_client: &Client, - rpc_url: &Url, - ) -> Result> { - let mut retries = 0; - let max_retries = 5; - let mut backoff = Duration::from_secs(1); - let max_backoff = Duration::from_secs(128); - let retry_backoff_multiplier: f32 = 2.0; - let mut response = None; - - while !*stop_receiver.borrow() { - let result = http_client - .post(rpc_url.clone()) - .json(self) - .send() - .await? - .error_for_status()? - .json::() - .await; - - match result { - Ok(res) => match res.error { - None => { - response = Some(res); - break; - } - Some(error) => { - // Handle corner case, where the old RPC interface expects 'Sgx' - if let Some(data) = error.data() { - if data.get().contains("unknown variant `sgx`, expected `Sgx`") { - self.params.1 = "Sgx".to_string(); - continue; - } - } - error!(?error, "received JSONRPC error {error:?}"); - bail!("JSONRPC error {error:?}"); - } - }, - Err(err) => { - retries += 1; - if retries >= max_retries { - return Err(anyhow::anyhow!( - "Failed to send request to {} after {} retries: {}. Request details: {:?}", - rpc_url, - max_retries, - err, - self - )); - } - warn!( - %err, - "Failed to send request to {rpc_url}. {retries}/{max_retries}, retrying in {} milliseconds. Request details: {:?}", - backoff.as_millis(), - self - ); - tokio::time::timeout(backoff, stop_receiver.changed()) - .await - .ok(); - backoff = std::cmp::min(backoff.mul_f32(retry_backoff_multiplier), max_backoff); - } - }; - } - - Ok(response.map_or_else(Vec::new, |res| res.result.unwrap_or_default())) - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct GetProofsResponse { - pub jsonrpc: String, - pub result: Option>, - pub id: u32, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option>, -} - -#[serde_as] -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Proof { - pub l1_batch_number: u32, - pub tee_type: String, - #[serde_as(as = "Option")] - pub pubkey: Option>, - #[serde_as(as = "Option")] - pub signature: Option>, - #[serde_as(as = "Option")] - pub proof: Option>, - pub proved_at: String, - pub status: Option, - #[serde_as(as = "Option")] - pub attestation: Option>, -} diff --git a/bin/verify-era-proof-attestation/src/proof/fetcher.rs b/bin/verify-era-proof-attestation/src/proof/fetcher.rs new file mode 100644 index 0000000..0a22445 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/proof/fetcher.rs @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use crate::{ + client::{HttpClient, RetryConfig, RetryHelper}, + error::{Error, Result}, + proof::{ + parsing::ProofResponseParser, + types::{GetProofsRequest, GetProofsResponse, Proof}, + }, +}; +use std::time::Duration; +use tokio::sync::watch; +use url::Url; +use zksync_basic_types::{tee_types::TeeType, L1BatchNumber}; + +/// Handles fetching proofs from the server with retry logic +pub struct ProofFetcher { + http_client: HttpClient, + rpc_url: Url, + retry_config: RetryConfig, +} + +impl ProofFetcher { + /// Create a new proof fetcher + pub fn new(http_client: HttpClient, rpc_url: Url, retry_config: RetryConfig) -> Self { + Self { + http_client, + rpc_url, + retry_config, + } + } + + /// Get proofs for a batch number with retry logic + pub async fn get_proofs( + &self, + stop_receiver: &mut watch::Receiver, + batch_number: L1BatchNumber, + tee_type: &TeeType, + ) -> Result> { + let mut proofs_request = GetProofsRequest::new(batch_number, tee_type); + let mut backoff = Duration::from_secs(1); + let max_backoff = Duration::from_secs(128); + let retry_backoff_multiplier: f32 = 2.0; + + while !*stop_receiver.borrow() { + match self.send_request(&proofs_request, stop_receiver).await { + Ok(response) => { + // Parse the response using the ProofResponseParser + match ProofResponseParser::parse_response(response) { + Ok(proofs) => { + // Filter valid proofs + let valid_proofs = ProofResponseParser::filter_valid_proofs(&proofs); + + if !valid_proofs.is_empty() { + return Ok(valid_proofs); + } + + // No valid proofs found, retry + let error_msg = format!( + "No valid TEE proofs found for batch #{}. They may not be ready yet. Retrying in {} milliseconds.", + batch_number.0, + backoff.as_millis() + ); + tracing::warn!(batch_no = batch_number.0, "{}", error_msg); + // Here we could use the ProofFetching error if we needed to return immediately + // return Err(Error::ProofFetching(error_msg)); + } + Err(e) => { + // Handle specific error for Sgx variant + if let Error::JsonRpc(msg) = &e { + if msg.contains("RPC requires 'Sgx' variant") { + tracing::debug!("Switching to 'Sgx' variant for RPC"); + proofs_request.params.1 = "Sgx".to_string(); + continue; + } + } + return Err(e); + } + } + } + Err(e) => { + return Err(e); + } + } + + tokio::time::timeout(backoff, stop_receiver.changed()) + .await + .ok(); + + backoff = std::cmp::min( + Duration::from_millis( + (backoff.as_millis() as f32 * retry_backoff_multiplier) as u64, + ), + max_backoff, + ); + + if *stop_receiver.borrow() { + break; + } + } + + // If we've reached this point, we've either been stopped or exhausted retries + if *stop_receiver.borrow() { + // Return empty vector if stopped + Ok(vec![]) + } else { + // Use the ProofFetching error variant if we've exhausted retries + Err(Error::proof_fetch(batch_number, "exhausted retries")) + } + } + + /// Send a request to the server with retry logic + async fn send_request( + &self, + request: &GetProofsRequest, + stop_receiver: &mut watch::Receiver, + ) -> Result { + let retry_helper = RetryHelper::new(self.retry_config.clone()); + let request_clone = request.clone(); + let http_client = self.http_client.clone(); + let rpc_url = self.rpc_url.clone(); + + retry_helper + .execute(&format!("get_proofs_{}", request.params.0), || async { + let result = http_client + .send_json::<_, GetProofsResponse>(&rpc_url, &request_clone) + .await; + + // Check if we need to abort due to stop signal + if *stop_receiver.borrow() { + return Err(Error::Interrupted); + } + + result + }) + .await + } +} diff --git a/bin/verify-era-proof-attestation/src/proof/mod.rs b/bin/verify-era-proof-attestation/src/proof/mod.rs new file mode 100644 index 0000000..46c125a --- /dev/null +++ b/bin/verify-era-proof-attestation/src/proof/mod.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +mod fetcher; +mod parsing; +mod types; + +pub use fetcher::ProofFetcher; +pub use types::Proof; diff --git a/bin/verify-era-proof-attestation/src/proof/parsing.rs b/bin/verify-era-proof-attestation/src/proof/parsing.rs new file mode 100644 index 0000000..6519e17 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/proof/parsing.rs @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use super::types::{GetProofsResponse, Proof}; +use crate::error; + +/// Handles parsing of proof responses and error handling +pub struct ProofResponseParser; + +impl ProofResponseParser { + /// Parse a response and extract the proofs + pub fn parse_response(response: GetProofsResponse) -> error::Result> { + // Handle JSON-RPC errors + if let Some(error) = response.error { + // Special case for handling the old RPC interface + if let Some(data) = error.data() { + if data.get().contains("unknown variant `sgx`, expected `Sgx`") { + return Err(error::Error::JsonRpc( + "RPC requires 'Sgx' variant instead of 'sgx'".to_string(), + )); + } + } + + return Err(error::Error::JsonRpc(format!("JSONRPC error: {:?}", error))); + } + + // Extract proofs from the result + Ok(response.result.unwrap_or_default()) + } + + /// Filter proofs to find valid ones + pub fn filter_valid_proofs(proofs: &[Proof]) -> Vec { + proofs + .iter() + .filter(|proof| !proof.is_failed_or_picked()) + .cloned() + .collect() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use jsonrpsee_types::error::ErrorObject; + + #[test] + fn test_proof_is_permanently_ignored() { + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("permanently_ignored".to_string()), + attestation: None, + }; + + assert!(proof.is_permanently_ignored()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("PERMANENTLY_IGNORED".to_string()), + attestation: None, + }; + + assert!(proof.is_permanently_ignored()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("other".to_string()), + attestation: None, + }; + + assert!(!proof.is_permanently_ignored()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: None, + attestation: None, + }; + + assert!(!proof.is_permanently_ignored()); + } + + #[test] + fn test_proof_is_failed_or_picked() { + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("failed".to_string()), + attestation: None, + }; + + assert!(proof.is_failed_or_picked()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("picked_by_prover".to_string()), + attestation: None, + }; + + assert!(proof.is_failed_or_picked()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("FAILED".to_string()), + attestation: None, + }; + + assert!(proof.is_failed_or_picked()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("other".to_string()), + attestation: None, + }; + + assert!(!proof.is_failed_or_picked()); + + let proof = Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: None, + attestation: None, + }; + + assert!(!proof.is_failed_or_picked()); + } + + #[test] + fn test_parse_response_success() { + let response = GetProofsResponse { + jsonrpc: "2.0".to_string(), + result: Some(vec![Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: None, + attestation: None, + }]), + id: 1, + error: None, + }; + + let proofs = ProofResponseParser::parse_response(response).unwrap(); + assert_eq!(proofs.len(), 1); + assert_eq!(proofs[0].l1_batch_number, 123); + } + + #[test] + fn test_parse_response_error() { + let response = GetProofsResponse { + jsonrpc: "2.0".to_string(), + result: None, + id: 1, + error: Some(ErrorObject::owned(1, "Error", None::<()>)), + }; + + let error = ProofResponseParser::parse_response(response).unwrap_err(); + match error { + error::Error::JsonRpc(msg) => { + assert!(msg.contains("JSONRPC error")); + } + _ => panic!("Expected JsonRpc error"), + } + } + + #[test] + fn test_parse_response_sgx_variant_error() { + let error_obj = ErrorObject::owned( + 1, + "Error", + Some( + serde_json::to_value("unknown variant `sgx`, expected `Sgx`") + .unwrap() + .to_string(), + ), + ); + + let response = GetProofsResponse { + jsonrpc: "2.0".to_string(), + result: None, + id: 1, + error: Some(error_obj), + }; + + let error = ProofResponseParser::parse_response(response).unwrap_err(); + match error { + error::Error::JsonRpc(msg) => { + assert!(msg.contains("RPC requires 'Sgx' variant")); + } + _ => panic!("Expected JsonRpc error about Sgx variant"), + } + } + + #[test] + fn test_filter_valid_proofs() { + let proofs = vec![ + Proof { + l1_batch_number: 123, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: None, + attestation: None, + }, + Proof { + l1_batch_number: 124, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("failed".to_string()), + attestation: None, + }, + Proof { + l1_batch_number: 125, + tee_type: "TDX".to_string(), + pubkey: None, + signature: None, + proof: None, + proved_at: "2023-01-01T00:00:00Z".to_string(), + status: Some("picked_by_prover".to_string()), + attestation: None, + }, + ]; + + let valid_proofs = ProofResponseParser::filter_valid_proofs(&proofs); + assert_eq!(valid_proofs.len(), 1); + assert_eq!(valid_proofs[0].l1_batch_number, 123); + } +} diff --git a/bin/verify-era-proof-attestation/src/proof/types.rs b/bin/verify-era-proof-attestation/src/proof/types.rs new file mode 100644 index 0000000..af3e905 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/proof/types.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use jsonrpsee_types::error::ErrorObject; +use serde::{Deserialize, Serialize}; +use serde_with::{hex::Hex, serde_as}; +use zksync_basic_types::{tee_types::TeeType, L1BatchNumber}; + +/// Request structure for fetching proofs +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct GetProofsRequest { + pub jsonrpc: String, + pub id: u32, + pub method: String, + pub params: (L1BatchNumber, String), +} + +impl GetProofsRequest { + /// Create a new request for the given batch number + pub fn new(batch_number: L1BatchNumber, tee_type: &TeeType) -> Self { + GetProofsRequest { + jsonrpc: "2.0".to_string(), + id: 1, + method: "unstable_getTeeProofs".to_string(), + params: (batch_number, tee_type.to_string()), + } + } +} + +/// Response structure for proof requests +#[derive(Debug, Serialize, Deserialize)] +pub struct GetProofsResponse { + pub jsonrpc: String, + pub result: Option>, + pub id: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option>, +} + +/// Proof structure containing attestation and signature data +#[serde_as] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Proof { + pub l1_batch_number: u32, + pub tee_type: String, + #[serde_as(as = "Option")] + pub pubkey: Option>, + #[serde_as(as = "Option")] + pub signature: Option>, + #[serde_as(as = "Option")] + pub proof: Option>, + pub proved_at: String, + pub status: Option, + #[serde_as(as = "Option")] + pub attestation: Option>, +} + +impl Proof { + /// Check if the proof is marked as permanently ignored + pub fn is_permanently_ignored(&self) -> bool { + self.status + .as_ref() + .map_or(false, |s| s.eq_ignore_ascii_case("permanently_ignored")) + } + + /// Check if the proof is failed or picked by a prover + pub fn is_failed_or_picked(&self) -> bool { + self.status.as_ref().map_or(false, |s| { + s.eq_ignore_ascii_case("failed") || s.eq_ignore_ascii_case("picked_by_prover") + }) + } + + /// Get the attestation bytes or an empty vector if not present + pub fn attestation_bytes(&self) -> Vec { + self.attestation.clone().unwrap_or_default() + } + + /// Get the signature bytes or an empty vector if not present + pub fn signature_bytes(&self) -> Vec { + self.signature.clone().unwrap_or_default() + } +} diff --git a/bin/verify-era-proof-attestation/src/verification.rs b/bin/verify-era-proof-attestation/src/verification.rs deleted file mode 100644 index 4ae892e..0000000 --- a/bin/verify-era-proof-attestation/src/verification.rs +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2025 Matter Labs - -use crate::{args::AttestationPolicyArgs, client::JsonRpcClient}; -use anyhow::{anyhow, Context, Result}; -use hex::encode; -use secp256k1::{ - ecdsa::{RecoverableSignature, RecoveryId, Signature}, - Message, SECP256K1, -}; -use teepot::{ - ethereum::{public_key_to_ethereum_address, recover_signer}, - prover::reportdata::ReportData, - quote::{ - error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral, - QuoteVerificationResult, Report, - }, - sgx::TcbLevel, -}; -use tracing::{debug, info, trace, warn}; -use zksync_basic_types::{L1BatchNumber, H256}; - -struct TeeProof { - report: ReportData, - root_hash: H256, - signature: Vec, -} - -impl TeeProof { - pub fn new(report: ReportData, root_hash: H256, signature: Vec) -> Self { - Self { - report, - root_hash, - signature, - } - } - - pub fn verify(&self) -> Result { - match &self.report { - ReportData::V0(report) => { - debug!("ReportData::V0"); - let signature = Signature::from_compact(&self.signature)?; - let root_hash_msg = Message::from_digest_slice(&self.root_hash.0)?; - Ok(signature.verify(&root_hash_msg, &report.pubkey).is_ok()) - } - ReportData::V1(report) => { - debug!("ReportData::V1"); - let ethereum_address_from_report = report.ethereum_address; - let root_hash_msg = Message::from_digest_slice(self.root_hash.as_bytes())?; - - trace!("sig len = {}", self.signature.len()); - - let sig_vec = self.signature.clone(); - - if self.signature.len() == 64 { - info!("Signature is missing RecoveryId!"); - // Fallback for missing RecoveryId - for rec_id in [ - RecoveryId::Zero, - RecoveryId::One, - RecoveryId::Two, - RecoveryId::Three, - ] { - let Ok(sig) = RecoverableSignature::from_compact(&sig_vec, rec_id) else { - continue; - }; - let Ok(public) = SECP256K1.recover_ecdsa(&root_hash_msg, &sig) else { - continue; - }; - let ethereum_address_from_signature = - public_key_to_ethereum_address(&public); - - debug!( - "Root hash: {}. Ethereum address from the attestation quote: {}. Ethereum address from the signature: {}.", - self.root_hash, - encode(ethereum_address_from_report), - encode(ethereum_address_from_signature), - ); - if ethereum_address_from_signature == ethereum_address_from_report { - info!("Had to use RecoveryId::{rec_id:?}"); - return Ok(true); - } - } - return Ok(false); - } - - let signature_bytes: [u8; 65] = sig_vec - .try_into() - .map_err(|e| anyhow!("{:?}", e)) - .context("invalid length of signature bytes")?; - let ethereum_address_from_signature = - recover_signer(&signature_bytes, &root_hash_msg)?; - debug!( - "Root hash: {}. Ethereum address from the attestation quote: {}. Ethereum address from the signature: {}.", - self.root_hash, - encode(ethereum_address_from_report), - encode(ethereum_address_from_signature), - ); - Ok(ethereum_address_from_signature == ethereum_address_from_report) - } - ReportData::Unknown(_) => Ok(false), - } - } -} - -pub async fn verify_batch_proof( - quote_verification_result: &QuoteVerificationResult, - attestation_policy: &AttestationPolicyArgs, - node_client: &impl JsonRpcClient, - signature: &[u8], - batch_number: L1BatchNumber, -) -> Result { - if !is_quote_matching_policy(attestation_policy, quote_verification_result) { - return Ok(false); - } - - 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 = ReportData::try_from(report_data_bytes)?; - let tee_proof = TeeProof::new(report_data, root_hash, signature.to_vec()); - tee_proof.verify() -} - -pub fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result { - let collateral = QuoteContext::context( - tee_qv_get_collateral(attestation_quote_bytes), - "Failed to get collateral!", - )?; - let unix_time: i64 = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH)? - .as_secs() as _; - verify_quote_with_collateral(attestation_quote_bytes, Some(&collateral), unix_time) - .context("Failed to verify quote with collateral!") -} - -pub fn log_quote_verification_summary(quote_verification_result: &QuoteVerificationResult) { - let QuoteVerificationResult { - collateral_expired, - result, - quote, - advisories, - .. - } = quote_verification_result; - if *collateral_expired { - warn!("Freshly fetched collateral expired!"); - } - let tcblevel = TcbLevel::from(*result); - let advisories = if advisories.is_empty() { - "None".to_string() - } else { - advisories - .iter() - .map(ToString::to_string) - .collect::>() - .join(", ") - }; - - info!( - "Quote verification result: {tcblevel}. {report}. Advisory IDs: {advisories}.", - report = "e.report - ); -} - -fn is_quote_matching_policy( - attestation_policy: &AttestationPolicyArgs, - quote_verification_result: &QuoteVerificationResult, -) -> bool { - let quote = "e_verification_result.quote; - let tcblevel = TcbLevel::from(quote_verification_result.result); - - if !attestation_policy.sgx_allowed_tcb_levels.contains(tcblevel) { - warn!( - "Quote verification failed: TCB level mismatch (expected one of: {:?}, actual: {})", - attestation_policy.sgx_allowed_tcb_levels, tcblevel - ); - return false; - } - match "e.report { - Report::SgxEnclave(report_body) => { - check_policy( - attestation_policy.sgx_mrsigners.as_deref(), - &report_body.mr_signer, - "mrsigner", - ) && check_policy( - attestation_policy.sgx_mrenclaves.as_deref(), - &report_body.mr_enclave, - "mrenclave", - ) - } - _ => false, - } -} - -fn check_policy(policy: Option<&str>, actual_value: &[u8], field_name: &str) -> bool { - if let Some(valid_values) = policy { - let valid_values: Vec<&str> = valid_values.split(',').collect(); - let actual_value = hex::encode(actual_value); - if !valid_values.contains(&actual_value.as_str()) { - warn!( - "Quote verification failed: {} mismatch (expected one of: {:?}, actual: {})", - field_name, valid_values, actual_value - ); - return false; - } - debug!(field_name, actual_value, "Attestation policy check passed"); - } - true -} diff --git a/bin/verify-era-proof-attestation/src/verification/attestation.rs b/bin/verify-era-proof-attestation/src/verification/attestation.rs new file mode 100644 index 0000000..cfbc00a --- /dev/null +++ b/bin/verify-era-proof-attestation/src/verification/attestation.rs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use teepot::quote::{ + error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral, + QuoteVerificationResult, +}; + +use crate::error; + +/// Handles verification of attestation quotes +pub struct AttestationVerifier; + +impl AttestationVerifier { + /// Verify an attestation quote + pub fn verify_quote(attestation_quote_bytes: &[u8]) -> error::Result { + // Get collateral for the quote + let collateral = QuoteContext::context( + tee_qv_get_collateral(attestation_quote_bytes), + "Failed to get collateral!", + )?; + + // Get current time for verification + let unix_time: i64 = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map_err(|e| error::Error::internal(format!("Failed to get system time: {}", e)))? + .as_secs() as _; + + // Verify the quote with the collateral + let res = + verify_quote_with_collateral(attestation_quote_bytes, Some(&collateral), unix_time)?; + + Ok(res) + } +} diff --git a/bin/verify-era-proof-attestation/src/verification/batch.rs b/bin/verify-era-proof-attestation/src/verification/batch.rs new file mode 100644 index 0000000..53c3438 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/verification/batch.rs @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use crate::{ + client::JsonRpcClient, + core::AttestationPolicy, + error, + proof::Proof, + verification::{AttestationVerifier, PolicyEnforcer, SignatureVerifier, VerificationReporter}, +}; +use tokio::sync::watch; +use zksync_basic_types::L1BatchNumber; + +/// Result of a batch verification +#[derive(Debug, Clone, Copy)] +pub struct BatchVerificationResult { + /// Total number of proofs processed + pub total_count: u32, + /// Number of proofs that were verified successfully + pub verified_count: u32, + /// Number of proofs that failed verification + pub unverified_count: u32, +} + +/// Handles the batch verification process +pub struct BatchVerifier { + node_client: C, + attestation_policy: AttestationPolicy, +} + +impl BatchVerifier { + /// Create a new batch verifier + pub fn new(node_client: C, attestation_policy: AttestationPolicy) -> Self { + Self { + node_client, + attestation_policy, + } + } + + /// Verify proofs for a batch + pub async fn verify_batch_proofs( + &self, + stop_receiver: &mut watch::Receiver, + batch_number: L1BatchNumber, + proofs: Vec, + ) -> error::Result { + let batch_no = batch_number.0; + let mut total_proofs_count: u32 = 0; + let mut verified_proofs_count: u32 = 0; + + for proof in proofs.into_iter() { + if *stop_receiver.borrow() { + tracing::warn!("Stop signal received during batch verification"); + return Ok(BatchVerificationResult { + total_count: total_proofs_count, + verified_count: verified_proofs_count, + unverified_count: total_proofs_count - verified_proofs_count, + }); + } + + total_proofs_count += 1; + let tee_type = proof.tee_type.to_uppercase(); + + if proof.is_permanently_ignored() { + tracing::debug!( + batch_no, + tee_type, + "Proof is marked as permanently ignored. Skipping." + ); + continue; + } + + tracing::debug!(batch_no, tee_type, proof.proved_at, "Verifying proof."); + + let attestation_bytes = proof.attestation_bytes(); + let signature_bytes = proof.signature_bytes(); + + tracing::debug!( + batch_no, + "Verifying quote ({} bytes)...", + attestation_bytes.len() + ); + + // Verify attestation + let quote_verification_result = AttestationVerifier::verify_quote(&attestation_bytes)?; + + // Log verification results + VerificationReporter::log_quote_verification_summary("e_verification_result); + + // Check if attestation matches policy + let policy_matches = PolicyEnforcer::validate_policy( + &self.attestation_policy, + "e_verification_result, + ); + + if let Err(e) = policy_matches { + tracing::error!(batch_no, tee_type, "Attestation policy check failed: {e}"); + continue; + } + + // Verify signature + let root_hash = self + .node_client + .get_root_hash(L1BatchNumber(proof.l1_batch_number)) + .await?; + + let signature_verified = SignatureVerifier::verify_batch_proof( + "e_verification_result, + root_hash, + &signature_bytes, + )?; + + if signature_verified { + tracing::info!( + batch_no, + proof.proved_at, + tee_type, + "Verification succeeded.", + ); + verified_proofs_count += 1; + } else { + tracing::warn!(batch_no, proof.proved_at, tee_type, "Verification failed!",); + } + } + + let unverified_proofs_count = total_proofs_count.saturating_sub(verified_proofs_count); + + // Log batch verification results + VerificationReporter::log_batch_verification_results( + batch_no, + verified_proofs_count, + unverified_proofs_count, + ); + + Ok(BatchVerificationResult { + total_count: total_proofs_count, + verified_count: verified_proofs_count, + unverified_count: unverified_proofs_count, + }) + } +} diff --git a/bin/verify-era-proof-attestation/src/verification/mod.rs b/bin/verify-era-proof-attestation/src/verification/mod.rs new file mode 100644 index 0000000..1a8f19b --- /dev/null +++ b/bin/verify-era-proof-attestation/src/verification/mod.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +mod attestation; +mod batch; +mod policy; +mod reporting; +mod signature; + +pub use attestation::AttestationVerifier; +pub use batch::BatchVerifier; +pub use policy::PolicyEnforcer; +pub use reporting::VerificationReporter; +pub use signature::SignatureVerifier; diff --git a/bin/verify-era-proof-attestation/src/verification/policy.rs b/bin/verify-era-proof-attestation/src/verification/policy.rs new file mode 100644 index 0000000..babff24 --- /dev/null +++ b/bin/verify-era-proof-attestation/src/verification/policy.rs @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use crate::{ + core::AttestationPolicy, + error::{Error, Result}, +}; +use bytes::Bytes; +use enumset::EnumSet; +use teepot::quote::{tcblevel::TcbLevel, QuoteVerificationResult, Report}; + +/// Enforces policy requirements on attestation quotes +pub struct PolicyEnforcer; + +impl PolicyEnforcer { + /// Check if a quote matches the attestation policy + pub fn validate_policy( + attestation_policy: &AttestationPolicy, + quote_verification_result: &QuoteVerificationResult, + ) -> Result<()> { + let quote = "e_verification_result.quote; + let tcblevel = TcbLevel::from(quote_verification_result.result); + + match "e.report { + Report::SgxEnclave(report_body) => { + // Validate TCB level + Self::validate_tcb_level(&attestation_policy.sgx_allowed_tcb_levels, tcblevel)?; + + // Validate SGX Advisories + for advisory in "e_verification_result.advisories { + Self::check_policy( + attestation_policy.sgx_allowed_advisory_ids.as_deref(), + advisory, + "advisories", + )?; + } + + // Validate SGX policies + Self::check_policy_hash( + attestation_policy.sgx_mrsigners.as_deref(), + &report_body.mr_signer, + "mrsigner", + )?; + + Self::check_policy_hash( + attestation_policy.sgx_mrenclaves.as_deref(), + &report_body.mr_enclave, + "mrenclave", + ) + } + Report::TD10(report_body) => { + // Validate TCB level + Self::validate_tcb_level(&attestation_policy.tdx_allowed_tcb_levels, tcblevel)?; + + // Validate TDX Advisories + for advisory in "e_verification_result.advisories { + Self::check_policy( + attestation_policy.tdx_allowed_advisory_ids.as_deref(), + advisory, + "mrsigner", + )?; + } + + // Build combined TDX MR and validate + let tdx_mr = Self::build_tdx_mr([ + &report_body.mr_td, + &report_body.rt_mr0, + &report_body.rt_mr1, + &report_body.rt_mr2, + &report_body.rt_mr3, + ]); + + Self::check_policy_hash(attestation_policy.tdx_mrs.as_deref(), &tdx_mr, "tdxmr") + } + Report::TD15(report_body) => { + // Validate TCB level + Self::validate_tcb_level(&attestation_policy.tdx_allowed_tcb_levels, tcblevel)?; + + // Validate TDX Advisories + for advisory in "e_verification_result.advisories { + Self::check_policy( + attestation_policy.tdx_allowed_advisory_ids.as_deref(), + advisory, + "advisories", + )?; + } + + // Build combined TDX MR and validate + let tdx_mr = Self::build_tdx_mr([ + &report_body.base.mr_td, + &report_body.base.rt_mr0, + &report_body.base.rt_mr1, + &report_body.base.rt_mr2, + &report_body.base.rt_mr3, + ]); + + Self::check_policy_hash(attestation_policy.tdx_mrs.as_deref(), &tdx_mr, "tdxmr") + } + _ => Err(Error::policy_violation("Unknown quote report format")), + } + } + + /// Helper method to validate TCB levels + fn validate_tcb_level( + allowed_levels: &EnumSet, + actual_level: TcbLevel, + ) -> Result<()> { + if !allowed_levels.contains(actual_level) { + let error_msg = format!( + "Quote verification failed: TCB level mismatch (expected one of: {:?}, actual: {})", + allowed_levels, actual_level + ); + return Err(Error::policy_violation(error_msg)); + } + Ok(()) + } + + /// Helper method to build combined TDX measurement register + fn build_tdx_mr(parts: [&[u8]; N]) -> Vec { + parts.into_iter().flatten().cloned().collect() + } + + /// Check if a policy value matches the actual value + fn check_policy(policy: Option<&[String]>, actual_value: &str, field_name: &str) -> Result<()> { + if let Some(valid_values) = policy { + if !valid_values.iter().any(|value| value == actual_value) { + let error_msg = + format!( + "Quote verification failed: {} mismatch (expected one of: [ {} ], actual: {})", + field_name, valid_values.join(", "), actual_value + ); + return Err(Error::policy_violation(error_msg)); + } + + tracing::debug!(field_name, actual_value, "Attestation policy check passed"); + } + + Ok(()) + } + + fn check_policy_hash( + policy: Option<&[Bytes]>, + actual_value: &[u8], + field_name: &str, + ) -> Result<()> { + if let Some(valid_values) = policy { + let actual_value = Bytes::copy_from_slice(actual_value); + if !valid_values.contains(&actual_value) { + let valid_values = valid_values + .iter() + .map(hex::encode) + .collect::>() + .join(", "); + let error_msg = format!( + "Quote verification failed: {} mismatch (expected one of: [ {} ], actual: {:x})", + field_name, valid_values, actual_value + ); + return Err(Error::policy_violation(error_msg)); + } + + tracing::debug!( + field_name, + actual_value = format!("{actual_value:x}"), + "Attestation policy check passed" + ); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_check_policy() { + // Test with no policy (should pass) + PolicyEnforcer::check_policy_hash(None, &[1, 2, 3], "test").unwrap(); + + // Test with matching policy + let actual_value: Bytes = hex::decode("01020304").unwrap().into(); + PolicyEnforcer::check_policy_hash( + Some(vec![actual_value.clone()]).as_deref(), + &actual_value, + "test", + ) + .unwrap(); + + //.clone() Test with matching policy (multiple values) + PolicyEnforcer::check_policy_hash( + Some(vec![ + "aabbcc".into(), + "01020304".into(), + "ddeeff".into(), + actual_value.clone(), + ]) + .as_deref(), + &actual_value, + "test", + ) + .unwrap(); + + // Test with non-matching policy + PolicyEnforcer::check_policy_hash( + Some(vec!["aabbcc".into(), "ddeeff".into()]).as_deref(), + &actual_value, + "test", + ) + .unwrap_err(); + } +} diff --git a/bin/verify-era-proof-attestation/src/verification/reporting.rs b/bin/verify-era-proof-attestation/src/verification/reporting.rs new file mode 100644 index 0000000..6c1b7aa --- /dev/null +++ b/bin/verify-era-proof-attestation/src/verification/reporting.rs @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use teepot::quote::{tcblevel::TcbLevel, QuoteVerificationResult}; + +/// Handles reporting and logging of verification results +pub struct VerificationReporter; + +impl VerificationReporter { + /// Log summary of a quote verification + pub fn log_quote_verification_summary(quote_verification_result: &QuoteVerificationResult) { + let QuoteVerificationResult { + collateral_expired, + result, + quote, + advisories, + .. + } = quote_verification_result; + + if *collateral_expired { + tracing::warn!("Freshly fetched collateral expired!"); + } + + let tcblevel = TcbLevel::from(*result); + let advisories = if advisories.is_empty() { + "None".to_string() + } else { + advisories + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + }; + + tracing::debug!( + "Quote verification result: {tcblevel}. {report}. Advisory IDs: {advisories}.", + report = "e.report + ); + } + + /// Log the results of batch verification + pub fn log_batch_verification_results( + batch_no: u32, + verified_proofs_count: u32, + unverified_proofs_count: u32, + ) { + if unverified_proofs_count > 0 { + if verified_proofs_count == 0 { + tracing::error!( + batch_no, + "All {} proofs failed verification!", + unverified_proofs_count + ); + } else { + tracing::warn!( + batch_no, + "Some proofs failed verification. Unverified proofs: {}. Verified proofs: {}.", + unverified_proofs_count, + verified_proofs_count + ); + } + } else if verified_proofs_count > 0 { + tracing::info!( + batch_no, + "All {} proofs verified successfully!", + verified_proofs_count + ); + } + } + + /// Log overall verification results for multiple batches + pub fn log_overall_verification_results( + verified_batches_count: u32, + unverified_batches_count: u32, + ) { + if unverified_batches_count > 0 { + if verified_batches_count == 0 { + tracing::error!( + "All {} batches failed verification!", + unverified_batches_count + ); + } else { + tracing::error!( + "Some batches failed verification! Unverified batches: {}. Verified batches: {}.", + unverified_batches_count, + verified_batches_count + ); + } + } else { + tracing::info!("{} batches verified successfully!", verified_batches_count); + } + } +} diff --git a/bin/verify-era-proof-attestation/src/verification/signature.rs b/bin/verify-era-proof-attestation/src/verification/signature.rs new file mode 100644 index 0000000..314218a --- /dev/null +++ b/bin/verify-era-proof-attestation/src/verification/signature.rs @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +use secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId, Signature}, + Message, SECP256K1, +}; +use teepot::{ + ethereum::{public_key_to_ethereum_address, recover_signer}, + prover::reportdata::ReportData, + quote::QuoteVerificationResult, +}; +use zksync_basic_types::H256; + +use crate::error; + +const SIGNATURE_LENGTH_WITH_RECOVERY_ID: usize = 65; +const SIGNATURE_LENGTH_WITHOUT_RECOVERY_ID: usize = 64; + +/// Handles verification of signatures in proofs +pub struct SignatureVerifier; + +impl SignatureVerifier { + /// Verify a batch proof signature + pub fn verify_batch_proof( + quote_verification_result: &QuoteVerificationResult, + root_hash: H256, + signature: &[u8], + ) -> error::Result { + let report_data_bytes = quote_verification_result.quote.get_report_data(); + tracing::trace!(?report_data_bytes); + + let report_data = ReportData::try_from(report_data_bytes).map_err(|e| { + error::Error::internal(format!("Could not convert to ReportData: {}", e)) + })?; + + Self::verify(&report_data, &root_hash, signature) + } + + /// Verify signature against report data and root hash + pub fn verify( + report_data: &ReportData, + root_hash: &H256, + signature: &[u8], + ) -> error::Result { + match report_data { + ReportData::V0(report) => Self::verify_v0(report, root_hash, signature), + ReportData::V1(report) => Self::verify_v1(report, root_hash, signature), + ReportData::Unknown(_) => Ok(false), + } + } + + /// Verify a V0 report + fn verify_v0( + report: &teepot::prover::reportdata::ReportDataV0, + root_hash: &H256, + signature: &[u8], + ) -> error::Result { + tracing::debug!("ReportData::V0"); + let signature = Signature::from_compact(signature) + .map_err(|e| error::Error::signature_verification(e.to_string()))?; + let root_hash_msg = Message::from_digest(root_hash.0); + Ok(signature.verify(&root_hash_msg, &report.pubkey).is_ok()) + } + + /// Verify a V1 report + fn verify_v1( + report: &teepot::prover::reportdata::ReportDataV1, + root_hash: &H256, + signature: &[u8], + ) -> error::Result { + tracing::debug!("ReportData::V1"); + let ethereum_address_from_report = report.ethereum_address; + + let root_hash_msg = Message::from_digest( + root_hash + .as_bytes() + .try_into() + .map_err(|_| error::Error::signature_verification("root hash not 32 bytes"))?, + ); + + tracing::trace!("sig len = {}", signature.len()); + + // Try to recover Ethereum address from signature + let ethereum_address_from_signature = match signature.len() { + // Handle 64-byte signature case (missing recovery ID) + SIGNATURE_LENGTH_WITHOUT_RECOVERY_ID => { + SignatureVerifier::recover_address_with_missing_recovery_id( + signature, + &root_hash_msg, + )? + } + // Standard 65-byte signature case + SIGNATURE_LENGTH_WITH_RECOVERY_ID => { + let signature_bytes: [u8; SIGNATURE_LENGTH_WITH_RECOVERY_ID] = + signature.try_into().map_err(|_| { + error::Error::signature_verification( + "Expected 65-byte signature but got a different length", + ) + })?; + + recover_signer(&signature_bytes, &root_hash_msg).map_err(|e| { + error::Error::signature_verification(format!("Failed to recover signer: {}", e)) + })? + } + // Any other length is invalid + len => { + return Err(error::Error::signature_verification(format!( + "Invalid signature length: {len} bytes" + ))) + } + }; + + // Log verification details + tracing::debug!( + "Root hash: {}. Ethereum address from the attestation quote: {}. Ethereum address from the signature: {}.", + root_hash, + hex::encode(ethereum_address_from_report), + hex::encode(ethereum_address_from_signature), + ); + + Ok(ethereum_address_from_signature == ethereum_address_from_report) + } + + /// Helper function to recover Ethereum address when recovery ID is missing + fn recover_address_with_missing_recovery_id( + signature: &[u8], + message: &Message, + ) -> error::Result<[u8; 20]> { + tracing::info!("Signature is missing RecoveryId!"); + + // Try all possible recovery IDs + for rec_id in [ + RecoveryId::Zero, + RecoveryId::One, + RecoveryId::Two, + RecoveryId::Three, + ] { + let Ok(rec_sig) = RecoverableSignature::from_compact(signature, rec_id) else { + continue; + }; + + let Ok(public) = SECP256K1.recover_ecdsa(message, &rec_sig) else { + continue; + }; + + let ethereum_address = public_key_to_ethereum_address(&public); + tracing::info!("Had to use RecoveryId::{rec_id:?}"); + return Ok(ethereum_address); + } + + // No valid recovery ID found + Err(error::Error::signature_verification( + "Could not find valid recovery ID", + )) + } +} diff --git a/crates/teepot/src/quote/tcblevel.rs b/crates/teepot/src/quote/tcblevel.rs index f7b7990..25669f0 100644 --- a/crates/teepot/src/quote/tcblevel.rs +++ b/crates/teepot/src/quote/tcblevel.rs @@ -14,7 +14,9 @@ use std::{ pub use enumset::EnumSet; /// TCB level -#[derive(EnumSetType, Debug)] +#[derive(EnumSetType, Debug, Serialize, Deserialize)] +#[enumset(serialize_repr = "list")] +#[non_exhaustive] pub enum TcbLevel { /// TCB is up to date Ok, From 95b6a2d70a7d1f7f0b01d14f413adf4227209c63 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 7 Apr 2025 08:54:00 +0200 Subject: [PATCH 070/114] refactor(verify-era-proof-attestation): replace watch channel with `CancellationToken` Refactored stop signal handling in all components to use `tokio_util::sync::CancellationToken` instead of `tokio::sync::watch`. - Improved cancellation logic by leveraging `CancellationToken` for cleaner and more efficient handling. - Updated corresponding dependency to `tokio-util` version `0.7.14`. --- Cargo.lock | 5 +++-- bin/verify-era-proof-attestation/Cargo.toml | 1 + bin/verify-era-proof-attestation/src/main.rs | 19 ++++++++++-------- .../src/processor/batch_processor.rs | 12 +++++------ .../src/processor/continuous_processor.rs | 14 +++++-------- .../src/processor/mod.rs | 11 ++++------ .../src/processor/one_shot_processor.rs | 9 +++------ .../src/proof/fetcher.rs | 20 +++++++++---------- .../src/verification/batch.rs | 6 +++--- 9 files changed, 45 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 08b0c8c..9e9d369 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4962,9 +4962,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -5386,6 +5386,7 @@ dependencies = [ "teepot", "thiserror 2.0.11", "tokio", + "tokio-util", "tracing", "tracing-subscriber", "url", diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index 533a3dc..a566639 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -22,6 +22,7 @@ serde_yaml = "0.9.33" teepot.workspace = true thiserror.workspace = true tokio.workspace = true +tokio-util = "0.7.14" tracing.workspace = true tracing-subscriber.workspace = true url.workspace = true diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index 9fa03ae..2f66b43 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -10,15 +10,15 @@ mod processor; mod proof; mod verification; -use clap::Parser; -use error::Result; -use tokio::{signal, sync::watch}; - use crate::{ core::{VerifierConfig, VerifierConfigArgs}, error::Error, processor::ProcessorFactory, }; +use clap::Parser; +use error::Result; +use tokio::signal; +use tokio_util::sync::CancellationToken; #[tokio::main] async fn main() -> Result<()> { @@ -35,14 +35,17 @@ async fn main() -> Result<()> { // Create processor based on config let (processor, mode) = ProcessorFactory::create(config.clone())?; - // Set up stop channel - let (stop_sender, stop_receiver) = watch::channel(false); + // Set up a cancellation Token + let token = CancellationToken::new(); // Log startup information tracing::info!("Starting verification in {}", mode); // Spawn processing task - let mut process_handle = tokio::spawn(async move { processor.run(stop_receiver).await }); + let mut process_handle = { + let token = token.clone(); + tokio::spawn(async move { processor.run(token).await }) + }; // Wait for processing to complete or for stop signal tokio::select! { @@ -77,7 +80,7 @@ async fn main() -> Result<()> { }, _ = signal::ctrl_c() => { tracing::info!("Stop signal received, shutting down gracefully..."); - stop_sender.send(true).ok(); + token.cancel(); // Wait for processor to complete gracefully match process_handle.await { diff --git a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs index f7520c2..c7e8cbf 100644 --- a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs @@ -4,7 +4,7 @@ //! Core functionality for processing individual batches use crate::error; -use tokio::sync::watch; +use tokio_util::sync::CancellationToken; use zksync_basic_types::L1BatchNumber; use crate::{ @@ -41,10 +41,10 @@ impl BatchProcessor { /// Process a single batch and return the verification result pub async fn process_batch( &self, - stop_receiver: &mut watch::Receiver, + token: &CancellationToken, batch_number: L1BatchNumber, ) -> error::Result { - if *stop_receiver.borrow() { + if token.is_cancelled() { tracing::info!("Stop signal received, shutting down"); return Ok(VerificationResult::Interrupted); } @@ -56,7 +56,7 @@ impl BatchProcessor { for tee_type in self.config.args.tee_types.iter() { match self .proof_fetcher - .get_proofs(stop_receiver, batch_number, tee_type) + .get_proofs(token, batch_number, tee_type) .await { Ok(batch_proofs) => proofs.extend(batch_proofs), @@ -81,7 +81,7 @@ impl BatchProcessor { // Verify proofs for the current batch let verification_result = self .batch_verifier - .verify_batch_proofs(stop_receiver, batch_number, proofs) + .verify_batch_proofs(token, batch_number, proofs) .await?; let result = if verification_result.total_count == 0 { @@ -103,7 +103,7 @@ impl BatchProcessor { if !matches!(result, VerificationResult::Interrupted) && self.config.args.rate_limit.as_millis() > 0 { - tokio::time::timeout(self.config.args.rate_limit, stop_receiver.changed()) + tokio::time::timeout(self.config.args.rate_limit, token.cancelled()) .await .ok(); } diff --git a/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs b/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs index 4e66ce0..9796367 100644 --- a/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs @@ -3,7 +3,7 @@ //! Continuous batch processor for ongoing verification of new batches -use tokio::sync::watch; +use tokio_util::sync::CancellationToken; use zksync_basic_types::L1BatchNumber; use crate::{ @@ -32,7 +32,7 @@ impl ContinuousProcessor { /// Run the processor until stopped pub async fn run( &self, - mut stop_receiver: watch::Receiver, + token: &CancellationToken, ) -> error::Result> { tracing::info!( "Starting continuous verification from batch {}", @@ -45,13 +45,9 @@ impl ContinuousProcessor { let mut current_batch = self.start_batch.0; // Continue processing batches until stopped or reaching maximum batch number - while !*stop_receiver.borrow() { + while !token.is_cancelled() { let batch = L1BatchNumber(current_batch); - match self - .batch_processor - .process_batch(&mut stop_receiver, batch) - .await - { + match self.batch_processor.process_batch(token, batch).await { Ok(result) => { match result { VerificationResult::Success => success_count += 1, @@ -64,7 +60,7 @@ impl ContinuousProcessor { VerificationResult::NoProofsFound => { // In continuous mode, we might hit batches that don't have proofs yet // Wait a bit longer before retrying - if !*stop_receiver.borrow() { + if !token.is_cancelled() { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; // Don't increment batch number, try again continue; diff --git a/bin/verify-era-proof-attestation/src/processor/mod.rs b/bin/verify-era-proof-attestation/src/processor/mod.rs index 449f694..75df936 100644 --- a/bin/verify-era-proof-attestation/src/processor/mod.rs +++ b/bin/verify-era-proof-attestation/src/processor/mod.rs @@ -15,7 +15,7 @@ use crate::{ core::{VerificationResult, VerifierConfig, VerifierMode}, error::Result, }; -use tokio::sync::watch; +use tokio_util::sync::CancellationToken; // Using an enum instead of a trait because async functions in traits can't be used in trait objects /// Processor variants for different verification modes @@ -28,13 +28,10 @@ pub enum ProcessorType { impl ProcessorType { /// Run the processor until completion or interruption - pub async fn run( - &self, - stop_receiver: watch::Receiver, - ) -> Result> { + pub async fn run(&self, token: CancellationToken) -> Result> { match self { - ProcessorType::OneShot(processor) => processor.run(stop_receiver).await, - ProcessorType::Continuous(processor) => processor.run(stop_receiver).await, + ProcessorType::OneShot(processor) => processor.run(&token).await, + ProcessorType::Continuous(processor) => processor.run(&token).await, } } } diff --git a/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs b/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs index 469e9de..1bd7d77 100644 --- a/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs @@ -4,7 +4,7 @@ //! One-shot batch processor for verifying a single batch or a range of batches use crate::error; -use tokio::sync::watch; +use tokio_util::sync::CancellationToken; use zksync_basic_types::L1BatchNumber; use crate::{ @@ -38,7 +38,7 @@ impl OneShotProcessor { /// Run the processor until completion or interruption pub async fn run( &self, - mut stop_receiver: watch::Receiver, + token: &CancellationToken, ) -> error::Result> { tracing::info!( "Starting one-shot verification of batches {} to {}", @@ -52,10 +52,7 @@ impl OneShotProcessor { for batch_number in self.start_batch.0..=self.end_batch.0 { let batch = L1BatchNumber(batch_number); - let result = self - .batch_processor - .process_batch(&mut stop_receiver, batch) - .await?; + let result = self.batch_processor.process_batch(token, batch).await?; match result { VerificationResult::Success => success_count += 1, diff --git a/bin/verify-era-proof-attestation/src/proof/fetcher.rs b/bin/verify-era-proof-attestation/src/proof/fetcher.rs index 0a22445..d8d0322 100644 --- a/bin/verify-era-proof-attestation/src/proof/fetcher.rs +++ b/bin/verify-era-proof-attestation/src/proof/fetcher.rs @@ -10,7 +10,7 @@ use crate::{ }, }; use std::time::Duration; -use tokio::sync::watch; +use tokio_util::sync::CancellationToken; use url::Url; use zksync_basic_types::{tee_types::TeeType, L1BatchNumber}; @@ -34,7 +34,7 @@ impl ProofFetcher { /// Get proofs for a batch number with retry logic pub async fn get_proofs( &self, - stop_receiver: &mut watch::Receiver, + token: &CancellationToken, batch_number: L1BatchNumber, tee_type: &TeeType, ) -> Result> { @@ -43,8 +43,8 @@ impl ProofFetcher { let max_backoff = Duration::from_secs(128); let retry_backoff_multiplier: f32 = 2.0; - while !*stop_receiver.borrow() { - match self.send_request(&proofs_request, stop_receiver).await { + while !token.is_cancelled() { + match self.send_request(&proofs_request, token).await { Ok(response) => { // Parse the response using the ProofResponseParser match ProofResponseParser::parse_response(response) { @@ -84,9 +84,7 @@ impl ProofFetcher { } } - tokio::time::timeout(backoff, stop_receiver.changed()) - .await - .ok(); + tokio::time::timeout(backoff, token.cancelled()).await.ok(); backoff = std::cmp::min( Duration::from_millis( @@ -95,13 +93,13 @@ impl ProofFetcher { max_backoff, ); - if *stop_receiver.borrow() { + if token.is_cancelled() { break; } } // If we've reached this point, we've either been stopped or exhausted retries - if *stop_receiver.borrow() { + if token.is_cancelled() { // Return empty vector if stopped Ok(vec![]) } else { @@ -114,7 +112,7 @@ impl ProofFetcher { async fn send_request( &self, request: &GetProofsRequest, - stop_receiver: &mut watch::Receiver, + token: &CancellationToken, ) -> Result { let retry_helper = RetryHelper::new(self.retry_config.clone()); let request_clone = request.clone(); @@ -128,7 +126,7 @@ impl ProofFetcher { .await; // Check if we need to abort due to stop signal - if *stop_receiver.borrow() { + if token.is_cancelled() { return Err(Error::Interrupted); } diff --git a/bin/verify-era-proof-attestation/src/verification/batch.rs b/bin/verify-era-proof-attestation/src/verification/batch.rs index 53c3438..5542f05 100644 --- a/bin/verify-era-proof-attestation/src/verification/batch.rs +++ b/bin/verify-era-proof-attestation/src/verification/batch.rs @@ -8,7 +8,7 @@ use crate::{ proof::Proof, verification::{AttestationVerifier, PolicyEnforcer, SignatureVerifier, VerificationReporter}, }; -use tokio::sync::watch; +use tokio_util::sync::CancellationToken; use zksync_basic_types::L1BatchNumber; /// Result of a batch verification @@ -40,7 +40,7 @@ impl BatchVerifier { /// Verify proofs for a batch pub async fn verify_batch_proofs( &self, - stop_receiver: &mut watch::Receiver, + token: &CancellationToken, batch_number: L1BatchNumber, proofs: Vec, ) -> error::Result { @@ -49,7 +49,7 @@ impl BatchVerifier { let mut verified_proofs_count: u32 = 0; for proof in proofs.into_iter() { - if *stop_receiver.borrow() { + if token.is_cancelled() { tracing::warn!("Stop signal received during batch verification"); return Ok(BatchVerificationResult { total_count: total_proofs_count, From eb39705ff1bbe2104885a55a7bf27ed6df9c26c2 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Thu, 20 Mar 2025 10:25:24 +0100 Subject: [PATCH 071/114] feat: compat code for non `x86_64-linux` - do not build packages, which require `x86_64-linux` - use Phala `dcap-qvl` crate for remote attestation, if possible - nix: exclude `nixsgx` on non `x86_64-linux` platforms Signed-off-by: Harald Hoyer --- .github/workflows/nix-non-x86.yml | 38 ++ Cargo.lock | 557 ++++++++++++++++-- Cargo.toml | 3 +- bin/rtmr-calc/src/main.rs | 2 +- bin/tdx-extend/src/main.rs | 97 +-- bin/tee-key-preexec/src/main.rs | 36 +- bin/verify-attestation/src/main.rs | 13 +- .../src/verification/attestation.rs | 10 +- .../src/verification/policy.rs | 2 +- .../src/verification/reporting.rs | 5 +- .../Cargo.toml | 10 +- crates/teepot-vault/Cargo.toml | 2 - crates/teepot-vault/src/client/mod.rs | 18 +- crates/teepot-vault/src/client/vault.rs | 7 +- crates/teepot/Cargo.toml | 13 +- crates/teepot/src/pki/mod.rs | 5 +- crates/teepot/src/quote/attestation.rs | 12 +- crates/teepot/src/quote/error.rs | 53 +- crates/teepot/src/quote/intel.rs | 260 ++++++++ crates/teepot/src/quote/mod.rs | 166 ++---- crates/teepot/src/quote/phala.rs | 259 ++++++++ crates/teepot/src/quote/tcblevel.rs | 40 +- crates/teepot/src/sgx/mod.rs | 3 +- crates/teepot/src/tdx/mod.rs | 36 +- crates/teepot/src/tdx/rtmr.rs | 14 +- crates/teepot/tests/sgx_quote_verification.rs | 51 +- deny.toml | 1 + .../default.nix | 2 + packages/container-tdx-test/default.nix | 50 +- .../default.nix | 2 + .../default.nix | 2 + packages/container-vault-admin/default.nix | 2 + .../container-vault-sgx-azure/default.nix | 4 +- .../default.nix | 2 + packages/container-vault-unseal/default.nix | 51 +- .../default.nix | 54 +- .../default.nix | 56 +- packages/tdx_google/default.nix | 5 +- packages/teepot/default.nix | 40 +- packages/teepotCrate/default.nix | 10 +- shells/teepot/default.nix | 57 +- 41 files changed, 1531 insertions(+), 519 deletions(-) create mode 100644 .github/workflows/nix-non-x86.yml create mode 100644 crates/teepot/src/quote/intel.rs create mode 100644 crates/teepot/src/quote/phala.rs diff --git a/.github/workflows/nix-non-x86.yml b/.github/workflows/nix-non-x86.yml new file mode 100644 index 0000000..0872032 --- /dev/null +++ b/.github/workflows/nix-non-x86.yml @@ -0,0 +1,38 @@ +name: nix-non-x86 + +permissions: + contents: read + pull-requests: read + +on: + pull_request: + branches: ["main"] + push: + branches: ["main"] + tags: ["*"] + +jobs: + macos-latest: + runs-on: macos-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: cachix/install-nix-action@v31 + with: + extra_nix_config: | + access-tokens = github.com=${{ github.token }} + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= tee-pot:SS6HcrpG87S1M6HZGPsfo7d1xJccCGev7/tXc5+I4jg= + substituters = https://cache.nixos.org/ https://attic.teepot.org/tee-pot + sandbox = true + - name: Setup Attic cache + uses: ryanccn/attic-action@v0 + with: + endpoint: https://attic.teepot.org/ + cache: tee-pot + token: ${{ secrets.ATTIC_TOKEN }} + + - name: nixci + # FIXME: this prevents it from running on macos + # https://github.com/NixOS/nix/pull/12570 + # run: nix run github:nixos/nixpkgs/nixos-24.11#nixci -- build + run: nix build -L .#teepot + diff --git a/Cargo.lock b/Cargo.lock index 9e9d369..0ac592f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.8.5", "sha1", "smallvec", "tokio", @@ -278,7 +278,7 @@ dependencies = [ "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -366,6 +366,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "asn1_der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" + [[package]] name = "async-stream" version = "0.3.6" @@ -448,7 +454,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.8.5", "rustls", "serde", "serde_json", @@ -540,7 +546,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -867,16 +873,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.39" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", - "windows-targets", + "wasm-bindgen", + "windows-link", ] [[package]] @@ -1137,7 +1151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1149,7 +1163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -1269,6 +1283,12 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "data-encoding" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" + [[package]] name = "dbl" version = "0.3.2" @@ -1278,6 +1298,36 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dcap-qvl" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8bc5d87613fe4c0a7a980c3e9113d9f10b9f9404218e19333e0eff2eff4c9a" +dependencies = [ + "anyhow", + "asn1_der", + "base64", + "byteorder", + "chrono", + "const-oid", + "der", + "futures", + "hex", + "log", + "parity-scale-codec", + "pem", + "reqwest", + "ring", + "rustls-webpki", + "scale-info", + "serde", + "serde-human-bytes", + "serde_json", + "tracing", + "urlencoding", + "x509-cert", +] + [[package]] name = "der" version = "0.7.9" @@ -1509,7 +1559,7 @@ dependencies = [ "hkdf", "pem-rfc7468 0.7.0", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1533,6 +1583,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "enumset" version = "1.1.5" @@ -1649,7 +1711,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1666,7 +1728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -1846,8 +1908,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1857,9 +1921,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "wasm-bindgen", + "windows-targets 0.52.6", ] [[package]] @@ -1949,7 +2015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -2051,6 +2117,51 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hickory-proto" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2078,6 +2189,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "hostname" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" +dependencies = [ + "cfg-if", + "libc", + "windows", +] + [[package]] name = "http" version = "0.2.12" @@ -2178,6 +2300,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -2489,6 +2612,18 @@ dependencies = [ "bindgen 0.65.1", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -2670,9 +2805,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.9" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" +checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6" dependencies = [ "http 1.2.0", "serde", @@ -2761,7 +2896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2770,6 +2905,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -2815,6 +2956,15 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2944,7 +3094,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "serde", "smallvec", "zeroize", @@ -3178,7 +3328,7 @@ dependencies = [ "glob", "opentelemetry", "percent-encoding", - "rand", + "rand 0.8.5", "serde_json", "thiserror 2.0.11", "tokio", @@ -3226,7 +3376,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "rand_core", + "rand_core 0.6.4", "sha2", ] @@ -3278,7 +3428,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3288,7 +3438,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -3329,6 +3479,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -3404,7 +3564,7 @@ dependencies = [ "p256", "p384", "p521", - "rand", + "rand 0.8.5", "ripemd", "rsa", "sha1", @@ -3502,7 +3662,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -3601,6 +3761,60 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "quinn" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" +dependencies = [ + "bytes", + "getrandom 0.3.1", + "rand 0.9.0", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.38" @@ -3623,8 +3837,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.24", ] [[package]] @@ -3634,7 +3859,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -3646,6 +3881,15 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -3718,6 +3962,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.8", + "hickory-resolver", "http 1.2.0", "http-body", "http-body-util", @@ -3733,7 +3978,10 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -3741,15 +3989,26 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", "tower 0.5.2", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "windows-registry", ] +[[package]] +name = "resolv-conf" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48375394603e3dd4b2d64371f7148fd8c7baa2680e28741f2cb8d23b59e3d4c4" +dependencies = [ + "hostname", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -3806,7 +4065,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sha2", "signature", "spki", @@ -3917,6 +4176,9 @@ name = "rustls-pki-types" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] [[package]] name = "rustls-platform-verifier" @@ -3978,6 +4240,31 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-info" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more 1.0.0", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "schannel" version = "0.1.27" @@ -4023,7 +4310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand", + "rand 0.8.5", "secp256k1-sys 0.10.1", ] @@ -4099,6 +4386,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-human-bytes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ef65cb41f3f9cef63c431193229067e8b98b53c4d4c4ed38a8ca87c4d07676" +dependencies = [ + "hex", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.218" @@ -4116,6 +4413,7 @@ version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ + "indexmap 2.7.1", "itoa", "memchr", "ryu", @@ -4294,7 +4592,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -4339,7 +4637,7 @@ dependencies = [ "futures", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", ] @@ -4626,10 +4924,14 @@ dependencies = [ "async-trait", "base64", "bytemuck", + "bytes", + "chrono", "clap 4.5.30", "config", "const-oid", + "dcap-qvl", "enumset", + "futures", "getrandom 0.3.1", "hex", "num-integer", @@ -4707,9 +5009,7 @@ dependencies = [ "serde_json", "serde_with 3.12.0", "sha2", - "tdx-attest-rs", "teepot", - "teepot-tee-quote-verification-rs", "thiserror 2.0.11", "tracing", "webpki-roots", @@ -4879,6 +5179,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tls_codec" version = "0.4.2" @@ -5049,7 +5364,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand", + "rand 0.8.5", "slab", "tokio", "tokio-util", @@ -5289,6 +5604,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -5541,6 +5862,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.26.8" @@ -5562,6 +5893,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + [[package]] name = "winapi" version = "0.3.9" @@ -5593,15 +5930,31 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-registry" version = "0.2.0" @@ -5610,7 +5963,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -5619,7 +5972,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -5629,7 +5982,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -5638,7 +6000,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -5647,7 +6009,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -5656,28 +6033,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5690,24 +6085,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5723,6 +6142,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wit-bindgen-rt" version = "0.33.0" @@ -5760,7 +6189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] @@ -5821,7 +6250,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -5835,6 +6273,17 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "zerofrom" version = "0.1.5" @@ -5931,7 +6380,7 @@ dependencies = [ "anyhow", "once_cell", "pin-project", - "rand", + "rand 0.8.5", "sha3", "thiserror 1.0.69", "time", @@ -5948,7 +6397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cf4af6d7e83c9ed0422a36c603b8bf84079ab510d295fda74f95ce49f62388" dependencies = [ "anyhow", - "rand", + "rand 0.8.5", "secrecy", "serde", "zksync_basic_types", @@ -5964,7 +6413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f9fa69ef68e6a1955a1d7b33077103fb6d106b560fec0d599c6de268f5be03" dependencies = [ "anyhow", - "rand", + "rand 0.8.5", "thiserror 1.0.69", "zksync_concurrency", ] @@ -5993,7 +6442,7 @@ dependencies = [ "anyhow", "blake2", "hex", - "rand", + "rand 0.8.5", "secp256k1 0.27.0", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 508f166..695755a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = ["crates/*", "bin/*", "crates/teepot-vault/bin/*"] +exclude = ["crates/teepot-tee-quote-verification-rs"] resolver = "2" [profile.release] @@ -30,8 +31,6 @@ enumset = { version = "1.1", features = ["serde"] } getrandom = { version = "0.3.1", features = ["std"] } gpt = "4.0.0" 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.3.0" } -intel-tee-quote-verification-sys = { version = "0.2.1" } num-integer = "0.1.46" num-traits = "0.2.18" opentelemetry = { version = "0.28.0", features = ["default", "logs"] } diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs index c49d95e..7a6cef5 100644 --- a/bin/rtmr-calc/src/main.rs +++ b/bin/rtmr-calc/src/main.rs @@ -12,7 +12,7 @@ use std::{ }; use teepot::{ log::{setup_logging, LogLevelParser}, - tdx::rtmr::UEFI_MARKER_DIGEST_BYTES, + tdx::UEFI_MARKER_DIGEST_BYTES, }; use tracing::{debug, info, level_filters::LevelFilter}; diff --git a/bin/tdx-extend/src/main.rs b/bin/tdx-extend/src/main.rs index 5a43f59..31aca89 100644 --- a/bin/tdx-extend/src/main.rs +++ b/bin/tdx-extend/src/main.rs @@ -6,53 +6,64 @@ #![deny(missing_docs)] #![deny(clippy::all)] -use anyhow::{Context, Result}; -use clap::Parser; -use teepot::{ - log::{setup_logging, LogLevelParser}, - tdx::rtmr::TdxRtmrEvent, - util::pad, -}; -use tracing::{error, level_filters::LevelFilter}; +use tracing::error; -/// Extend a TDX rtmr with a hash digest for measured boot. -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Arguments { - /// digest in hex to extend the rtmr with - #[arg(long)] - digest: String, - /// the number or the rtmr - #[arg(long, default_value = "2")] - rtmr: u64, - /// Log level for the log output. - /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` - #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] - pub log_level: LevelFilter, +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] +mod os { + use anyhow::{Context as _, Result}; + use clap::Parser; + use teepot::{ + log::{setup_logging, LogLevelParser}, + tdx::rtmr::TdxRtmrEvent, + util::pad, + }; + use tracing::level_filters::LevelFilter; + + /// Extend a TDX rtmr with a hash digest for measured boot. + #[derive(Parser, Debug)] + #[command(author, version, about, long_about = None)] + struct Arguments { + /// digest in hex to extend the rtmr with + #[arg(long)] + digest: String, + /// the number or the rtmr + #[arg(long, default_value = "2")] + rtmr: u64, + /// Log level for the log output. + /// Valid values are: `off`, `error`, `warn`, `info`, `debug`, `trace` + #[clap(long, default_value_t = LevelFilter::WARN, value_parser = LogLevelParser)] + pub log_level: LevelFilter, + } + + pub fn main_with_error() -> Result<()> { + let args = Arguments::parse(); + tracing::subscriber::set_global_default(setup_logging( + env!("CARGO_CRATE_NAME"), + &args.log_level, + )?)?; + + // Parse the digest string as a hex array + let digest_bytes = hex::decode(&args.digest).context("Invalid digest format")?; + let extend_data: [u8; 48] = pad(&digest_bytes).context("Invalid digest length")?; + + // Extend the TDX measurement with the extend data + TdxRtmrEvent::default() + .with_extend_data(extend_data) + .with_rtmr_index(args.rtmr) + .extend()?; + + Ok(()) + } } -fn main_with_error() -> Result<()> { - let args = Arguments::parse(); - tracing::subscriber::set_global_default(setup_logging( - env!("CARGO_CRATE_NAME"), - &args.log_level, - )?)?; - - // Parse the digest string as a hex array - let digest_bytes = hex::decode(&args.digest).context("Invalid digest format")?; - let extend_data: [u8; 48] = pad(&digest_bytes).context("Invalid digest length")?; - - // Extend the TDX measurement with the extend data - TdxRtmrEvent::default() - .with_extend_data(extend_data) - .with_rtmr_index(args.rtmr) - .extend()?; - - Ok(()) +#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))] +mod os { + pub fn main_with_error() -> anyhow::Result<()> { + anyhow::bail!("OS or architecture not supported"); + } } - -fn main() -> Result<()> { - let ret = main_with_error(); +fn main() -> anyhow::Result<()> { + let ret = os::main_with_error(); if let Err(e) = &ret { error!(error = %e, "Execution failed"); } diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 5d62361..14c10c3 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -6,21 +6,10 @@ #![deny(missing_docs)] #![deny(clippy::all)] -use anyhow::{Context, Result}; +use anyhow::Result; use clap::Parser; -use secp256k1::{rand, Secp256k1}; -use std::{ffi::OsString, os::unix::process::CommandExt, process::Command}; -use teepot::{ - ethereum::public_key_to_ethereum_address, - prover::reportdata::ReportDataV1, - quote::get_quote, - tdx::rtmr::{TdxRtmrEvent, UEFI_MARKER_DIGEST_BYTES}, -}; +use std::ffi::OsString; use tracing::error; -use tracing_log::LogTracer; -use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; - -const TEE_QUOTE_FILE: &str = "/tmp/tee_quote"; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -33,7 +22,21 @@ struct Args { cmd_args: Vec, } +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] fn main_with_error() -> Result<()> { + use anyhow::Context; + use secp256k1::{rand, Secp256k1}; + use std::{os::unix::process::CommandExt, process::Command}; + use teepot::tdx::rtmr::TdxRtmrEvent; + use teepot::{ + ethereum::public_key_to_ethereum_address, prover::reportdata::ReportDataV1, + quote::get_quote, + }; + use tracing_log::LogTracer; + use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; + + const TEE_QUOTE_FILE: &str = "/tmp/tee_quote"; + LogTracer::init().context("Failed to set logger")?; let subscriber = Registry::default() @@ -54,7 +57,7 @@ fn main_with_error() -> Result<()> { // so that any breach can't generate a new attestation with the expected RTMRs TdxRtmrEvent::default() .with_rtmr_index(3) - .with_extend_data(UEFI_MARKER_DIGEST_BYTES) + .with_extend_data(teepot::tdx::UEFI_MARKER_DIGEST_BYTES) .extend()?; // save quote to file @@ -94,6 +97,11 @@ fn main_with_error() -> Result<()> { }) } +#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))] +fn main_with_error() -> Result<()> { + anyhow::bail!("OS or architecture not supported"); +} + fn main() -> Result<()> { let ret = main_with_error(); if let Err(e) = &ret { diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index 3eee26f..4eb84f1 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -7,10 +7,7 @@ use anyhow::{bail, Context, Result}; use clap::Parser; use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; -use teepot::quote::{ - error, tcblevel::TcbLevel, tee_qv_get_collateral, verify_quote_with_collateral, - QuoteVerificationResult, -}; +use teepot::quote::{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)] @@ -62,10 +59,7 @@ fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result Result error::Result { // Get collateral for the quote - let collateral = QuoteContext::context( - tee_qv_get_collateral(attestation_quote_bytes), - "Failed to get collateral!", - )?; + let collateral = get_collateral(attestation_quote_bytes)?; // Get current time for verification let unix_time: i64 = std::time::SystemTime::now() diff --git a/bin/verify-era-proof-attestation/src/verification/policy.rs b/bin/verify-era-proof-attestation/src/verification/policy.rs index babff24..8130075 100644 --- a/bin/verify-era-proof-attestation/src/verification/policy.rs +++ b/bin/verify-era-proof-attestation/src/verification/policy.rs @@ -19,7 +19,7 @@ impl PolicyEnforcer { quote_verification_result: &QuoteVerificationResult, ) -> Result<()> { let quote = "e_verification_result.quote; - let tcblevel = TcbLevel::from(quote_verification_result.result); + let tcblevel = quote_verification_result.result; match "e.report { Report::SgxEnclave(report_body) => { diff --git a/bin/verify-era-proof-attestation/src/verification/reporting.rs b/bin/verify-era-proof-attestation/src/verification/reporting.rs index 6c1b7aa..638512d 100644 --- a/bin/verify-era-proof-attestation/src/verification/reporting.rs +++ b/bin/verify-era-proof-attestation/src/verification/reporting.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2023-2025 Matter Labs -use teepot::quote::{tcblevel::TcbLevel, QuoteVerificationResult}; +use teepot::quote::QuoteVerificationResult; /// Handles reporting and logging of verification results pub struct VerificationReporter; @@ -11,7 +11,7 @@ impl VerificationReporter { pub fn log_quote_verification_summary(quote_verification_result: &QuoteVerificationResult) { let QuoteVerificationResult { collateral_expired, - result, + result: tcblevel, quote, advisories, .. @@ -21,7 +21,6 @@ impl VerificationReporter { tracing::warn!("Freshly fetched collateral expired!"); } - let tcblevel = TcbLevel::from(*result); let advisories = if advisories.is_empty() { "None".to_string() } else { diff --git a/crates/teepot-tee-quote-verification-rs/Cargo.toml b/crates/teepot-tee-quote-verification-rs/Cargo.toml index 1959c34..b267be8 100644 --- a/crates/teepot-tee-quote-verification-rs/Cargo.toml +++ b/crates/teepot-tee-quote-verification-rs/Cargo.toml @@ -5,10 +5,12 @@ name = "teepot-tee-quote-verification-rs" version = "0.3.0" edition = "2021" license = "BSD-3-Clause" -repository.workspace = true -homepage.workspace = true +repository = "https://github.com/matter-labs/teepot" +homepage = "https://github.com/matter-labs/teepot" description = "Fork of intel-tee-quote-verification-rs" [dependencies] -intel-tee-quote-verification-sys.workspace = true -serde.workspace = true +serde = { version = "1", features = ["derive", "rc"] } + +[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] +intel-tee-quote-verification-sys = { version = "0.2.1" } diff --git a/crates/teepot-vault/Cargo.toml b/crates/teepot-vault/Cargo.toml index 4564c7d..9967d5d 100644 --- a/crates/teepot-vault/Cargo.toml +++ b/crates/teepot-vault/Cargo.toml @@ -17,14 +17,12 @@ clap.workspace = true const-oid.workspace = true futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } hex.workspace = true -intel-tee-quote-verification-rs.workspace = true pgp.workspace = true rustls.workspace = true serde.workspace = true serde_json.workspace = true serde_with.workspace = true sha2.workspace = true -tdx-attest-rs.workspace = true teepot.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/teepot-vault/src/client/mod.rs b/crates/teepot-vault/src/client/mod.rs index 8235f8e..f254fd8 100644 --- a/crates/teepot-vault/src/client/mod.rs +++ b/crates/teepot-vault/src/client/mod.rs @@ -8,13 +8,15 @@ pub mod vault; -use crate::server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}; +use crate::server::{ + attestation::Collateral, + pki::{RaTlsCollateralExtension, RaTlsQuoteExtension}, +}; use actix_web::http::header; use anyhow::Result; use awc::{Client, Connector}; use clap::Args; use const_oid::AssociatedOid; -use intel_tee_quote_verification_rs::Collateral; use rustls::{ client::{ danger::{HandshakeSignatureValid, ServerCertVerifier}, @@ -25,10 +27,9 @@ use rustls::{ }; use sha2::{Digest, Sha256}; use std::{sync::Arc, time, time::Duration}; -pub use teepot::{ - quote::tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, - quote::{verify_quote_with_collateral, QuoteVerificationResult}, - sgx::sgx_ql_qv_result_t, +pub use teepot::quote::{ + tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, + verify_quote_with_collateral, QuoteVerificationResult, }; use teepot::{quote::Report, sgx::Quote}; use tracing::{debug, error, info, trace, warn}; @@ -194,7 +195,7 @@ impl TeeConnection { let QuoteVerificationResult { collateral_expired, - result, + result: tcblevel, quote, advisories, earliest_expiration_date, @@ -206,7 +207,7 @@ impl TeeConnection { return Err(Error::General("TDX quote and not SGX quote".into())); }; - if collateral_expired || result != sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK { + if collateral_expired || tcblevel != TcbLevel::Ok { if collateral_expired { error!( "Collateral is out of date! Expired {}", @@ -218,7 +219,6 @@ impl TeeConnection { ))); } - let tcblevel = TcbLevel::from(result); if self .args .sgx_allowed_tcb_levels diff --git a/crates/teepot-vault/src/client/vault.rs b/crates/teepot-vault/src/client/vault.rs index 462d47d..42cfbae 100644 --- a/crates/teepot-vault/src/client/vault.rs +++ b/crates/teepot-vault/src/client/vault.rs @@ -20,7 +20,6 @@ use awc::{ }; use bytes::Bytes; use futures_core::Stream; -use intel_tee_quote_verification_rs::tee_qv_get_collateral; use rustls::ClientConfig; use serde_json::{json, Value}; use std::{ @@ -28,13 +27,13 @@ use std::{ sync::Arc, time, }; -use teepot::quote::error::QuoteContext; +use teepot::quote::get_collateral; pub use teepot::{ quote::{ tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, verify_quote_with_collateral, QuoteVerificationResult, }, - sgx::{sgx_gramine_get_quote, sgx_ql_qv_result_t, Collateral}, + sgx::{sgx_gramine_get_quote, Collateral}, }; use tracing::{debug, error, info, trace}; @@ -158,7 +157,7 @@ impl VaultConnection { info!("Getting attestation report"); let attestation_url = AuthRequest::URL; let quote = sgx_gramine_get_quote(&self.key_hash).context("Failed to get own quote")?; - let collateral = tee_qv_get_collateral("e).context("Failed to get own collateral")?; + let collateral = get_collateral("e).context("Failed to get own collateral")?; let auth_req = AuthRequest { name: self.name.clone(), diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index 8f960c4..c848a92 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -10,6 +10,15 @@ edition.workspace = true authors.workspace = true repository.workspace = true +[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] +tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } +teepot-tee-quote-verification-rs = { path = "../teepot-tee-quote-verification-rs" } + +[target.'cfg(not(all(target_os = "linux", target_arch = "x86_64")))'.dependencies] +dcap-qvl = "0.2.3" +chrono = "0.4.40" +bytes.workspace = true + [dependencies] anyhow.workspace = true async-trait.workspace = true @@ -18,9 +27,9 @@ clap.workspace = true config.workspace = true const-oid.workspace = true enumset.workspace = true +futures = "0.3.31" getrandom.workspace = true hex.workspace = true -intel-tee-quote-verification-rs.workspace = true num-integer.workspace = true num-traits.workspace = true opentelemetry.workspace = true @@ -39,8 +48,8 @@ serde_json.workspace = true sha2.workspace = true sha3.workspace = true signature.workspace = true -tdx-attest-rs.workspace = true thiserror.workspace = true +tokio.workspace = true tracing.workspace = true tracing-futures.workspace = true tracing-log.workspace = true diff --git a/crates/teepot/src/pki/mod.rs b/crates/teepot/src/pki/mod.rs index bed0cf6..b79f864 100644 --- a/crates/teepot/src/pki/mod.rs +++ b/crates/teepot/src/pki/mod.rs @@ -2,13 +2,12 @@ // Copyright (c) 2023-2025 Matter Labs //! Create a private key and a signed and self-signed certificates -use crate::quote::{error::QuoteContext, get_quote}; +use crate::quote::{get_collateral, get_quote}; use anyhow::{Context, Result}; use const_oid::{ db::rfc5280::{ID_KP_CLIENT_AUTH, ID_KP_SERVER_AUTH}, AssociatedOid, }; -use intel_tee_quote_verification_rs::tee_qv_get_collateral; use p256::{ecdsa::DerSignature, pkcs8::EncodePrivateKey}; use pkcs8::der; use rustls::pki_types::PrivatePkcs8KeyDer; @@ -148,7 +147,7 @@ pub fn make_self_signed_cert( debug!("quote.len: {:?}", quote.len()); // Create a relative distinguished name. let rdns = RdnSequence::from_str(dn)?; - let collateral = tee_qv_get_collateral("e).context("Failed to get own collateral")?; + let collateral = get_collateral("e).context("Failed to get own collateral")?; let mut serial = [0u8; 16]; getrandom::fill(&mut serial)?; diff --git a/crates/teepot/src/quote/attestation.rs b/crates/teepot/src/quote/attestation.rs index a41c8de..4f00065 100644 --- a/crates/teepot/src/quote/attestation.rs +++ b/crates/teepot/src/quote/attestation.rs @@ -4,13 +4,11 @@ //! Common attestation API for all TEEs use crate::quote::{ - error::QuoteContext, - get_quote, + get_collateral, get_quote, tcblevel::{EnumSet, TcbLevel}, verify_quote_with_collateral, Collateral, QuoteVerificationResult, }; use anyhow::{bail, Context, Result}; -use intel_tee_quote_verification_rs::tee_qv_get_collateral; use serde::{Deserialize, Serialize}; use std::{ sync::{Arc, RwLock}, @@ -46,8 +44,7 @@ pub fn get_quote_and_collateral( static ATTESTATION: RwLock> = RwLock::new(None); let unix_time: i64 = std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() + .duration_since(UNIX_EPOCH)? .as_secs() as _; if let Some(attestation) = ATTESTATION.read().unwrap().as_ref() { @@ -65,11 +62,11 @@ pub fn get_quote_and_collateral( } let (_tee_type, myquote) = get_quote(report_data).context("Failed to get own quote")?; - let collateral = tee_qv_get_collateral(&myquote).context("Failed to get own collateral")?; + let collateral = get_collateral(&myquote).context("Failed to get own collateral")?; let QuoteVerificationResult { collateral_expired, - result, + result: tcblevel, earliest_expiration_date, tcb_level_date_tag, quote, @@ -83,7 +80,6 @@ pub fn get_quote_and_collateral( bail!("Freshly fetched collateral expired"); } - let tcblevel = TcbLevel::from(result); if tcblevel != TcbLevel::Ok && allowed_tcb_levels.map_or(false, |levels| !levels.contains(tcblevel)) { diff --git a/crates/teepot/src/quote/error.rs b/crates/teepot/src/quote/error.rs index 508b5f3..b469161 100644 --- a/crates/teepot/src/quote/error.rs +++ b/crates/teepot/src/quote/error.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs //! Quote Error type -use intel_tee_quote_verification_rs::quote3_error_t; use std::io; +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] use tdx_attest_rs::tdx_attest_error_t; use thiserror::Error; @@ -22,8 +22,7 @@ pub enum QuoteError { InvalidTeeType, #[error("unsupported body type")] UnsupportedBodyType, - #[error("quote verification error {msg}: {inner:?}")] - Quote3Error { inner: quote3_error_t, msg: String }, + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] #[error("tdx_att_get_quote error {msg}: {inner:?}")] TdxAttGetQuote { inner: tdx_attest_error_t, @@ -35,8 +34,31 @@ pub enum QuoteError { ReportDataSize, #[error("can't get a quote: unknown TEE")] UnknownTee, + #[error("{0}: invalid parameter")] + InvalidParameter(String), + #[error("{0}: platform lib unavailable")] + PlatformLibUnavailable(String), + #[error("{0}: pck cert chain error")] + PckCertChainError(String), + #[error("{0}: pck cert unsupported format")] + PckCertUnsupportedFormat(String), + #[error("{0}: quote format unsupported")] + QuoteFormatUnsupported(String), + #[error("{0}: out of memory")] + OutOfMemory(String), + #[error("{0}: no quote collateral data")] + NoQuoteCollateralData(String), + #[error("{0}: unexpected error")] + Unexpected(String), + #[error("{0}: quote certification data unsupported")] + QuoteCertificationDataUnsupported(String), + #[error("{0}: unable to generate report")] + UnableToGenerateReport(String), + #[error("{0}: CRL unsupported format")] + CrlUnsupportedFormat(String), } +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] impl From for QuoteError { fn from(code: tdx_attest_error_t) -> Self { Self::TdxAttGetQuote { @@ -64,16 +86,29 @@ impl QuoteContext for Result { } } -impl QuoteContext for Result { +impl QuoteContext for Option { type Ok = T; fn context>(self, msg: I) -> Result { - self.map_err(|e| QuoteError::Quote3Error { - msg: msg.into(), - inner: e, - }) + self.ok_or(QuoteError::Unexpected(msg.into())) } } +/// Usability trait for easy QuoteError annotation +pub trait QuoteContextErr { + /// The Ok Type + type Ok; + /// The Context + fn str_context(self, msg: I) -> Result; +} + +impl QuoteContextErr for Result { + type Ok = T; + fn str_context(self, msg: I) -> Result { + self.map_err(|e| QuoteError::Unexpected(format!("{}: {}", msg, e))) + } +} + +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] impl QuoteContext for Result { type Ok = T; fn context>(self, msg: I) -> Result { diff --git a/crates/teepot/src/quote/intel.rs b/crates/teepot/src/quote/intel.rs new file mode 100644 index 0000000..fbbaf0b --- /dev/null +++ b/crates/teepot/src/quote/intel.rs @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +//! Drive Intel DCAP verification crate, which is using the C library + +use crate::{ + quote::{ + error::QuoteError, tcblevel::TcbLevel, Collateral, Quote, QuoteVerificationResult, TEEType, + }, + sgx::sgx_gramine_get_quote, +}; +use bytemuck::cast_slice; +use std::{ffi::CStr, mem, mem::MaybeUninit, pin::Pin}; +use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; +use teepot_tee_quote_verification_rs::{ + quote3_error_t as _quote3_error_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, + tee_get_supplemental_data_version_and_size, tee_qv_get_collateral, tee_supp_data_descriptor_t, + tee_verify_quote, Collateral as IntelCollateral, +}; +use tracing::{trace, warn}; + +/// Convert SGX QV result to our TcbLevel enum +fn convert_tcb_level(value: sgx_ql_qv_result_t) -> TcbLevel { + match value { + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => TcbLevel::Ok, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE => TcbLevel::OutOfDate, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => { + TcbLevel::OutOfDateConfigNeeded + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => TcbLevel::SwHardeningNeeded, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { + TcbLevel::ConfigAndSwHardeningNeeded + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED => TcbLevel::ConfigNeeded, + _ => TcbLevel::Invalid, + } +} + +/// Convert quote3_error_t to QuoteError with context +fn convert_quote_error(error: _quote3_error_t, context: impl Into) -> QuoteError { + let context = context.into(); + match error { + _quote3_error_t::SGX_QL_ERROR_INVALID_PARAMETER => QuoteError::InvalidParameter(context), + _quote3_error_t::SGX_QL_PCK_CERT_CHAIN_ERROR => QuoteError::PckCertChainError(context), + _quote3_error_t::SGX_QL_PCK_CERT_UNSUPPORTED_FORMAT => { + QuoteError::PckCertUnsupportedFormat(context) + } + _quote3_error_t::SGX_QL_QUOTE_FORMAT_UNSUPPORTED => { + QuoteError::QuoteFormatUnsupported(context) + } + _quote3_error_t::SGX_QL_ERROR_OUT_OF_MEMORY => QuoteError::OutOfMemory(context), + _quote3_error_t::SGX_QL_NO_QUOTE_COLLATERAL_DATA => { + QuoteError::NoQuoteCollateralData(context) + } + _quote3_error_t::SGX_QL_ERROR_UNEXPECTED => QuoteError::Unexpected(context), + _quote3_error_t::SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED => { + QuoteError::QuoteCertificationDataUnsupported(context) + } + _quote3_error_t::SGX_QL_UNABLE_TO_GENERATE_REPORT => { + QuoteError::UnableToGenerateReport(context) + } + _quote3_error_t::SGX_QL_CRL_UNSUPPORTED_FORMAT => QuoteError::CrlUnsupportedFormat(context), + _ => QuoteError::Unexpected(context), + } +} + +/// Convert internal Collateral type to Intel library Collateral type +fn convert_to_intel_collateral(collateral: &Collateral) -> IntelCollateral { + IntelCollateral { + major_version: collateral.major_version, + minor_version: collateral.minor_version, + tee_type: collateral.tee_type, + pck_crl_issuer_chain: collateral.pck_crl_issuer_chain.clone(), + root_ca_crl: collateral.root_ca_crl.clone(), + pck_crl: collateral.pck_crl.clone(), + tcb_info_issuer_chain: collateral.tcb_info_issuer_chain.clone(), + tcb_info: collateral.tcb_info.clone(), + qe_identity_issuer_chain: collateral.qe_identity_issuer_chain.clone(), + qe_identity: collateral.qe_identity.clone(), + } +} + +/// Get collateral data for a quote +pub fn get_collateral(quote: &[u8]) -> Result { + let collateral = tee_qv_get_collateral(quote) + .map_err(|e| convert_quote_error(e, "tee_qv_get_collateral"))?; + + Ok(Collateral { + major_version: collateral.major_version, + minor_version: collateral.minor_version, + tee_type: collateral.tee_type, + pck_crl_issuer_chain: collateral.pck_crl_issuer_chain, + root_ca_crl: collateral.root_ca_crl, + pck_crl: collateral.pck_crl, + tcb_info_issuer_chain: collateral.tcb_info_issuer_chain, + tcb_info: collateral.tcb_info, + qe_identity_issuer_chain: collateral.qe_identity_issuer_chain, + qe_identity: collateral.qe_identity, + }) +} + +/// Extract advisory information from supplemental data +fn extract_supplemental_data_info(supp_data: sgx_ql_qv_supplemental_t) -> (Vec, i64, i64) { + // Convert to valid UTF-8 string + let advisories = CStr::from_bytes_until_nul(cast_slice(&supp_data.sa_list[..])) + .ok() + .and_then(|s| CStr::to_str(s).ok()) + .into_iter() + .flat_map(|s| s.split(',').map(str::trim).map(String::from)) + .filter(|s| !s.is_empty()) + .collect(); + + ( + advisories, + supp_data.earliest_expiration_date, + supp_data.tcb_level_date_tag, + ) +} + +/// Verifies a quote with optional collateral material +pub(crate) fn verify_quote_with_collateral( + quote: &[u8], + collateral: Option<&crate::quote::Collateral>, + current_time: i64, +) -> Result { + // Convert collateral if provided + let intel_collateral = collateral.map(convert_to_intel_collateral); + + let TeeSuppDataDescriptor { + supp_data, + mut supp_data_descriptor, + } = initialize_supplemental_data(quote)?; + + let (collateral_expiration_status, result) = tee_verify_quote( + quote, + intel_collateral.as_ref(), + current_time, + None, + supp_data_descriptor.as_mut(), + ) + .map_err(|e| convert_quote_error(e, "tee_verify_quote"))?; + + // Extract supplemental data if available + let (advisories, earliest_expiration_date, tcb_level_date_tag) = + if supp_data_descriptor.is_some() { + let supp_data = unsafe { supp_data.assume_init() }; + extract_supplemental_data_info(supp_data) + } else { + (vec![], 0, 0) + }; + + let quote = Quote::parse(quote)?; + + Ok(QuoteVerificationResult { + collateral_expired: collateral_expiration_status != 0, + earliest_expiration_date, + tcb_level_date_tag, + result: convert_tcb_level(result), + quote, + advisories, + }) +} + +struct TeeSuppDataDescriptor { + supp_data: Pin>>, + supp_data_descriptor: Option, +} + +fn initialize_supplemental_data(quote: &[u8]) -> Result { + let mut supp_data = Box::pin(mem::MaybeUninit::zeroed()); + let mut supp_data_desc = tee_supp_data_descriptor_t { + major_version: 0, + data_size: 0, + p_data: supp_data.as_mut_ptr() as *mut u8, + }; + trace!("tee_get_supplemental_data_version_and_size"); + let (_, supp_size) = tee_get_supplemental_data_version_and_size(quote) + .map_err(|e| convert_quote_error(e, "tee_get_supplemental_data_version_and_size"))?; + + trace!( + "tee_get_supplemental_data_version_and_size supp_size: {}", + supp_size + ); + + let p_supplemental_data = if supp_size == mem::size_of::() as u32 { + supp_data_desc.data_size = supp_size; + Some(supp_data_desc) + } else { + supp_data_desc.data_size = 0; + trace!( + "tee_get_supplemental_data_version_and_size supp_size: {}", + supp_size + ); + trace!( + "mem::size_of::(): {}", + mem::size_of::() + ); + warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you install DCAP QVL and QvE from the same release."); + None + }; + + Ok(TeeSuppDataDescriptor { + supp_data, + supp_data_descriptor: p_supplemental_data, + }) +} + +/// Prepare report data for quote generation +fn prepare_report_data(report_data: &[u8]) -> Result<[u8; 64], QuoteError> { + if report_data.len() > 64 { + return Err(QuoteError::ReportDataSize); + } + + let mut report_data_fixed = [0u8; 64]; + report_data_fixed[..report_data.len()].copy_from_slice(report_data); + Ok(report_data_fixed) +} + +/// Get a TDX quote +fn tdx_get_quote(report_data_bytes: &[u8; 64]) -> Result, QuoteError> { + let mut tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; + tdx_report_data.d.copy_from_slice(report_data_bytes); + + let (error, quote) = tdx_att_get_quote(Some(&tdx_report_data), None, None, 0); + + if error == tdx_attest_error_t::TDX_ATTEST_SUCCESS { + if let Some(quote) = quote { + Ok(quote.into()) + } else { + Err(QuoteError::TdxAttGetQuote { + msg: "tdx_att_get_quote: No quote returned".into(), + inner: error, + }) + } + } else { + Err(error.into()) + } +} + +/// Detect the TEE environment +fn detect_tee_environment() -> Result { + if std::fs::metadata("/dev/attestation").is_ok() { + Ok(TEEType::SGX) + } else if std::fs::metadata("/dev/tdx_guest").is_ok() { + Ok(TEEType::TDX) + } else { + Err(QuoteError::UnknownTee) + } +} + +/// Get the attestation quote from a TEE +pub(crate) fn get_quote(report_data: &[u8]) -> Result<(TEEType, Box<[u8]>), QuoteError> { + let report_data_fixed = prepare_report_data(report_data)?; + + match detect_tee_environment()? { + TEEType::SGX => Ok((TEEType::SGX, sgx_gramine_get_quote(&report_data_fixed)?)), + TEEType::TDX => Ok((TEEType::TDX, tdx_get_quote(&report_data_fixed)?)), + _ => Err(QuoteError::UnknownTee), // For future TEE types + } +} diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 321aa08..8a373cf 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -10,27 +10,25 @@ pub mod attestation; pub mod error; pub mod tcblevel; -use crate::{ - quote::error::{QuoteContext as _, QuoteError}, - sgx::sgx_gramine_get_quote, - tdx::tgx_get_quote, -}; -use bytemuck::{cast_slice, AnyBitPattern}; -use intel_tee_quote_verification_rs::{ - sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, tee_get_supplemental_data_version_and_size, - tee_supp_data_descriptor_t, tee_verify_quote, Collateral, +#[cfg_attr(all(target_os = "linux", target_arch = "x86_64"), path = "intel.rs")] +#[cfg_attr( + not(all(target_os = "linux", target_arch = "x86_64")), + path = "phala.rs" +)] +mod os; + +use crate::quote::{ + error::{QuoteContext as _, QuoteError}, + tcblevel::TcbLevel, }; +use bytemuck::AnyBitPattern; use serde::{Deserialize, Serialize}; use std::{ - ffi::CStr, fmt::{Display, Formatter}, io::Read, - mem, str::FromStr, }; -use tracing::{trace, warn}; - -pub use intel_tee_quote_verification_rs::tee_qv_get_collateral; +use tracing::trace; #[allow(missing_docs)] pub const TEE_TYPE_SGX: u32 = 0x00000000; @@ -603,35 +601,13 @@ impl FromStr for TEEType { /// Get the attestation quote from a TEE pub fn get_quote(report_data: &[u8]) -> Result<(TEEType, Box<[u8]>), QuoteError> { - // check, if we are running in a TEE - if std::fs::metadata("/dev/attestation").is_ok() { - if report_data.len() > 64 { - return Err(QuoteError::ReportDataSize); - } - - let mut report_data_fixed = [0u8; 64]; - report_data_fixed[..report_data.len()].copy_from_slice(report_data); - - Ok((TEEType::SGX, sgx_gramine_get_quote(&report_data_fixed)?)) - } else if std::fs::metadata("/dev/tdx_guest").is_ok() { - if report_data.len() > 64 { - return Err(QuoteError::ReportDataSize); - } - - let mut report_data_fixed = [0u8; 64]; - report_data_fixed[..report_data.len()].copy_from_slice(report_data); - - Ok((TEEType::TDX, tgx_get_quote(&report_data_fixed)?)) - } else { - // if not, return an error - Err(QuoteError::UnknownTee) - } + os::get_quote(report_data) } /// The result of the quote verification pub struct QuoteVerificationResult { /// the raw result - pub result: sgx_ql_qv_result_t, + pub result: TcbLevel, /// indicates if the collateral is expired pub collateral_expired: bool, /// the earliest expiration date of the collateral @@ -644,93 +620,41 @@ pub struct QuoteVerificationResult { pub quote: Quote, } +/// The collateral data needed to do remote attestation for SGX and TDX +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Collateral { + /// Major version of the collateral data + pub major_version: u16, + /// Minor version of the collateral data + pub minor_version: u16, + /// Type of TEE (SGX=0, TDX=0x81) + pub tee_type: u32, + /// The PCK CRL issuer chain used for validating the PCK CRL + pub pck_crl_issuer_chain: Box<[u8]>, + /// The root CA CRL used for validating the PCK CRL issuer chain + pub root_ca_crl: Box<[u8]>, + /// The PCK CRL used for validating the PCK certificate + pub pck_crl: Box<[u8]>, + /// The TCB info issuer chain used for validating the TCB info + pub tcb_info_issuer_chain: Box<[u8]>, + /// The TCB info used for determining the TCB level + pub tcb_info: Box<[u8]>, + /// The QE identity issuer chain used for validating the QE identity + pub qe_identity_issuer_chain: Box<[u8]>, + /// The QE identity used for validating the QE + pub qe_identity: Box<[u8]>, +} + +/// Get the collateral data from an SGX or TDX quote +pub fn get_collateral(quote: &[u8]) -> Result { + os::get_collateral(quote) +} + /// Verifies a quote with optional collateral material pub fn verify_quote_with_collateral( quote: &[u8], collateral: Option<&Collateral>, current_time: i64, ) -> Result { - let mut supp_data: mem::MaybeUninit = mem::MaybeUninit::zeroed(); - let mut supp_data_desc = tee_supp_data_descriptor_t { - major_version: 0, - data_size: 0, - p_data: supp_data.as_mut_ptr() as *mut u8, - }; - trace!("tee_get_supplemental_data_version_and_size"); - let (_, supp_size) = - tee_get_supplemental_data_version_and_size(quote).map_err(|e| QuoteError::Quote3Error { - msg: "tee_get_supplemental_data_version_and_size".into(), - inner: e, - })?; - - trace!( - "tee_get_supplemental_data_version_and_size supp_size: {}", - supp_size - ); - - if supp_size == mem::size_of::() as u32 { - supp_data_desc.data_size = supp_size; - } else { - supp_data_desc.data_size = 0; - trace!( - "tee_get_supplemental_data_version_and_size supp_size: {}", - supp_size - ); - trace!( - "mem::size_of::(): {}", - mem::size_of::() - ); - warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you installed DCAP QVL and QvE from same release.") - } - - let p_supplemental_data = match supp_data_desc.data_size { - 0 => None, - _ => Some(&mut supp_data_desc), - }; - - let has_sup = p_supplemental_data.is_some(); - - trace!("tee_verify_quote"); - - let (collateral_expiration_status, result) = - tee_verify_quote(quote, collateral, current_time, None, p_supplemental_data) - .context("tee_verify_quote")?; - - trace!("tee_verify_quote end"); - - // check supplemental data if necessary - let (advisories, earliest_expiration_date, tcb_level_date_tag) = if has_sup { - unsafe { - let supp_data = supp_data.assume_init(); - // convert to valid UTF-8 string - let ads = CStr::from_bytes_until_nul(cast_slice(&supp_data.sa_list[..])) - .ok() - .and_then(|s| CStr::to_str(s).ok()) - .into_iter() - .flat_map(|s| s.split(',').map(str::trim).map(String::from)) - .filter(|s| !s.is_empty()) - .collect(); - ( - ads, - supp_data.earliest_expiration_date, - supp_data.tcb_level_date_tag, - ) - } - } else { - (vec![], 0, 0) - }; - - trace!("Quote::parse"); - let quote = Quote::parse(quote)?; - - let res = QuoteVerificationResult { - collateral_expired: collateral_expiration_status != 0, - earliest_expiration_date, - tcb_level_date_tag, - result, - quote, - advisories, - }; - - Ok(res) + os::verify_quote_with_collateral(quote, collateral, current_time) } diff --git a/crates/teepot/src/quote/phala.rs b/crates/teepot/src/quote/phala.rs new file mode 100644 index 0000000..e416110 --- /dev/null +++ b/crates/teepot/src/quote/phala.rs @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2025 Matter Labs + +//! Emulate Intel DCAP library collateral and verification + +use crate::quote::{ + error::{QuoteContext, QuoteContextErr, QuoteError}, + tcblevel::TcbLevel, + Collateral, Quote, QuoteVerificationResult, TEEType, +}; +use bytes::Bytes; +use dcap_qvl::{verify::VerifiedReport, QuoteCollateralV3}; +use std::ffi::{CStr, CString}; +use std::str::FromStr; + +/// Helper function to extract a required header value from a response +fn extract_header_value( + response: &reqwest::Response, + header_name: &str, +) -> Result { + response + .headers() + .get(header_name) + .ok_or_else(|| QuoteError::Unexpected(format!("Missing required header: {header_name}")))? + .to_str() + .map_err(|e| QuoteError::Unexpected(format!("Invalid header value: {e}"))) + .map(|val| val.to_string()) +} + +/// Fetch collateral data from Intel's Provisioning Certification Service +async fn fetch_pcs_collateral( + quote: &[u8], +) -> Result<(QuoteCollateralV3, String, Bytes), QuoteError> { + let client = reqwest::Client::new(); + let response = client + .get("https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform") + .send() + .await + .map_err(|e| QuoteError::Unexpected(format!("Failed to fetch collateral: {e}")))?; + + // Extract required fields + let issuer_chain = extract_header_value(&response, "SGX-PCK-CRL-Issuer-Chain")?; + let pck_crl_data = response + .bytes() + .await + .map_err(|e| QuoteError::Unexpected(format!("Failed to fetch collateral data: {e}")))?; + + // Fetch the full collateral + dcap_qvl::collateral::get_collateral_from_pcs(quote, std::time::Duration::from_secs(1000)) + .await + .map(|collateral| (collateral, issuer_chain, pck_crl_data)) + .str_context("Fetching PCS collateral with `get_collateral_from_pcs`") +} + +/// Get collateral for a quote, handling the async operations +pub(crate) fn get_collateral(quote: &[u8]) -> Result { + // Execute the async operation in a separate thread + let result = std::thread::scope(|s| { + s.spawn(|| { + // Create a minimal runtime for this thread only + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .context("Failed to build tokio runtime")?; + + // Run the async function + rt.block_on(fetch_pcs_collateral(quote)) + }) + .join() + .map_err(|_| QuoteError::Unexpected("Thread panic in get_collateral".into())) + })??; + + // Destructure the result + let (collateral, pck_crl, pck_issuer_chain) = result; + + // Convert QuoteCollateralV3 to Collateral + convert_to_collateral(collateral, pck_crl, pck_issuer_chain) +} + +// Helper function to convert QuoteCollateralV3 to Collateral +fn convert_to_collateral( + collateral: QuoteCollateralV3, + pck_crl: String, + pck_issuer_chain: Bytes, +) -> Result { + let QuoteCollateralV3 { + tcb_info_issuer_chain, + tcb_info, + tcb_info_signature, + qe_identity_issuer_chain, + qe_identity, + qe_identity_signature, + } = collateral; + + let tcb_info_signature = hex::encode(tcb_info_signature); + let qe_identity_signature = hex::encode(qe_identity_signature); + + // Create strings with proper formatting + let tcb_info_json = + format!("{{ \"tcbInfo\": {tcb_info}, \"signature\": \"{tcb_info_signature}\" }}"); + + let qe_identity_json = format!( + "{{ \"enclaveIdentity\": {qe_identity}, \"signature\": \"{qe_identity_signature}\" }}" + ); + + // Helper to create CString and convert to Box<[u8]> + let to_bytes_with_nul = |s: String, context: &str| -> Result, QuoteError> { + Ok(CString::new(s) + .str_context(context)? + .as_bytes_with_nul() + .into()) + }; + + Ok(Collateral { + // Default/unhandled values + major_version: 0, + minor_version: 0, + tee_type: 0, + root_ca_crl: Box::new([]), + + // Converted values + pck_crl_issuer_chain: pck_issuer_chain.as_ref().into(), + pck_crl: pck_crl.as_bytes().into(), + tcb_info_issuer_chain: to_bytes_with_nul(tcb_info_issuer_chain, "tcb_info_issuer_chain")?, + tcb_info: to_bytes_with_nul(tcb_info_json, "tcb_info")?, + qe_identity_issuer_chain: to_bytes_with_nul( + qe_identity_issuer_chain, + "qe_identity_issuer_chain", + )?, + qe_identity: to_bytes_with_nul(qe_identity_json, "qe_identity")?, + }) +} + +/// Split the last zero byte +fn get_str_from_bytes(bytes: &[u8], context: &str) -> Result { + let c_str = CStr::from_bytes_until_nul(bytes) + .str_context(format!("Failed to extract CString: {}", context))?; + Ok(c_str.to_string_lossy().into_owned()) +} + +/// Parse JSON field from collateral data +fn parse_json_field(data: &[u8], context: &str) -> Result { + serde_json::from_str(&get_str_from_bytes(data, context)?) + .str_context(format!("Failed to parse JSON: {}", context)) +} + +/// Convert Collateral to QuoteCollateralV3 +fn convert_collateral(collateral: &Collateral) -> Result { + // Parse TCB info + let tcb_info_json = parse_json_field(collateral.tcb_info.as_ref(), "tcb_info_json")?; + + let tcb_info = tcb_info_json["tcbInfo"].to_string(); + let tcb_info_signature = tcb_info_json + .get("signature") + .context("TCB Info missing 'signature' field")? + .as_str() + .context("TCB Info signature must be a string")?; + + let tcb_info_signature = hex::decode(tcb_info_signature) + .ok() + .context("TCB Info signature must be valid hex")?; + + // Parse QE identity + let qe_identity_json = parse_json_field(collateral.qe_identity.as_ref(), "qe_identity_json")?; + + let qe_identity = qe_identity_json + .get("enclaveIdentity") + .context("QE Identity missing 'enclaveIdentity' field")? + .to_string(); + + let qe_identity_signature = qe_identity_json + .get("signature") + .context("QE Identity missing 'signature' field")? + .as_str() + .context("QE Identity signature must be a string")?; + + let qe_identity_signature = hex::decode(qe_identity_signature) + .ok() + .context("QE Identity signature must be valid hex")?; + + Ok(QuoteCollateralV3 { + tcb_info_issuer_chain: get_str_from_bytes( + collateral.tcb_info_issuer_chain.as_ref(), + "convert_collateral: tcb_info_issuer_chain", + )?, + tcb_info, + tcb_info_signature, + qe_identity_issuer_chain: get_str_from_bytes( + collateral.qe_identity_issuer_chain.as_ref(), + "convert_collateral: qe_identity_issuer_chain", + )?, + qe_identity, + qe_identity_signature, + }) +} + +/// Verify a quote with the provided collateral +pub(crate) fn verify_quote_with_collateral( + quote: &[u8], + collateral: Option<&Collateral>, + current_time: i64, +) -> Result { + // Convert collateral or return error if not provided + let collateral = collateral + .ok_or_else(|| QuoteError::Unexpected("No collateral provided".into())) + .and_then(convert_collateral)?; + + // Convert current time to u64 + let current_time_u64 = current_time + .try_into() + .str_context("Failed to convert current_time to u64")?; + + // Verify the quote + let verified_report = dcap_qvl::verify::verify(quote, &collateral, current_time_u64) + .expect("Failed to verify quote"); + + let VerifiedReport { + status, + advisory_ids, + report: _, + } = verified_report; + + // Parse TCB level from status + let result = + TcbLevel::from_str(&status).str_context("Failed to parse TCB level from status")?; + + // Parse quote + let quote = Quote::parse(quote)?; + + let tcb_info_json: serde_json::Value = + serde_json::from_str(&String::from_utf8_lossy(collateral.tcb_info.as_ref())) + .str_context("verify_quote_with_collateral tcb_info_json")?; + + let next_update = tcb_info_json + .get("nextUpdate") + .context("verify_quote_with_collateral: TCB Info missing 'nextUpdate' field")? + .as_str() + .context("verify_quote_with_collateral: TCB Info nextUpdate must be a string")?; + + let next_update = chrono::DateTime::parse_from_rfc3339(next_update) + .ok() + .context("verify_quote_with_collateral: Failed to parse next update")?; + + Ok(QuoteVerificationResult { + result, + collateral_expired: result == TcbLevel::OutOfDate, + earliest_expiration_date: next_update + .signed_duration_since(chrono::DateTime::UNIX_EPOCH) + .num_seconds(), + tcb_level_date_tag: 0, + advisories: advisory_ids, + quote, + }) +} + +/// Get the attestation quote from a TEE +pub fn get_quote(_report_data: &[u8]) -> Result<(TEEType, Box<[u8]>), QuoteError> { + Err(QuoteError::UnknownTee) +} diff --git a/crates/teepot/src/quote/tcblevel.rs b/crates/teepot/src/quote/tcblevel.rs index 25669f0..f2baee5 100644 --- a/crates/teepot/src/quote/tcblevel.rs +++ b/crates/teepot/src/quote/tcblevel.rs @@ -4,7 +4,6 @@ //! Intel SGX Enclave TCB level wrapper use enumset::EnumSetType; -use intel_tee_quote_verification_rs::sgx_ql_qv_result_t; use serde::{Deserialize, Serialize}; use std::{ fmt::{Display, Formatter}, @@ -34,37 +33,20 @@ pub enum TcbLevel { Invalid, } -impl From for TcbLevel { - fn from(value: sgx_ql_qv_result_t) -> Self { - match value { - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => TcbLevel::Ok, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE => TcbLevel::OutOfDate, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => { - TcbLevel::OutOfDateConfigNeeded - } - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => TcbLevel::SwHardeningNeeded, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { - TcbLevel::ConfigAndSwHardeningNeeded - } - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED => TcbLevel::ConfigNeeded, - _ => TcbLevel::Invalid, - } - } -} - impl FromStr for TcbLevel { - type Err = (); + type Err = String; fn from_str(s: &str) -> Result { - match s { - "Ok" => Ok(TcbLevel::Ok), - "ConfigNeeded" => Ok(TcbLevel::ConfigNeeded), - "ConfigAndSwHardeningNeeded" => Ok(TcbLevel::ConfigAndSwHardeningNeeded), - "SwHardeningNeeded" => Ok(TcbLevel::SwHardeningNeeded), - "OutOfDate" => Ok(TcbLevel::OutOfDate), - "OutOfDateConfigNeeded" => Ok(TcbLevel::OutOfDateConfigNeeded), - "Invalid" => Ok(TcbLevel::Invalid), - _ => Err(()), + match s.to_ascii_lowercase().as_str() { + "ok" => Ok(TcbLevel::Ok), + "uptodate" => Ok(TcbLevel::Ok), + "configneeded" => Ok(TcbLevel::ConfigNeeded), + "configandswhardeningneeded" => Ok(TcbLevel::ConfigAndSwHardeningNeeded), + "swhardeningneeded" => Ok(TcbLevel::SwHardeningNeeded), + "outofdate" => Ok(TcbLevel::OutOfDate), + "outofdateconfigneeded" => Ok(TcbLevel::OutOfDateConfigNeeded), + "invalid" => Ok(TcbLevel::Invalid), + _ => Err(format!("Invalid TCB level: {}", s)), } } } diff --git a/crates/teepot/src/sgx/mod.rs b/crates/teepot/src/sgx/mod.rs index d5dba44..8a9f85d 100644 --- a/crates/teepot/src/sgx/mod.rs +++ b/crates/teepot/src/sgx/mod.rs @@ -8,9 +8,8 @@ pub mod sign; use crate::quote::error::QuoteContext; -pub use crate::quote::error::QuoteError; +pub use crate::quote::{error::QuoteError, Collateral}; use bytemuck::{try_from_bytes, AnyBitPattern, PodCastError}; -pub use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; use std::{ fs::OpenOptions, io::{Read, Write}, diff --git a/crates/teepot/src/tdx/mod.rs b/crates/teepot/src/tdx/mod.rs index 321c2d7..878cd17 100644 --- a/crates/teepot/src/tdx/mod.rs +++ b/crates/teepot/src/tdx/mod.rs @@ -3,29 +3,17 @@ //! Intel TDX helper functions. +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] pub mod rtmr; -use crate::sgx::QuoteError; -pub use intel_tee_quote_verification_rs::Collateral; -use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; - -/// Get a TDX quote -pub fn tgx_get_quote(report_data_bytes: &[u8; 64]) -> Result, QuoteError> { - let mut tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; - tdx_report_data.d.copy_from_slice(report_data_bytes); - - let (error, quote) = tdx_att_get_quote(Some(&tdx_report_data), None, None, 0); - - if error == tdx_attest_error_t::TDX_ATTEST_SUCCESS { - if let Some(quote) = quote { - Ok(quote.into()) - } else { - Err(QuoteError::TdxAttGetQuote { - msg: "tdx_att_get_quote: No quote returned".into(), - inner: error, - }) - } - } else { - Err(error.into()) - } -} +/// The sha384 digest of 0u32, which is used in the UEFI TPM protocol +/// as a marker. Used to advance the PCR. +/// ```shell +/// $ echo -n -e "\000\000\000\000" | sha384sum -b +/// 394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0 *- +/// ``` +pub const UEFI_MARKER_DIGEST_BYTES: [u8; 48] = [ + 0x39, 0x43, 0x41, 0xb7, 0x18, 0x2c, 0xd2, 0x27, 0xc5, 0xc6, 0xb0, 0x7e, 0xf8, 0x00, 0x0c, 0xdf, + 0xd8, 0x61, 0x36, 0xc4, 0x29, 0x2b, 0x8e, 0x57, 0x65, 0x73, 0xad, 0x7e, 0xd9, 0xae, 0x41, 0x01, + 0x9f, 0x58, 0x18, 0xb4, 0xb9, 0x71, 0xc9, 0xef, 0xfc, 0x60, 0xe1, 0xad, 0x9f, 0x12, 0x89, 0xf0, +]; diff --git a/crates/teepot/src/tdx/rtmr.rs b/crates/teepot/src/tdx/rtmr.rs index dbb8d67..58725f3 100644 --- a/crates/teepot/src/tdx/rtmr.rs +++ b/crates/teepot/src/tdx/rtmr.rs @@ -5,18 +5,6 @@ use crate::sgx::QuoteError; -/// The sha384 digest of 0u32, which is used in the UEFI TPM protocol -/// as a marker. Used to advance the PCR. -/// ```shell -/// $ echo -n -e "\000\000\000\000" | sha384sum -b -/// 394341b7182cd227c5c6b07ef8000cdfd86136c4292b8e576573ad7ed9ae41019f5818b4b971c9effc60e1ad9f1289f0 *- -/// ``` -pub const UEFI_MARKER_DIGEST_BYTES: [u8; 48] = [ - 0x39, 0x43, 0x41, 0xb7, 0x18, 0x2c, 0xd2, 0x27, 0xc5, 0xc6, 0xb0, 0x7e, 0xf8, 0x00, 0x0c, 0xdf, - 0xd8, 0x61, 0x36, 0xc4, 0x29, 0x2b, 0x8e, 0x57, 0x65, 0x73, 0xad, 0x7e, 0xd9, 0xae, 0x41, 0x01, - 0x9f, 0x58, 0x18, 0xb4, 0xb9, 0x71, 0xc9, 0xef, 0xfc, 0x60, 0xe1, 0xad, 0x9f, 0x12, 0x89, 0xf0, -]; - /// The actual rtmr event data handled in DCAP #[repr(C, packed)] pub struct TdxRtmrEvent { @@ -103,7 +91,7 @@ impl From for Vec { #[cfg(test)] mod test { - use super::UEFI_MARKER_DIGEST_BYTES; + use crate::tdx::UEFI_MARKER_DIGEST_BYTES; #[test] fn test_uefi_marker_digest() { diff --git a/crates/teepot/tests/sgx_quote_verification.rs b/crates/teepot/tests/sgx_quote_verification.rs index 08c8198..28a33e9 100644 --- a/crates/teepot/tests/sgx_quote_verification.rs +++ b/crates/teepot/tests/sgx_quote_verification.rs @@ -1,13 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024 Matter Labs +// Copyright (c) 2024-2025 Matter Labs mod sgx { use anyhow::{Context, Result}; - use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; use std::time::{Duration, UNIX_EPOCH}; use teepot::{ prover::reportdata::{ReportData, ReportDataV1}, - quote::{verify_quote_with_collateral, Quote, QuoteVerificationResult, Report}, + quote::{ + tcblevel::TcbLevel, verify_quote_with_collateral, Collateral, Quote, + QuoteVerificationResult, Report, + }, }; use tracing_test::traced_test; @@ -17,7 +19,7 @@ mod sgx { current_time: i64, expected_mrsigner: &[u8], expected_reportdata: &[u8], - expected_result: sgx_ql_qv_result_t, + expected_result: TcbLevel, ) -> Result<()> { let QuoteVerificationResult { collateral_expired, @@ -28,7 +30,7 @@ mod sgx { tcb_level_date_tag, } = verify_quote_with_collateral(quote, collateral, current_time)?; - if collateral_expired || result != sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK { + if collateral_expired || result != TcbLevel::Ok { print!("Attestation failed: "); if collateral_expired { @@ -40,28 +42,7 @@ mod sgx { earliest_expiration_date ); } - - match result { - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => (), - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED => println!("Config needed"), - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { - println!("Config and Software hardening needed") - } - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE => println!("Out of date"), - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => { - println!("Out of Date and Config needed") - } - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => { - println!("Software hardening needed") - } - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_INVALID_SIGNATURE => { - println!("Invalid signature") - } - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_REVOKED => println!("Revoked"), - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED => println!("Unspecified"), - - _ => println!("Unknown state!"), - } + println!("{result:?}"); } for advisory in advisories { @@ -85,6 +66,8 @@ mod sgx { } #[test] + // alternative quote verification cannot cope with old collateral data format + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] fn sw_hardening() { let quote = [ 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, @@ -1144,12 +1127,14 @@ mod sgx { current_time, &mrsigner, &report_data, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED, + TcbLevel::SwHardeningNeeded, ) .unwrap(); } #[test] + // alternative quote verification cannot cope with old collateral data format + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] fn out_of_date() { let quote = [ 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, @@ -2215,7 +2200,7 @@ mod sgx { current_time, &mrsigner, &report_data, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE, + TcbLevel::OutOfDate, ) .unwrap(); } @@ -2598,12 +2583,14 @@ mod sgx { current_time, &mrsigner, &report_data, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED, + TcbLevel::SwHardeningNeeded, ) .unwrap(); } #[test] + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + // alternative quote verification errors on debug flag fn vault_proxy() { let quote = [ 3, 0, 2, 0, 0, 0, 0, 0, 9, 0, 14, 0, 147, 154, 114, 51, 247, 156, 76, 169, 148, 10, 13, @@ -3681,7 +3668,7 @@ mod sgx { current_time, &mrsigner, &report_data, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED, + TcbLevel::SwHardeningNeeded, ) .unwrap(); } @@ -4809,7 +4796,7 @@ mod sgx { current_time as i64, &mrsigner, &report_data, - sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK, + TcbLevel::Ok, ) .context("check_quote")?; Ok(()) diff --git a/deny.toml b/deny.toml index 2fc391c..1c4ee4e 100644 --- a/deny.toml +++ b/deny.toml @@ -32,6 +32,7 @@ allow = [ "BSD-3-Clause", "OpenSSL", "CC0-1.0", + "Zlib", ] confidence-threshold = 0.8 exceptions = [] diff --git a/packages/container-self-attestation-test-sgx-azure/default.nix b/packages/container-self-attestation-test-sgx-azure/default.nix index d6f6bcb..6f25ff8 100644 --- a/packages/container-self-attestation-test-sgx-azure/default.nix +++ b/packages/container-self-attestation-test-sgx-azure/default.nix @@ -2,10 +2,12 @@ # Copyright (c) 2024 Matter Labs { teepot , pkgs +, stdenv , container-name ? "teepot-self-attestation-test-sgx-azure" , tag ? null , isAzure ? true }: +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else pkgs.lib.tee.sgxGramineContainer { name = container-name; inherit tag; diff --git a/packages/container-tdx-test/default.nix b/packages/container-tdx-test/default.nix index e12c646..9563fff 100644 --- a/packages/container-tdx-test/default.nix +++ b/packages/container-tdx-test/default.nix @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs { lib +, stdenv , openssl , curl , dockerTools @@ -8,28 +9,31 @@ , teepot , nixsgx }: -dockerTools.buildLayeredImage { - name = "tdx-test"; +if (stdenv.hostPlatform.isDarwin) then { + # FIXME: dockerTools.buildLayeredImage seems to be broken on Darwin +} else + dockerTools.buildLayeredImage { + name = "tdx-test"; - config.Entrypoint = [ "${teepot.teepot.tdx_test}/bin/tdx-test-dcap" ]; - config.Env = [ - "SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt" - ]; - - contents = buildEnv { - name = "image-root"; - - paths = with dockerTools;[ - teepot.teepot.tdx_test - openssl.out - curl.out - nixsgx.sgx-dcap.quote_verify - nixsgx.sgx-dcap.default_qpl - usrBinEnv - binSh - caCertificates - fakeNss + config.Entrypoint = [ "${teepot.teepot.tdx_test}/bin/tdx-test" ]; + config.Env = [ + "SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt" ]; - pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; - }; -} + + contents = buildEnv { + name = "image-root"; + + paths = with dockerTools; [ + teepot.teepot.tdx_test + openssl.out + curl.out + # nixsgx.sgx-dcap.quote_verify + # nixsgx.sgx-dcap.default_qpl + usrBinEnv + binSh + caCertificates + fakeNss + ]; + pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; + }; + } diff --git a/packages/container-tee-key-preexec-dcap/default.nix b/packages/container-tee-key-preexec-dcap/default.nix index b49ff69..c2ebf94 100644 --- a/packages/container-tee-key-preexec-dcap/default.nix +++ b/packages/container-tee-key-preexec-dcap/default.nix @@ -2,6 +2,7 @@ # Copyright (c) 2024 Matter Labs { teepot , pkgs +, stdenv , bash , coreutils , container-name ? "teepot-key-preexec-dcap" @@ -9,6 +10,7 @@ }: let entrypoint = "${bash}/bin/bash"; in +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else pkgs.lib.tee.sgxGramineContainer { name = container-name; inherit tag entrypoint; diff --git a/packages/container-vault-admin-sgx-azure/default.nix b/packages/container-vault-admin-sgx-azure/default.nix index cb50463..dc661ef 100644 --- a/packages/container-vault-admin-sgx-azure/default.nix +++ b/packages/container-vault-admin-sgx-azure/default.nix @@ -2,10 +2,12 @@ # Copyright (c) 2024 Matter Labs { teepot , pkgs +, stdenv , container-name ? "teepot-vault-admin-sgx-azure" , tag ? null , isAzure ? null }: +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else pkgs.lib.tee.sgxGramineContainer { name = container-name; inherit tag; diff --git a/packages/container-vault-admin/default.nix b/packages/container-vault-admin/default.nix index ec70476..ee1549e 100644 --- a/packages/container-vault-admin/default.nix +++ b/packages/container-vault-admin/default.nix @@ -2,11 +2,13 @@ # Copyright (c) 2024 Matter Labs { dockerTools , buildEnv +, stdenv , teepot , openssl , curl , nixsgx }: +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else dockerTools.buildLayeredImage { name = "vault-admin"; diff --git a/packages/container-vault-sgx-azure/default.nix b/packages/container-vault-sgx-azure/default.nix index 9d94e9e..52d88a4 100644 --- a/packages/container-vault-sgx-azure/default.nix +++ b/packages/container-vault-sgx-azure/default.nix @@ -2,6 +2,7 @@ # Copyright (c) 2024 Matter Labs { teepot , pkgs +, stdenv , vat , vault , container-name ? "teepot-vault-sgx-azure" @@ -12,6 +13,7 @@ let entrypoint = "${teepot.teepot.tee_ratls_preexec}/bin/tee-ratls-preexec"; appDir = "/opt/vault"; in +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else pkgs.lib.tee.sgxGramineContainer { name = container-name; inherit tag; @@ -86,5 +88,3 @@ pkgs.lib.tee.sgxGramineContainer { sys.experimental__enable_flock = true; }; } - - diff --git a/packages/container-vault-unseal-sgx-azure/default.nix b/packages/container-vault-unseal-sgx-azure/default.nix index c1f0774..cd2ca12 100644 --- a/packages/container-vault-unseal-sgx-azure/default.nix +++ b/packages/container-vault-unseal-sgx-azure/default.nix @@ -2,11 +2,13 @@ # Copyright (c) 2024 Matter Labs { teepot , pkgs +, stdenv , vat , container-name ? "teepot-vault-unseal-sgx-azure" , tag ? null , isAzure ? true }: +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else pkgs.lib.tee.sgxGramineContainer { name = container-name; inherit tag isAzure; diff --git a/packages/container-vault-unseal/default.nix b/packages/container-vault-unseal/default.nix index 1345d09..22979b9 100644 --- a/packages/container-vault-unseal/default.nix +++ b/packages/container-vault-unseal/default.nix @@ -1,30 +1,43 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs { dockerTools +, lib +, stdenv , buildEnv , teepot , openssl , curl , nixsgx }: -dockerTools.buildLayeredImage { - name = "vault-unseal"; +if (stdenv.hostPlatform.isDarwin) then { + # FIXME: dockerTools.buildLayeredImage seems to be broken on Darwin +} else + dockerTools.buildLayeredImage { + name = "vault-unseal"; - config.Entrypoint = [ "${teepot.teepot.vault_unseal}/bin/vault-unseal" ]; + config.Entrypoint = [ "${teepot.teepot.vault_unseal}/bin/vault-unseal" ]; - contents = buildEnv { - name = "image-root"; - paths = with dockerTools; with nixsgx;[ - openssl.out - curl.out - sgx-dcap.quote_verify - sgx-dcap.default_qpl - usrBinEnv - binSh - caCertificates - fakeNss - teepot.teepot.vault_unseal - ]; - pathsToLink = [ "/bin" "/lib" "/etc" ]; - }; -} + contents = buildEnv { + name = "image-root"; + paths = + with dockerTools; + with nixsgx; + [ + openssl.out + curl.out + usrBinEnv + binSh + caCertificates + fakeNss + teepot.teepot.vault_unseal + ] ++ lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [ + sgx-dcap.quote_verify + sgx-dcap.default_qpl + ]; + pathsToLink = [ + "/bin" + "/lib" + "/etc" + ]; + }; + } diff --git a/packages/container-verify-attestation-sgx/default.nix b/packages/container-verify-attestation-sgx/default.nix index d01e540..e871549 100644 --- a/packages/container-verify-attestation-sgx/default.nix +++ b/packages/container-verify-attestation-sgx/default.nix @@ -2,30 +2,44 @@ # Copyright (c) 2024 Matter Labs { dockerTools , buildEnv +, lib +, stdenv , teepot , openssl , curl , nixsgx }: -dockerTools.buildLayeredImage { - name = "verify-attestation-sgx"; +if (stdenv.hostPlatform.isDarwin) then { + # FIXME: dockerTools.buildLayeredImage seems to be broken on Darwin +} else + dockerTools.buildLayeredImage { + name = "verify-attestation-sgx"; - config.Entrypoint = [ "${teepot.teepot.verify_attestation}/bin/verify-attestation" ]; - config.Env = [ "LD_LIBRARY_PATH=/lib" ]; - contents = buildEnv { - name = "image-root"; + config.Entrypoint = [ "${teepot.teepot.verify_attestation}/bin/verify-attestation" ]; + config.Env = [ "LD_LIBRARY_PATH=/lib" ]; + contents = buildEnv { + name = "image-root"; - paths = with dockerTools; with nixsgx;[ - openssl.out - curl.out - sgx-dcap.quote_verify - sgx-dcap.default_qpl - teepot.teepot.verify_attestation - usrBinEnv - binSh - caCertificates - fakeNss - ]; - pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; - }; -} + paths = + with dockerTools; + with nixsgx; + [ + openssl.out + curl.out + teepot.teepot.verify_attestation + usrBinEnv + binSh + caCertificates + fakeNss + ] ++ lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [ + sgx-dcap.quote_verify + sgx-dcap.default_qpl + ]; + pathsToLink = [ + "/bin" + "/lib" + "/etc" + "/share" + ]; + }; + } diff --git a/packages/container-verify-era-proof-attestation-sgx/default.nix b/packages/container-verify-era-proof-attestation-sgx/default.nix index f0918d1..d8be90c 100644 --- a/packages/container-verify-era-proof-attestation-sgx/default.nix +++ b/packages/container-verify-era-proof-attestation-sgx/default.nix @@ -3,31 +3,45 @@ { dockerTools , buildEnv , teepot +, stdenv , openssl , curl , nixsgx , pkg-config }: -dockerTools.buildLayeredImage { - name = "verify-era-proof-attestation"; +if (stdenv.hostPlatform.isDarwin) then { + # FIXME: dockerTools.buildLayeredImage seems to be broken on Darwin +} else + dockerTools.buildLayeredImage { + name = "verify-era-proof-attestation"; - config.Entrypoint = [ "${teepot.teepot.verify_era_proof_attestation}/bin/verify-era-proof-attestation" ]; - config.Env = [ "LD_LIBRARY_PATH=/lib" ]; - contents = buildEnv { - name = "image-root"; - - paths = with dockerTools; with nixsgx;[ - pkg-config - openssl.out - curl.out - sgx-dcap.quote_verify - sgx-dcap.default_qpl - teepot.teepot.verify_era_proof_attestation - usrBinEnv - binSh - caCertificates - fakeNss + config.Entrypoint = [ + "${teepot.teepot.verify_era_proof_attestation}/bin/verify-era-proof-attestation" ]; - pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; - }; -} + config.Env = [ "LD_LIBRARY_PATH=/lib" ]; + contents = buildEnv { + name = "image-root"; + + paths = + with dockerTools; + with nixsgx; + [ + pkg-config + openssl.out + curl.out + sgx-dcap.quote_verify + sgx-dcap.default_qpl + teepot.teepot.verify_era_proof_attestation + usrBinEnv + binSh + caCertificates + fakeNss + ]; + pathsToLink = [ + "/bin" + "/lib" + "/etc" + "/share" + ]; + }; + } diff --git a/packages/tdx_google/default.nix b/packages/tdx_google/default.nix index 5044fd7..98f16a6 100644 --- a/packages/tdx_google/default.nix +++ b/packages/tdx_google/default.nix @@ -2,9 +2,12 @@ # Copyright (c) 2024 Matter Labs { lib , pkgs +, stdenv , system , ... -}: lib.teepot.nixosGenerate { +}: +if (stdenv.hostPlatform.system != "x86_64-linux") then { } else +lib.teepot.nixosGenerate { inherit (lib) nixosSystem; inherit system pkgs; modules = [ diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index 9aee174..340bbae 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -1,20 +1,30 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ lib, pkgs, makeWrapper, teepot }: -let teepotCrate = teepot.teepotCrate; in +{ lib +, pkgs +, makeWrapper +, teepot +, stdenv +}: +let + teepotCrate = teepot.teepotCrate; +in teepotCrate.craneLib.buildPackage ( - teepotCrate.commonArgs // { + teepotCrate.commonArgs + // { pname = "teepot"; inherit (teepotCrate) cargoArtifacts; nativeBuildInputs = teepotCrate.commonArgs.nativeBuildInputs ++ [ makeWrapper ]; passthru = { - inherit (teepotCrate) rustPlatform + inherit (teepotCrate) + rustPlatform rustVersion commonArgs craneLib - cargoArtifacts; + cargoArtifacts + ; }; outputs = [ @@ -37,9 +47,10 @@ teepotCrate.craneLib.buildPackage ( "verify_era_proof_attestation" ]; - postInstall = '' + postInstall = lib.optionalString (stdenv.hostPlatform.system == "x86_64-linux") '' removeReferencesToVendoredSources "$out" "$cargoVendorDir" removeReferencesToVendoredSources "$out" "${teepotCrate.rustVersion}/lib/rustlib/" + '' + '' mkdir -p $out/nix-support for i in $outputs; do [[ $i == "out" ]] && continue @@ -47,14 +58,19 @@ teepotCrate.craneLib.buildPackage ( echo -n "''${!i} " >> $out/nix-support/propagated-user-env-packages binname=''${i//_/-} mv "$out/bin/$binname" "''${!i}/bin/" - - makeWrapper "''${!i}/bin/$binname" "''${!i}/bin/$binname-dcap" \ - --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ pkgs.nixsgx.sgx-dcap.quote_verify pkgs.nixsgx.sgx-dcap.default_qpl pkgs.curl ]}" \ - --set-default QCNL_CONF_PATH "${pkgs.nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf" - + '' + lib.optionalString (stdenv.hostPlatform.system == "x86_64-linux") '' + makeWrapper "''${!i}/bin/$binname" "''${!i}/bin/$binname-dcap" \ + --prefix LD_LIBRARY_PATH : "${ + lib.makeLibraryPath [ + pkgs.nixsgx.sgx-dcap.quote_verify + pkgs.nixsgx.sgx-dcap.default_qpl + pkgs.curl + ] + }" \ + --set-default QCNL_CONF_PATH "${pkgs.nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf" + '' + '' done rmdir "$out/bin" ''; } ) - diff --git a/packages/teepotCrate/default.nix b/packages/teepotCrate/default.nix index 9c3be39..41263c3 100644 --- a/packages/teepotCrate/default.nix +++ b/packages/teepotCrate/default.nix @@ -2,12 +2,14 @@ # Copyright (c) 2024 Matter Labs { lib , inputs +, stdenv , makeRustPlatform -, nixsgx +, nixsgx ? null , pkg-config , rust-bin , pkgs , openssl +, darwin }: let rustVersion = rust-bin.fromRustupToolchainFile (inputs.src + "/rust-toolchain.toml"); @@ -23,11 +25,15 @@ let ]; buildInputs = [ - openssl + openssl.dev + ] + ++ lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [ nixsgx.sgx-sdk nixsgx.sgx-dcap nixsgx.sgx-dcap.quote_verify nixsgx.sgx-dcap.libtdx_attest + ] ++ lib.optionals stdenv.isDarwin [ + darwin.apple_sdk.frameworks.Security ]; strictDeps = true; diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index a8e3195..7fed35a 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -6,11 +6,18 @@ , teepot , nixsgx , stdenv +, }: let - toolchain_with_src = (teepot.teepot.passthru.rustVersion.override { - extensions = [ "rustfmt" "clippy" "rust-src" ]; - }); + toolchain_with_src = ( + teepot.teepot.passthru.rustVersion.override { + extensions = [ + "rustfmt" + "clippy" + "rust-src" + ]; + } + ); in mkShell { inputsFrom = [ teepot.teepot ]; @@ -21,26 +28,34 @@ mkShell { teepot.teepot.passthru.rustPlatform.bindgenHook ]; - packages = with pkgs; [ - dive - taplo - vault - cargo-release - google-cloud-sdk-gce - azure-cli - kubectl - kubectx - k9s - ]; + packages = + with pkgs; + [ + dive + taplo + vault + cargo-release + azure-cli + kubectl + kubectx + k9s + google-cloud-sdk + ]; - TEE_LD_LIBRARY_PATH = lib.makeLibraryPath [ - pkgs.curl - nixsgx.sgx-dcap - nixsgx.sgx-dcap.quote_verify - nixsgx.sgx-dcap.default_qpl - ]; + TEE_LD_LIBRARY_PATH = lib.makeLibraryPath ( + lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [ + pkgs.curl + nixsgx.sgx-dcap + nixsgx.sgx-dcap.quote_verify + nixsgx.sgx-dcap.default_qpl + ] + ); - QCNL_CONF_PATH = "${nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf"; + QCNL_CONF_PATH = + if (stdenv.hostPlatform.system != "x86_64-linux") then + "" + else + "${nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf"; OPENSSL_NO_VENDOR = "1"; RUST_SRC_PATH = "${toolchain_with_src}/lib/rustlib/src/rust/library"; From 0b8f1d54c78c452a58d1e8b7a8ab00f81f3c4bbf Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 7 Apr 2025 13:41:53 +0200 Subject: [PATCH 072/114] feat: bump rust version to 1.86 fixes the hardcoded `/usr/bin/strip` issue on macos see https://github.com/rust-lang/rust/issues/131206 Signed-off-by: Harald Hoyer --- bin/verify-era-proof-attestation/src/proof/types.rs | 4 ++-- crates/teepot-vault/src/client/mod.rs | 2 +- crates/teepot-vault/src/client/vault.rs | 8 ++++---- crates/teepot/src/quote/attestation.rs | 2 +- flake.lock | 6 +++--- rust-toolchain.toml | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/proof/types.rs b/bin/verify-era-proof-attestation/src/proof/types.rs index af3e905..e2362e6 100644 --- a/bin/verify-era-proof-attestation/src/proof/types.rs +++ b/bin/verify-era-proof-attestation/src/proof/types.rs @@ -61,12 +61,12 @@ impl Proof { pub fn is_permanently_ignored(&self) -> bool { self.status .as_ref() - .map_or(false, |s| s.eq_ignore_ascii_case("permanently_ignored")) + .is_some_and(|s| s.eq_ignore_ascii_case("permanently_ignored")) } /// Check if the proof is failed or picked by a prover pub fn is_failed_or_picked(&self) -> bool { - self.status.as_ref().map_or(false, |s| { + self.status.as_ref().is_some_and(|s| { s.eq_ignore_ascii_case("failed") || s.eq_ignore_ascii_case("picked_by_prover") }) } diff --git a/crates/teepot-vault/src/client/mod.rs b/crates/teepot-vault/src/client/mod.rs index f254fd8..97625d7 100644 --- a/crates/teepot-vault/src/client/mod.rs +++ b/crates/teepot-vault/src/client/mod.rs @@ -222,7 +222,7 @@ impl TeeConnection { if self .args .sgx_allowed_tcb_levels - .map_or(true, |levels| !levels.contains(tcblevel)) + .is_none_or(|levels| !levels.contains(tcblevel)) { error!("Quote verification result: {}", tcblevel); return Err(Error::General(format!( diff --git a/crates/teepot-vault/src/client/vault.rs b/crates/teepot-vault/src/client/vault.rs index 42cfbae..c3cf4ad 100644 --- a/crates/teepot-vault/src/client/vault.rs +++ b/crates/teepot-vault/src/client/vault.rs @@ -297,7 +297,7 @@ impl VaultConnection { } /// set a secret in the vault - pub async fn store_secret<'de, T: serde::Serialize>( + pub async fn store_secret( &self, val: T, rel_path: &str, @@ -306,7 +306,7 @@ impl VaultConnection { } /// set a secret in the vault for a different TEE - pub async fn store_secret_for_tee<'de, T: serde::Serialize>( + pub async fn store_secret_for_tee( &self, tee_name: &str, val: T, @@ -330,7 +330,7 @@ impl VaultConnection { } /// get a secret from the vault - pub async fn load_secret<'de, T: serde::de::DeserializeOwned>( + pub async fn load_secret( &self, rel_path: &str, ) -> Result, HttpResponseError> { @@ -338,7 +338,7 @@ impl VaultConnection { } /// get a secret from the vault for a specific TEE - pub async fn load_secret_for_tee<'de, T: serde::de::DeserializeOwned>( + pub async fn load_secret_for_tee( &self, tee_name: &str, rel_path: &str, diff --git a/crates/teepot/src/quote/attestation.rs b/crates/teepot/src/quote/attestation.rs index 4f00065..371545c 100644 --- a/crates/teepot/src/quote/attestation.rs +++ b/crates/teepot/src/quote/attestation.rs @@ -81,7 +81,7 @@ pub fn get_quote_and_collateral( } if tcblevel != TcbLevel::Ok - && allowed_tcb_levels.map_or(false, |levels| !levels.contains(tcblevel)) + && allowed_tcb_levels.is_some_and(|levels| !levels.contains(tcblevel)) { error!("Quote verification result: {}", tcblevel); bail!("Quote verification result: {}", tcblevel); diff --git a/flake.lock b/flake.lock index 643b08f..62f2b11 100644 --- a/flake.lock +++ b/flake.lock @@ -234,11 +234,11 @@ ] }, "locked": { - "lastModified": 1734661750, - "narHash": "sha256-BI58NBdimxu1lnpOrG9XxBz7Cwqy+qIf99zunWofX5w=", + "lastModified": 1743993291, + "narHash": "sha256-u8GHvduU1gCtoFXvTS/wGjH1ouv5S/GRGq6MAT+sG/k=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7d3d910d5fd575e6e8c5600d83d54e5c47273bfe", + "rev": "0cb3c8979c65dc6a5812dfe67499a8c7b8b4325b", "type": "github" }, "original": { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index dbe555f..a237e46 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.83" +channel = "1.86" components = ["rustfmt", "clippy", "rust-src"] From ed84a424dbeb338caaba20de31c1b74caf7206a7 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 9 Apr 2025 16:29:37 +0200 Subject: [PATCH 073/114] feat(api): add Intel DCAP API client module Introduced a new `intel-dcap-api` crate for interacting with Intel's DCAP APIs. - Implemented various API client functionalities for SGX/TDX attestation services. - Added support for registration, certification, enclave identity, and FMSPC retrieval. Signed-off-by: Harald Hoyer --- Cargo.lock | 15 + Cargo.toml | 3 +- crates/intel-dcap-api/Cargo.toml | 27 + crates/intel-dcap-api/examples/example.rs | 78 + crates/intel-dcap-api/examples/get_pck_crl.rs | 75 + crates/intel-dcap-api/src/client.rs | 1324 +++++++++++++++++ crates/intel-dcap-api/src/error.rs | 104 ++ crates/intel-dcap-api/src/lib.rs | 53 + crates/intel-dcap-api/src/requests.rs | 28 + crates/intel-dcap-api/src/responses.rs | 111 ++ crates/intel-dcap-api/src/types.rs | 122 ++ 11 files changed, 1939 insertions(+), 1 deletion(-) create mode 100644 crates/intel-dcap-api/Cargo.toml create mode 100644 crates/intel-dcap-api/examples/example.rs create mode 100644 crates/intel-dcap-api/examples/get_pck_crl.rs create mode 100644 crates/intel-dcap-api/src/client.rs create mode 100644 crates/intel-dcap-api/src/error.rs create mode 100644 crates/intel-dcap-api/src/lib.rs create mode 100644 crates/intel-dcap-api/src/requests.rs create mode 100644 crates/intel-dcap-api/src/responses.rs create mode 100644 crates/intel-dcap-api/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 0ac592f..35f1966 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2603,6 +2603,21 @@ dependencies = [ "generic-array", ] +[[package]] +name = "intel-dcap-api" +version = "0.3.0" +dependencies = [ + "hex", + "percent-encoding", + "reqwest", + "serde", + "serde_json", + "thiserror 2.0.11", + "tokio", + "url", + "x509-cert", +] + [[package]] name = "intel-tee-quote-verification-sys" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 695755a..ae48f3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ enumset = { version = "1.1", features = ["serde"] } getrandom = { version = "0.3.1", features = ["std"] } gpt = "4.0.0" hex = { version = "0.4.3", features = ["std"], default-features = false } +intel-dcap-api = { path = "crates/intel-dcap-api" } num-integer = "0.1.46" num-traits = "0.2.18" opentelemetry = { version = "0.28.0", features = ["default", "logs"] } @@ -65,5 +66,5 @@ tracing-log = "0.2" tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "ansi"] } tracing-test = { version = "0.2.5", features = ["no-env-filter"] } url = "2.5.2" -x509-cert = { version = "0.2", features = ["builder", "signature"] } +x509-cert = { version = "0.2", features = ["builder", "signature", "default"] } zeroize = { version = "1.7.0", features = ["serde"] } diff --git a/crates/intel-dcap-api/Cargo.toml b/crates/intel-dcap-api/Cargo.toml new file mode 100644 index 0000000..df51592 --- /dev/null +++ b/crates/intel-dcap-api/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "intel-dcap-api" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +keywords = ["sgx", "tdx", "intel", "attestation", "confidential"] +categories = ["api-bindings", "cryptography", "authentication"] + +[dependencies] +percent-encoding = "2.3.1" +reqwest = { workspace = true, features = ["json"] } +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +tokio.workspace = true +url.workspace = true + +[dev-dependencies] +hex.workspace = true +x509-cert.workspace = true + +[features] +default = ["reqwest/default-tls"] +rustls = ["reqwest/rustls-tls"] diff --git a/crates/intel-dcap-api/examples/example.rs b/crates/intel-dcap-api/examples/example.rs new file mode 100644 index 0000000..16c3523 --- /dev/null +++ b/crates/intel-dcap-api/examples/example.rs @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use intel_dcap_api::{ + ApiClient, ApiVersion, CaType, CrlEncoding, EnclaveIdentityResponse, IntelApiError, + PckCrlResponse, PlatformFilter, TcbInfoResponse, +}; + +#[tokio::main] +async fn main() -> Result<(), IntelApiError> { + for api_version in [ApiVersion::V3, ApiVersion::V4] { + println!("Using API version: {}", api_version); + + let client = ApiClient::new_with_version(api_version)?; + + // Example: Get SGX TCB Info + let fmspc_example = "00606A000000"; // Example FMSPC from docs + match client.get_sgx_tcb_info(fmspc_example, None, None).await { + Ok(TcbInfoResponse { + tcb_info_json, + issuer_chain, + }) => println!( + "SGX TCB Info for {}:\n{}\nIssuer Chain: {}", + fmspc_example, tcb_info_json, issuer_chain + ), + Err(e) => eprintln!("Error getting SGX TCB info: {}", e), + } + + // Example: Get FMSPCs + match client.get_fmspcs(Some(PlatformFilter::E3)).await { + // Filter for E3 platform type [cite: 230] + Ok(fmspc_list) => println!("\nE3 FMSPCs:\n{}", fmspc_list), + Err(e) => eprintln!("Error getting FMSPCs: {}", e), + } + + // Example: Get SGX QE Identity + match client.get_sgx_qe_identity(None, None).await { + Ok(EnclaveIdentityResponse { + enclave_identity_json, + issuer_chain, + }) => { + println!( + "\nSGX QE Identity:\n{}\nIssuer Chain: {}", + enclave_identity_json, issuer_chain + ) + } + Err(e) => eprintln!("Error getting SGX QE Identity: {}", e), + } + + // Example: Get PCK CRL (Platform CA, PEM encoding) + match client + .get_pck_crl(CaType::Platform, Some(CrlEncoding::Pem)) + .await + { + // [cite: 118, 119] + Ok(PckCrlResponse { + crl_data, + issuer_chain, + }) => { + // Attempt to decode PEM for display, otherwise show byte count + match String::from_utf8(crl_data.clone()) { + Ok(pem_string) => println!( + "\nPlatform PCK CRL (PEM):\n{}\nIssuer Chain: {}", + pem_string, issuer_chain + ), + Err(_) => println!( + "\nPlatform PCK CRL ({} bytes, likely DER):\nIssuer Chain: {}", + crl_data.len(), + issuer_chain + ), + } + } + Err(e) => eprintln!("Error getting PCK CRL: {}", e), + } + } + + Ok(()) +} diff --git a/crates/intel-dcap-api/examples/get_pck_crl.rs b/crates/intel-dcap-api/examples/get_pck_crl.rs new file mode 100644 index 0000000..72d0820 --- /dev/null +++ b/crates/intel-dcap-api/examples/get_pck_crl.rs @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use intel_dcap_api::{ApiClient, CaType, CrlEncoding, IntelApiError, PckCrlResponse}; +use x509_cert::{ + der::{oid::AssociatedOid, Decode, SliceReader}, + ext::pkix::{ + crl::dp::DistributionPoint, + name::{DistributionPointName, GeneralName}, + CrlDistributionPoints, + }, +}; + +#[tokio::main] +async fn main() -> Result<(), IntelApiError> { + let client = ApiClient::new()?; + + let PckCrlResponse { + crl_data, + issuer_chain, + } = client + .get_pck_crl(CaType::Platform, Some(CrlEncoding::Der)) + .await?; + + let certs = x509_cert::certificate::CertificateInner::< + x509_cert::certificate::Rfc5280 + >::load_pem_chain(issuer_chain.as_bytes()).map_err( + |_| IntelApiError::InvalidParameter("Could not load a PEM chain") + )?; + + for cert in certs { + println!("Issuer: {}", cert.tbs_certificate.issuer); + println!("Subject: {}", cert.tbs_certificate.subject); + println!("Serial Number: {}", cert.tbs_certificate.serial_number); + println!("Not Before: {}", cert.tbs_certificate.validity.not_before); + println!("Not After: {}", cert.tbs_certificate.validity.not_after); + + // Extract and print CRL distribution points + if let Some(extensions) = &cert.tbs_certificate.extensions { + for ext in extensions.iter() { + if ext.extn_id == CrlDistributionPoints::OID { + // Create a SliceReader from the byte slice + let mut reader = SliceReader::new(ext.extn_value.as_bytes()).map_err(|_| { + IntelApiError::InvalidParameter( + "Could not create reader from extension value", + ) + })?; + + // Now pass the reader to decode_value + if let Ok(dist_points) = Vec::::decode(&mut reader) { + for point in dist_points { + if let Some(DistributionPointName::FullName(names)) = + point.distribution_point + { + for name in names { + if let GeneralName::UniformResourceIdentifier(uri) = name { + let uri = uri.as_str(); + let crl_bytes = reqwest::get(uri).await?.bytes().await?; + println!("CRL bytes (hex): {}", hex::encode(&crl_bytes)); + } + } + } + } + } else { + println!("Could not decode CRL distribution points"); + } + } + } + } + } + + println!("CRL bytes (hex): {}", hex::encode(&crl_data)); + + Ok(()) +} diff --git a/crates/intel-dcap-api/src/client.rs b/crates/intel-dcap-api/src/client.rs new file mode 100644 index 0000000..294b6fb --- /dev/null +++ b/crates/intel-dcap-api/src/client.rs @@ -0,0 +1,1324 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use crate::responses::AddPackageResponse; +use crate::{ + error::{check_status, extract_api_error_details, IntelApiError}, + requests::{PckCertRequest, PckCertsConfigRequest, PckCertsRequest}, + responses::{ + EnclaveIdentityResponse, PckCertificateResponse, PckCertificatesResponse, PckCrlResponse, + TcbEvaluationDataNumbersResponse, TcbInfoResponse, + }, + types::{ApiVersion, CaType, CrlEncoding, PlatformFilter, UpdateType}, // Import ApiVersion + FmspcJsonResponse, +}; +use percent_encoding::percent_decode_str; +use reqwest::{header, Client, IntoUrl, RequestBuilder, Response, StatusCode}; +use std::num::ParseIntError; +use url::Url; + +// Base URL for the Intel Trusted Services API +const BASE_URL: &str = "https://api.trustedservices.intel.com"; + +/// Client for interacting with Intel Trusted Services API. +/// +/// Provides methods to access both SGX and TDX certification services, +/// supporting API versions V3 and V4. This client offers functionality +/// to register platforms, retrieve PCK certificates and CRLs, fetch TCB +/// information, enclave identities, as well as TCB evaluation data numbers. +/// +/// # Examples +/// +/// ```rust,no_run +/// use intel_dcap_api::ApiClient; +/// +/// #[tokio::main] +/// async fn main() -> Result<(), Box> { +/// // Create a client with default settings (V4 API) +/// let client = ApiClient::new()?; +/// +/// // Retrieve TCB info for a specific FMSPC +/// let tcb_info = client.get_sgx_tcb_info("00606A000000", None, None).await?; +/// println!("TCB Info: {}", tcb_info.tcb_info_json); +/// +/// Ok(()) +/// } +/// ``` +#[derive(Clone)] +pub struct ApiClient { + client: Client, + base_url: Url, + api_version: ApiVersion, +} + +impl ApiClient { + /// Creates a new client targeting the latest supported API version (V4). + /// + /// # Returns + /// + /// A result containing the newly created `ApiClient` or an `IntelApiError` if there + /// was an issue building the underlying HTTP client. + /// + /// # Errors + /// + /// This function may fail if the provided TLS version or base URL + /// cannot be used to build a `reqwest` client. + pub fn new() -> Result { + Self::new_with_options(BASE_URL, ApiVersion::V4) // Default to V4 + } + + /// Creates a new client targeting a specific API version. + /// + /// # Arguments + /// + /// * `api_version` - The desired API version to use (V3 or V4). + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the `reqwest` client cannot be built + /// with the specified options. + pub fn new_with_version(api_version: ApiVersion) -> Result { + Self::new_with_options(BASE_URL, api_version) + } + + /// Creates a new client with a custom base URL, targeting the latest supported API version (V4). + /// + /// # Arguments + /// + /// * `base_url` - The custom base URL for the Intel Trusted Services API. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the `reqwest` client cannot be built + /// or if the provided base URL is invalid. + pub fn new_with_base_url(base_url: impl IntoUrl) -> Result { + Self::new_with_options(base_url, ApiVersion::V4) // Default to V4 + } + + /// Creates a new client with a custom base URL and specific API version. + /// + /// # Arguments + /// + /// * `base_url` - The custom base URL for the Intel Trusted Services API. + /// * `api_version` - The desired API version (V3 or V4). + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the `reqwest` client cannot be built + /// or if the provided base URL is invalid. + pub fn new_with_options( + base_url: impl IntoUrl, + api_version: ApiVersion, + ) -> Result { + Ok(ApiClient { + client: Client::builder() + .min_tls_version(reqwest::tls::Version::TLS_1_2) + .build()?, + base_url: base_url.into_url()?, + api_version, // Store the version + }) + } + + /// POST /sgx/registration/v1/platform + /// Registers a multi-package SGX platform with the Intel Trusted Services API. + /// + /// # Arguments + /// + /// * `platform_manifest` - Binary data representing the platform manifest. + /// + /// # Returns + /// + /// Request body is binary Platform Manifest + /// Returns the hex-encoded PPID as a `String` upon success. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not HTTP `201 CREATED`. + pub async fn register_platform( + &self, + platform_manifest: Vec, + ) -> Result { + // Registration paths are fixed, use the helper with "registration" service + let path = self.build_api_path("sgx", "registration", "platform")?; + let url = self.base_url.join(&path)?; + + let response = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/octet-stream") + .body(platform_manifest) + .send() + .await?; + + let response = check_status(response, &[StatusCode::CREATED]).await?; + + // Response body is hex-encoded PPID + let ppid_hex = response.text().await?; + Ok(ppid_hex) + } + + /// POST /sgx/registration/v1/package + /// Adds new package(s) to an already registered SGX platform instance. + /// + /// # Arguments + /// + /// * `add_package_request` - Binary data for the "Add Package" request body. + /// * `subscription_key` - The subscription key required by the Intel API. + /// + /// # Returns + /// + /// A [`AddPackageResponse`] containing the Platform Membership Certificates and + /// the count of them extracted from the response header. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails, if the subscription key is invalid, + /// or if the response status is not HTTP `200 OK`. + pub async fn add_package( + &self, + add_package_request: Vec, + subscription_key: &str, + ) -> Result { + if subscription_key.is_empty() { + return Err(IntelApiError::InvalidSubscriptionKey); + } + + // Registration paths are fixed + let path = self.build_api_path("sgx", "registration", "package")?; + let url = self.base_url.join(&path)?; + + let response = self + .client + .post(url) + .header("Ocp-Apim-Subscription-Key", subscription_key) + .header(header::CONTENT_TYPE, "application/octet-stream") + .body(add_package_request) + .send() + .await?; + + let response = check_status(response, &[StatusCode::OK]).await?; + + // Use the generic header helper, assuming header name is stable across reg versions + let cert_count_str = self.get_required_header(&response, "Certificate-Count", None)?; + let pck_cert_count: usize = cert_count_str.parse().map_err(|e: ParseIntError| { + IntelApiError::HeaderValueParse("Certificate-Count", e.to_string()) + })?; + + // Response body is a binary array of certificates + let pck_certs = response.bytes().await?.to_vec(); + Ok(AddPackageResponse { + pck_certs, + pck_cert_count, + }) + } + + // === Provisioning Certification Service === + + /// GET /sgx/certification/{v3,v4}/pckcert + /// Retrieves a single SGX PCK certificate using encrypted PPID and SVNs. + /// + /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter + /// is only valid for API v4 and allows specifying the PPID encryption key type (e.g. "RSA-3072"). + /// + /// # Arguments + /// + /// * `encrypted_ppid` - Hex-encoded encrypted PPID. + /// * `cpusvn` - Hex-encoded CPUSVN value. + /// * `pcesvn` - Hex-encoded PCESVN value. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). + /// + /// # Returns + /// + /// A [`PckCertificateResponse`] containing the PEM-encoded certificate, issuer chain, + /// TCBm, and FMSPC. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API call fails or the response contains an invalid status. + /// Returns PEM Cert, Issuer Chain, TCBm, FMSPC. + pub async fn get_pck_certificate_by_ppid( + &self, + encrypted_ppid: &str, + cpusvn: &str, + pcesvn: &str, + pceid: &str, + subscription_key: Option<&str>, + ppid_encryption_key_type: Option<&str>, + ) -> Result { + // Check V4-only parameter + self.check_v4_only_param(ppid_encryption_key_type, "PPID-Encryption-Key")?; + + let path = self.build_api_path("sgx", "", "pckcert")?; // service is empty + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("encrypted_ppid", encrypted_ppid) + .append_pair("cpusvn", cpusvn) + .append_pair("pcesvn", pcesvn) + .append_pair("pceid", pceid); + + let mut request_builder = self.client.get(url); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + // Only add for V4 + if self.api_version == ApiVersion::V4 { + request_builder = Self::maybe_add_header( + request_builder, + "PPID-Encryption-Key", + ppid_encryption_key_type, + ); + } + + self.fetch_pck_certificate(request_builder).await + } + + /// POST /sgx/certification/{v3,v4}/pckcert + /// Retrieves a single SGX PCK certificate using a platform manifest and SVNs. + /// + /// Optionally requires a subscription key. + /// + /// # Arguments + /// + /// * `platform_manifest` - Hex-encoded platform manifest. + /// * `cpusvn` - Hex-encoded CPUSVN value. + /// * `pcesvn` - Hex-encoded PCESVN value. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// + /// # Returns + /// + /// A [`PckCertificateResponse`] containing the PEM-encoded certificate, issuer chain, + /// TCBm, and FMSPC. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response is invalid. + /// Returns PEM Cert, Issuer Chain, TCBm, FMSPC. + pub async fn get_pck_certificate_by_manifest( + &self, + platform_manifest: &str, + cpusvn: &str, + pcesvn: &str, + pceid: &str, + subscription_key: Option<&str>, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcert")?; + let url = self.base_url.join(&path)?; + let request_body = PckCertRequest { + platform_manifest, + cpusvn, + pcesvn, + pceid, + }; + + let mut request_builder = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .json(&request_body); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + self.fetch_pck_certificate(request_builder).await + } + + /// GET /sgx/certification/{v3,v4}/pckcerts + /// Retrieves all SGX PCK certificates for a platform using encrypted PPID. + /// + /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter + /// is only valid for API v4. + /// + /// # Arguments + /// + /// * `encrypted_ppid` - Hex-encoded encrypted PPID. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] containing JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API call fails or the response status is invalid. + pub async fn get_pck_certificates_by_ppid( + &self, + encrypted_ppid: &str, + pceid: &str, + subscription_key: Option<&str>, + ppid_encryption_key_type: Option<&str>, + ) -> Result { + // Check V4-only parameter + self.check_v4_only_param(ppid_encryption_key_type, "PPID-Encryption-Key")?; + + let path = self.build_api_path("sgx", "", "pckcerts")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("encrypted_ppid", encrypted_ppid) + .append_pair("pceid", pceid); + + let mut request_builder = self.client.get(url); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + // Only add for V4 + if self.api_version == ApiVersion::V4 { + request_builder = Self::maybe_add_header( + request_builder, + "PPID-Encryption-Key", + ppid_encryption_key_type, + ); + } + + self.fetch_pck_certificates(request_builder).await + } + + /// POST /sgx/certification/{v3,v4}/pckcerts + /// Retrieves all SGX PCK certificates for a platform using a platform manifest. + /// + /// Optionally requires a subscription key. + /// + /// # Arguments + /// + /// * `platform_manifest` - Hex-encoded platform manifest. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] containing JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API call fails or the response status is invalid. + pub async fn get_pck_certificates_by_manifest( + &self, + platform_manifest: &str, + pceid: &str, + subscription_key: Option<&str>, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcerts")?; + let url = self.base_url.join(&path)?; + let request_body = PckCertsRequest { + platform_manifest, + pceid, + }; + + let mut request_builder = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .json(&request_body); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + self.fetch_pck_certificates(request_builder).await + } + + /// GET /sgx/certification/{v3,v4}/pckcerts/config (using PPID) + /// Retrieves SGX PCK certificates for a specific configuration (CPUSVN) using encrypted PPID. + /// + /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter + /// is only valid for API v4. Returns JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Arguments + /// + /// * `encrypted_ppid` - Hex-encoded encrypted PPID. + /// * `pceid` - Hex-encoded PCEID value. + /// * `cpusvn` - Hex-encoded CPUSVN value for the requested configuration. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] with the requested config's certificate data. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not `200 OK`. + pub async fn get_pck_certificates_config_by_ppid( + &self, + encrypted_ppid: &str, + pceid: &str, + cpusvn: &str, + subscription_key: Option<&str>, + ppid_encryption_key_type: Option<&str>, + ) -> Result { + // V3 does not support PPID-Encryption-Key header/type + if self.api_version == ApiVersion::V3 && ppid_encryption_key_type.is_some() { + return Err(IntelApiError::UnsupportedApiVersion( + "PPID-Encryption-Key header is only supported in API v4".to_string(), + )); + } + + let path = self.build_api_path("sgx", "", "pckcerts/config")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("encrypted_ppid", encrypted_ppid) + .append_pair("pceid", pceid) + .append_pair("cpusvn", cpusvn); + + let mut request_builder = self.client.get(url); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + // Only add for V4 + if self.api_version == ApiVersion::V4 { + request_builder = Self::maybe_add_header( + request_builder, + "PPID-Encryption-Key", + ppid_encryption_key_type, + ); + } + + self.fetch_pck_certificates(request_builder).await + } + + /// POST /sgx/certification/{v3,v4}/pckcerts/config (using Manifest) + /// Retrieves SGX PCK certificates for a specific configuration (CPUSVN) using a platform manifest. + /// + /// Optionally requires a subscription key. Returns JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Arguments + /// + /// * `platform_manifest` - Hex-encoded platform manifest. + /// * `pceid` - Hex-encoded PCEID value. + /// * `cpusvn` - Hex-encoded CPUSVN value for the requested configuration. + /// * `subscription_key` - Optional subscription key if needed by the Intel API. + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] with the requested config's certificate data. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not `200 OK`. + pub async fn get_pck_certificates_config_by_manifest( + &self, + platform_manifest: &str, + pceid: &str, + cpusvn: &str, + subscription_key: Option<&str>, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcerts/config")?; + let url = self.base_url.join(&path)?; + let request_body = PckCertsConfigRequest { + platform_manifest, + pceid, + cpusvn, + }; + + let mut request_builder = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .json(&request_body); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + self.fetch_pck_certificates(request_builder).await + } + + /// GET /sgx/certification/{v3,v4}/pckcrl + /// Retrieves the PCK Certificate Revocation List (CRL) for a specified CA type. + /// + /// Optionally takes an `encoding` parameter indicating whether the CRL should be + /// returned as PEM or DER. Defaults to PEM if not specified. + /// + /// # Arguments + /// + /// * `ca_type` - The type of CA to retrieve the CRL for (e.g., "processor" or "platform"). + /// * `encoding` - An optional [`CrlEncoding`] (PEM or DER). + /// + /// # Returns + /// + /// A [`PckCrlResponse`] containing the CRL data and the issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not `200 OK`. + /// Optional 'encoding' parameter ("pem" or "der"). + /// Returns CRL data (PEM or DER) and Issuer Chain header. + pub async fn get_pck_crl( + &self, + ca_type: CaType, + encoding: Option, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcrl")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("ca", &ca_type.to_string()); + + if let Some(enc) = encoding { + url.query_pairs_mut() + .append_pair("encoding", &enc.to_string()); + } + + let request_builder = self.client.get(url); + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = self.get_required_header( + &response, + "SGX-PCK-CRL-Issuer-Chain", // v4 name + Some("SGX-PCK-CRL-Issuer-Chain"), // v3 name + )?; + + // Response body is PEM or DER CRL + let crl_data = response.bytes().await?.to_vec(); + + Ok(PckCrlResponse { + crl_data, + issuer_chain, + }) + } + + // --- TCB Info --- + + /// GET /sgx/certification/{v3,v4}/tcb + /// Retrieves SGX TCB information for a given FMSPC. + /// + /// Returns TCB Info JSON string (Appendix A) and Issuer Chain header. + /// This function supports both API v3 and v4. The `update` and `tcbEvaluationDataNumber` + /// parameters are only supported by API v4. If both are provided at the same time (for v4), + /// a conflict error is returned. + /// + /// # Arguments + /// + /// * `fmspc` - Hex-encoded FMSPC value. + /// * `update` - Optional [`UpdateType`] for API v4. + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// A [`TcbInfoResponse`] containing the TCB info JSON and the issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API request fails, if conflicting parameters are used, + /// or if the requested TCB data is not found. + pub async fn get_sgx_tcb_info( + &self, + fmspc: &str, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // V3 does not support 'update' or 'tcbEvaluationDataNumber' + if self.api_version == ApiVersion::V3 && update.is_some() { + return Err(IntelApiError::UnsupportedApiVersion( + "'update' parameter requires API v4".to_string(), + )); + } + if self.api_version == ApiVersion::V3 && tcb_evaluation_data_number.is_some() { + return Err(IntelApiError::UnsupportedApiVersion( + "'tcbEvaluationDataNumber' parameter requires API v4".to_string(), + )); + } + if self.api_version == ApiVersion::V4 + && update.is_some() + && tcb_evaluation_data_number.is_some() + { + return Err(IntelApiError::ConflictingParameters( + "'update' and 'tcbEvaluationDataNumber'", + )); + } + + let path = self.build_api_path("sgx", "", "tcb")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut().append_pair("fmspc", fmspc); + + // Add V4-specific parameters + if self.api_version == ApiVersion::V4 { + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + } + + let request_builder = self.client.get(url); + + // Special handling for 404/410 when tcbEvaluationDataNumber is specified (V4 only) + if self.api_version == ApiVersion::V4 { + if let Some(tedn_val) = tcb_evaluation_data_number { + // Use the helper function to check status before proceeding + self.check_tcb_evaluation_status(&request_builder, tedn_val, "SGX TCB Info") + .await?; + // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain + } + } + + // Fetch JSON and header (header name seems same for v3/v4) + let (tcb_info_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "TCB-Info-Issuer-Chain", // v4 name + Some("SGX-TCB-Info-Issuer-Chain"), // v3 name + ) + .await?; + + Ok(TcbInfoResponse { + tcb_info_json, + issuer_chain, + }) + } + + /// GET /tdx/certification/v4/tcb + /// Retrieves TDX TCB information for a given FMSPC (API v4 only). + /// + /// # Arguments + /// + /// * `fmspc` - Hex-encoded FMSPC value. + /// * `update` - An optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - An optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// A [`TcbInfoResponse`] containing TDX TCB info JSON and the issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used, + /// if there are conflicting parameters, or if the TDX TCB data is not found. + /// Returns TCB Info JSON string (Appendix A) and Issuer Chain header. + pub async fn get_tdx_tcb_info( + &self, + fmspc: &str, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // Ensure V4 API + self.ensure_v4_api("get_tdx_tcb_info")?; + // Check conflicting parameters (only relevant for V4, checked inside helper) + self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; + + let path = self.build_api_path("tdx", "", "tcb")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut().append_pair("fmspc", fmspc); + + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + + let request_builder = self.client.get(url); + + // Special handling for 404/410 when tcbEvaluationDataNumber is specified + if let Some(tedn_val) = tcb_evaluation_data_number { + // Use the helper function to check status before proceeding + self.check_tcb_evaluation_status(&request_builder, tedn_val, "TDX TCB Info") + .await?; + // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain + } + + // Fetch JSON and header (TDX only exists in V4) + let (tcb_info_json, issuer_chain) = self + .fetch_json_with_issuer_chain(request_builder, "TCB-Info-Issuer-Chain", None) + .await?; + + Ok(TcbInfoResponse { + tcb_info_json, + issuer_chain, + }) + } + + // --- Enclave Identity --- + + /// Retrieves the SGX QE Identity from the Intel API. + /// + /// Returns Enclave Identity JSON string (Appendix B) and Issuer Chain header. + /// Supports both v3 and v4. The `update` and `tcb_evaluation_data_number` + /// parameters are only valid in API v4. Returns the enclave identity JSON + /// and an issuer chain header. + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the JSON identity and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails, if conflicting v4 parameters are used, + /// or if the desired identity resource is not found. + pub async fn get_sgx_qe_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + self.get_sgx_enclave_identity("qe", update, tcb_evaluation_data_number) + .await + } + + /// Retrieves the TDX QE Identity from the Intel API (API v4 only). + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the JSON identity and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used, + /// if conflicting parameters are provided, or if the identity resource is not found. + /// GET /tdx/certification/v4/qe/identity - V4 ONLY + pub async fn get_tdx_qe_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // Ensure V4 API + self.ensure_v4_api("get_tdx_qe_identity")?; + // Check conflicting parameters (only relevant for V4, checked inside helper) + self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; + + let path = self.build_api_path("tdx", "qe", "identity")?; + let mut url = self.base_url.join(&path)?; + + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + + let request_builder = self.client.get(url); + + // Special handling for 404/410 when tcbEvaluationDataNumber is specified + if let Some(tedn_val) = tcb_evaluation_data_number { + // Use the helper function to check status before proceeding + self.check_tcb_evaluation_status(&request_builder, tedn_val, "TDX QE Identity") + .await?; + // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain + } + + // Fetch JSON and header (TDX only exists in V4) + let (enclave_identity_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "SGX-Enclave-Identity-Issuer-Chain", + None, + ) + .await?; + + Ok(EnclaveIdentityResponse { + enclave_identity_json, + issuer_chain, + }) + } + + /// Retrieves the SGX QVE Identity from the Intel API. + /// + /// Supports API v3 and v4. The `update` and `tcb_evaluation_data_number` parameters + /// are v4 only. Returns the QVE identity JSON and issuer chain. + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the QVE identity JSON and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails, if conflicting parameters are used, + /// or if the identity resource is not found. + /// GET /sgx/certification/{v3,v4}/qve/identity + pub async fn get_sgx_qve_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + self.get_sgx_enclave_identity("qve", update, tcb_evaluation_data_number) + .await + } + + /// Retrieves the SGX QAE Identity from the Intel API (API v4 only). + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the QAE identity JSON and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used, + /// if conflicting parameters are provided, or if the QAE identity is not found. + /// GET /sgx/certification/v4/qae/identity - V4 ONLY + pub async fn get_sgx_qae_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // QAE endpoint requires V4 + if self.api_version != ApiVersion::V4 { + return Err(IntelApiError::UnsupportedApiVersion( + "QAE Identity endpoint requires API v4".to_string(), + )); + } + // Call the generic helper, it will handle V4 params and 404/410 checks + self.get_sgx_enclave_identity("qae", update, tcb_evaluation_data_number) + .await + } + + // --- FMSPCs & TCB Evaluation Data Numbers --- + + /// GET /sgx/certification/{v3,v4}/fmspcs + /// Retrieves a list of FMSPC values for SGX and TDX platforms (API v4 only). + /// + /// # Arguments + /// + /// * `platform_filter` - An optional filter specifying SGX or TDX platforms. + /// + /// # Returns + /// + /// Optional 'platform' filter. + /// A `String` containing the JSON array of objects, each containing `fmspc` and `platform`. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. + pub async fn get_fmspcs( + &self, + platform_filter: Option, + ) -> Result { + if self.api_version == ApiVersion::V3 { + return Err(IntelApiError::UnsupportedApiVersion( + "API v4 only function".to_string(), + )); + } + let path = self.build_api_path("sgx", "", "fmspcs")?; + let mut url = self.base_url.join(&path)?; + + if let Some(pf) = platform_filter { + url.query_pairs_mut() + .append_pair("platform", &pf.to_string()); + } + + let request_builder = self.client.get(url); + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let fmspcs_json = response.text().await?; + + Ok(fmspcs_json) + } + + /// GET /sgx/certification/v4/tcbevaluationdatanumbers - V4 ONLY + /// Retrieves the currently supported SGX TCB Evaluation Data Numbers (API v4 only). + /// + /// # Returns + /// + /// A [`TcbEvaluationDataNumbersResponse`] containing the JSON structure of TCB Evaluation + /// Data Numbers and an issuer chain header. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. + pub async fn get_sgx_tcb_evaluation_data_numbers( + &self, + ) -> Result { + // Endpoint requires V4 + if self.api_version != ApiVersion::V4 { + return Err(IntelApiError::UnsupportedApiVersion( + "SGX TCB Evaluation Data Numbers endpoint requires API v4".to_string(), + )); + } + + let path = self.build_api_path("sgx", "", "tcbevaluationdatanumbers")?; + let url = self.base_url.join(&path)?; + let request_builder = self.client.get(url); + + let (tcb_evaluation_data_numbers_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "TCB-Evaluation-Data-Numbers-Issuer-Chain", + None, + ) + .await?; + + Ok(TcbEvaluationDataNumbersResponse { + tcb_evaluation_data_numbers_json, + issuer_chain, + }) + } + + /// GET /tdx/certification/v4/tcbevaluationdatanumbers - V4 ONLY + /// Retrieves the currently supported TDX TCB Evaluation Data Numbers (API v4 only). + /// + /// # Returns + /// + /// A [`TcbEvaluationDataNumbersResponse`] containing the JSON structure of TCB Evaluation + /// Data Numbers and an issuer chain header. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. + pub async fn get_tdx_tcb_evaluation_data_numbers( + &self, + ) -> Result { + // Endpoint requires V4 + if self.api_version != ApiVersion::V4 { + return Err(IntelApiError::UnsupportedApiVersion( + "TDX TCB Evaluation Data Numbers endpoint requires API v4".to_string(), + )); + } + + let path = self.build_api_path("tdx", "", "tcbevaluationdatanumbers")?; + let url = self.base_url.join(&path)?; + let request_builder = self.client.get(url); + + let (tcb_evaluation_data_numbers_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "TCB-Evaluation-Data-Numbers-Issuer-Chain", + None, + ) + .await?; + + Ok(TcbEvaluationDataNumbersResponse { + tcb_evaluation_data_numbers_json, + issuer_chain, + }) + } + + // ------------------------ + // Internal helper methods + // ------------------------ + + /// Helper to construct API paths dynamically based on version and technology (SGX/TDX). + fn build_api_path( + &self, + technology: &str, + service: &str, + endpoint: &str, + ) -> Result { + let api_segment = self.api_version.path_segment(); + + if technology == "tdx" && self.api_version == ApiVersion::V3 { + return Err(IntelApiError::UnsupportedApiVersion(format!( + "TDX endpoint /{}/{}/{} requires API v4", + service, endpoint, technology + ))); + } + if technology == "sgx" && service == "registration" { + return Ok(format!("/sgx/registration/v1/{}", endpoint).replace("//", "/")); + } + + Ok(format!( + "/{}/certification/{}/{}/{}", + technology, api_segment, service, endpoint + ) + .replace("//", "/")) + } + + /// Helper to add an optional header if the string is non-empty. + fn maybe_add_header( + builder: RequestBuilder, + header_name: &'static str, + header_value: Option<&str>, + ) -> RequestBuilder { + match header_value { + Some(value) if !value.is_empty() => builder.header(header_name, value), + _ => builder, + } + } + + /// Helper to extract a required header string value, handling potential v3/v4 differences. + fn get_required_header( + &self, + response: &Response, + v4_header_name: &'static str, + v3_header_name: Option<&'static str>, + ) -> Result { + let header_name = match self.api_version { + ApiVersion::V4 => v4_header_name, + ApiVersion::V3 => v3_header_name.unwrap_or(v4_header_name), + }; + let value = response + .headers() + .get(header_name) + .ok_or(IntelApiError::MissingOrInvalidHeader(header_name))? + .to_str() + .map_err(|e| IntelApiError::HeaderValueParse(header_name, e.to_string()))?; + + if value.contains('%') { + percent_decode_str(value) + .decode_utf8() + .map_err(|e| IntelApiError::HeaderValueParse(header_name, e.to_string())) + .map(|s| s.to_string()) + } else { + Ok(value.to_string()) + } + } + + /// Helper to execute a request that returns a single PCK certificate and associated headers. + async fn fetch_pck_certificate( + &self, + request_builder: RequestBuilder, + ) -> Result { + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = self.get_required_header( + &response, + "SGX-PCK-Certificate-Issuer-Chain", + Some("SGX-PCK-Certificate-Issuer-Chain"), + )?; + let tcbm = self.get_required_header(&response, "SGX-TCBm", Some("SGX-TCBm"))?; + let fmspc = self.get_required_header(&response, "SGX-FMSPC", Some("SGX-FMSPC"))?; + let pck_cert_pem = response.text().await?; + + Ok(PckCertificateResponse { + pck_cert_pem, + issuer_chain, + tcbm, + fmspc, + }) + } + + /// Helper to execute a request that returns a PCK certificates JSON array and associated headers. + async fn fetch_pck_certificates( + &self, + request_builder: RequestBuilder, + ) -> Result { + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = self.get_required_header( + &response, + "SGX-PCK-Certificate-Issuer-Chain", + Some("SGX-PCK-Certificate-Issuer-Chain"), + )?; + let fmspc = self.get_required_header(&response, "SGX-FMSPC", Some("SGX-FMSPC"))?; + let pck_certs_json = response.text().await?; + + Ok(PckCertificatesResponse { + pck_certs_json, + issuer_chain, + fmspc, + }) + } + + /// Helper to execute a request expected to return JSON plus an Issuer-Chain header. + async fn fetch_json_with_issuer_chain( + &self, + request_builder: RequestBuilder, + v4_issuer_chain_header: &'static str, + v3_issuer_chain_header: Option<&'static str>, + ) -> Result<(String, String), IntelApiError> { + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = + self.get_required_header(&response, v4_issuer_chain_header, v3_issuer_chain_header)?; + let json_body = response.text().await?; + + Ok((json_body, issuer_chain)) + } + + /// Checks for HTTP 404 or 410 status when querying TCB Evaluation Data Number based resources. + async fn check_tcb_evaluation_status( + &self, + request_builder: &RequestBuilder, + tcb_evaluation_data_number_val: u64, + resource_description: &str, + ) -> Result<(), IntelApiError> { + let builder_clone = request_builder.try_clone().ok_or_else(|| { + IntelApiError::Io(std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to clone request builder for status check", + )) + })?; + + let response = builder_clone.send().await?; + let status = response.status(); + + if status == StatusCode::NOT_FOUND || status == StatusCode::GONE { + let (request_id, _, _) = extract_api_error_details(&response); + return Err(IntelApiError::ApiError { + status, + request_id, + error_code: None, + error_message: Some(format!( + "{} for TCB Evaluation Data Number {} {}", + resource_description, + tcb_evaluation_data_number_val, + if status == StatusCode::NOT_FOUND { + "not found" + } else { + "is no longer available" + } + )), + }); + } + Ok(()) + } + + /// Ensures the client is configured for API v4, otherwise returns an error. + fn ensure_v4_api(&self, function_name: &str) -> Result<(), IntelApiError> { + if self.api_version != ApiVersion::V4 { + Err(IntelApiError::UnsupportedApiVersion(format!( + "{} requires API v4", + function_name + ))) + } else { + Ok(()) + } + } + + /// Checks if a V4-only parameter is provided with a V3 API version. + fn check_v4_only_param( + &self, + param_value: Option, + param_name: &str, + ) -> Result<(), IntelApiError> { + if self.api_version == ApiVersion::V3 && param_value.is_some() { + Err(IntelApiError::UnsupportedApiVersion(format!( + "'{}' parameter requires API v4", + param_name + ))) + } else { + Ok(()) + } + } + + /// Checks for conflicting `update` and `tcb_evaluation_data_number` parameters when using V4. + fn check_conflicting_update_params( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result<(), IntelApiError> { + if self.api_version == ApiVersion::V4 + && update.is_some() + && tcb_evaluation_data_number.is_some() + { + Err(IntelApiError::ConflictingParameters( + "'update' and 'tcbEvaluationDataNumber'", + )) + } else { + Ok(()) + } + } + + /// Retrieves generic SGX enclave identity (QE, QVE, QAE) data. + /// + /// # Arguments + /// + /// * `identity_path_segment` - String slice representing the identity path segment (e.g., "qe", "qve", "qae"). + /// * `update` - Optional [`UpdateType`] for API v4. + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number for API v4. + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the JSON identity data and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or the specified resource + /// is unavailable. + async fn get_sgx_enclave_identity( + &self, + identity_path_segment: &str, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + self.check_v4_only_param(update, "update")?; + self.check_v4_only_param(tcb_evaluation_data_number, "tcbEvaluationDataNumber")?; + self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; + + let path = self.build_api_path("sgx", identity_path_segment, "identity")?; + let mut url = self.base_url.join(&path)?; + + if self.api_version == ApiVersion::V4 { + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + } + + let request_builder = self.client.get(url); + + if self.api_version == ApiVersion::V4 { + if let Some(tedn_val) = tcb_evaluation_data_number { + let description = format!("SGX {} Identity", identity_path_segment.to_uppercase()); + self.check_tcb_evaluation_status(&request_builder, tedn_val, &description) + .await?; + } + } + + let (enclave_identity_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "SGX-Enclave-Identity-Issuer-Chain", + Some("SGX-Enclave-Identity-Issuer-Chain"), + ) + .await?; + + Ok(EnclaveIdentityResponse { + enclave_identity_json, + issuer_chain, + }) + } +} diff --git a/crates/intel-dcap-api/src/error.rs b/crates/intel-dcap-api/src/error.rs new file mode 100644 index 0000000..564bbd2 --- /dev/null +++ b/crates/intel-dcap-api/src/error.rs @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use reqwest::{Response, StatusCode}; +use thiserror::Error; + +/// Represents all possible errors that can occur when interacting with Intel's DCAP API. +#[derive(Error, Debug)] +pub enum IntelApiError { + /// Indicates that the requested API version or feature is unsupported. + #[error("Unsupported API version or feature: {0}")] + UnsupportedApiVersion(String), + + /// Wraps an underlying reqwest error. + #[error("Reqwest error: {0}")] + Reqwest(#[from] reqwest::Error), + + /// Wraps a URL parsing error. + #[error("URL parsing error: {0}")] + UrlParse(#[from] url::ParseError), + + /// Wraps a Serde JSON error. + #[error("Serde JSON error: {0}")] + JsonError(#[from] serde_json::Error), + + /// Represents a general API error, capturing the HTTP status and optional error details. + #[error("API Error: Status={status}, Request-ID={request_id}, Code={error_code:?}, Message={error_message:?}")] + ApiError { + /// HTTP status code returned by the API. + status: StatusCode, + /// The unique request identifier for tracing errors. + request_id: String, + /// An optional server-provided error code. + error_code: Option, + /// An optional server-provided error message. + error_message: Option, + }, + + /// Indicates that a header is missing or invalid. + #[error("Header missing or invalid: {0}")] + MissingOrInvalidHeader(&'static str), + + /// Represents an invalid subscription key. + #[error("Invalid Subscription Key format")] + InvalidSubscriptionKey, + + /// Indicates that conflicting parameters were supplied. + #[error("Cannot provide conflicting parameters: {0}")] + ConflictingParameters(&'static str), + + /// Wraps a standard I/O error. + #[error("I/O Error: {0}")] + Io(#[from] std::io::Error), + + /// Represents an error while parsing a header's value. + #[error("Header value parse error for '{0}': {1}")] + HeaderValueParse(&'static str, String), + + /// Indicates an invalid parameter was provided. + #[error("Invalid parameter value: {0}")] + InvalidParameter(&'static str), +} + +/// Extracts common API error details from response headers. +pub(crate) fn extract_api_error_details( + response: &Response, +) -> (String, Option, Option) { + let request_id = response + .headers() + .get("Request-ID") + .and_then(|v| v.to_str().ok()) + .unwrap_or("Unknown") + .to_string(); + let error_code = response + .headers() + .get("Error-Code") + .and_then(|v| v.to_str().ok()) + .map(String::from); + let error_message = response + .headers() + .get("Error-Message") + .and_then(|v| v.to_str().ok()) + .map(String::from); + (request_id, error_code, error_message) +} + +/// Checks the response status and returns an ApiError if it's not one of the expected statuses. +pub(crate) async fn check_status( + response: Response, + expected_statuses: &[StatusCode], +) -> Result { + let status = response.status(); + if expected_statuses.contains(&status) { + Ok(response) + } else { + let (request_id, error_code, error_message) = extract_api_error_details(&response); + Err(IntelApiError::ApiError { + status, + request_id, + error_code, + error_message, + }) + } +} diff --git a/crates/intel-dcap-api/src/lib.rs b/crates/intel-dcap-api/src/lib.rs new file mode 100644 index 0000000..a0d9e20 --- /dev/null +++ b/crates/intel-dcap-api/src/lib.rs @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +//! Intel API Client +//! +//! This module provides an API client for interacting with the Intel API for Trusted Services. +//! The API follows the documentation found at [Intel API Documentation](https://api.portal.trustedservices.intel.com/content/documentation.html). +//! +//! Create an [`ApiClient`] to interface with the Intel API. +//! +//! Example +//! ```rust,no_run +//! use intel_dcap_api::{ApiClient, IntelApiError, TcbInfoResponse}; +//! +//! #[tokio::main] +//! async fn main() -> Result<(), IntelApiError> { +//! let client = ApiClient::new()?; +//! +//! // Example: Get SGX TCB Info +//! let fmspc_example = "00606A000000"; // Example FMSPC from docs +//! match client.get_sgx_tcb_info(fmspc_example, None, None).await { +//! Ok(TcbInfoResponse { +//! tcb_info_json, +//! issuer_chain, +//! }) => println!( +//! "SGX TCB Info for {}:\n{}\nIssuer Chain: {}", +//! fmspc_example, tcb_info_json, issuer_chain +//! ), +//! Err(e) => eprintln!("Error getting SGX TCB info: {}", e), +//! } +//! +//! Ok(()) +//! } +//! ``` + +#![deny(missing_docs)] +#![deny(clippy::all)] + +mod client; +mod error; +mod requests; +mod responses; +mod types; + +// Re-export public items +pub use client::ApiClient; +pub use error::IntelApiError; +pub use responses::{ + AddPackageResponse, EnclaveIdentityJson, EnclaveIdentityResponse, FmspcJsonResponse, + PckCertificateResponse, PckCertificatesResponse, PckCrlResponse, TcbEvaluationDataNumbersJson, + TcbEvaluationDataNumbersResponse, TcbInfoJson, TcbInfoResponse, +}; +pub use types::{ApiVersion, CaType, CrlEncoding, PlatformFilter, UpdateType}; diff --git a/crates/intel-dcap-api/src/requests.rs b/crates/intel-dcap-api/src/requests.rs new file mode 100644 index 0000000..3be562c --- /dev/null +++ b/crates/intel-dcap-api/src/requests.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use serde::Serialize; + +#[derive(Serialize)] +pub(crate) struct PckCertRequest<'a> { + #[serde(rename = "platformManifest")] + pub(crate) platform_manifest: &'a str, + pub(crate) cpusvn: &'a str, + pub(crate) pcesvn: &'a str, + pub(crate) pceid: &'a str, +} + +#[derive(Serialize)] +pub(crate) struct PckCertsRequest<'a> { + #[serde(rename = "platformManifest")] + pub(crate) platform_manifest: &'a str, + pub(crate) pceid: &'a str, +} + +#[derive(Serialize)] +pub(crate) struct PckCertsConfigRequest<'a> { + #[serde(rename = "platformManifest")] + pub(crate) platform_manifest: &'a str, + pub(crate) cpusvn: &'a str, + pub(crate) pceid: &'a str, +} diff --git a/crates/intel-dcap-api/src/responses.rs b/crates/intel-dcap-api/src/responses.rs new file mode 100644 index 0000000..29e0a37 --- /dev/null +++ b/crates/intel-dcap-api/src/responses.rs @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +/// JSON structure as defined in Appendix A of the API spec. +/// Content may vary slightly between API v3 and v4. +pub type TcbInfoJson = String; + +/// JSON structure as defined in Appendix B of the API spec. +/// Content may vary slightly between API v3 and v4. +pub type EnclaveIdentityJson = String; + +/// JSON Array of {tcb, tcbm, cert}. +/// Content structure expected to be consistent between v3 and v4. +pub type PckCertsJsonResponse = String; + +/// JSON Array of {fmspc, platform}. +/// Content structure expected to be consistent between v3 and v4. +pub type FmspcJsonResponse = String; + +/// JSON structure as defined in Appendix C of the API spec (V4 ONLY). +pub type TcbEvaluationDataNumbersJson = String; + +/// Response structure for a PCK (Platform Configuration Key) Certificate. +/// +/// Contains the PCK certificate, its issuer chain, TCB measurement, and FMSPC value. +#[derive(Debug, Clone)] +pub struct PckCertificateResponse { + /// PEM-encoded PCK certificate. + pub pck_cert_pem: String, + /// PEM-encoded certificate chain for the PCK certificate issuer. + /// Header name differs between v3 ("PCS-Certificate-Issuer-Chain") and v4 ("SGX-PCK-Certificate-Issuer-Chain"). + pub issuer_chain: String, + /// TCBm value associated with the certificate (Hex-encoded). + pub tcbm: String, + /// FMSPC value associated with the certificate (Hex-encoded). + pub fmspc: String, +} + +/// Response structure for multiple PCK (Platform Configuration Key) Certificates. +/// +/// Contains a JSON array of PCK certificates, their issuer chain, and the associated FMSPC value. +/// This struct represents the response for retrieving multiple PCK certificates from the Intel SGX API. +#[derive(Debug, Clone)] +pub struct PckCertificatesResponse { + /// JSON array containing PCK certificates and their associated TCB levels. + pub pck_certs_json: PckCertsJsonResponse, // String alias for now + /// PEM-encoded certificate chain for the PCK certificate issuer. + /// Header name differs between v3 ("PCS-Certificate-Issuer-Chain") and v4 ("SGX-PCK-Certificate-Issuer-Chain"). + pub issuer_chain: String, + /// FMSPC value associated with the certificates (Hex-encoded). + pub fmspc: String, +} + +/// Response structure for TCB (Trusted Computing Base) Information. +/// +/// Contains the JSON representation of TCB information for a specific platform, +/// along with the certificate chain of the TCB Info signer. +#[derive(Debug, Clone)] +pub struct TcbInfoResponse { + /// JSON containing TCB information for a specific platform (FMSPC). + pub tcb_info_json: TcbInfoJson, // String alias for now + /// PEM-encoded certificate chain for the TCB Info signer. + /// Header name differs slightly between v3 ("SGX-TCB-Info-Issuer-Chain") and v4 ("TCB-Info-Issuer-Chain" - check spec). + pub issuer_chain: String, +} + +/// Response structure for Enclave Identity Information. +/// +/// Contains the JSON representation of enclave identity details for QE, QvE, or QAE, +/// along with its issuer chain. +#[derive(Debug, Clone)] +pub struct EnclaveIdentityResponse { + /// JSON containing information about the QE, QvE, or QAE. + pub enclave_identity_json: EnclaveIdentityJson, // String alias for now + /// PEM-encoded certificate chain for the Enclave Identity signer. + /// Header name seems consistent ("SGX-Enclave-Identity-Issuer-Chain"). + pub issuer_chain: String, +} + +/// Response structure for TCB Evaluation Data Numbers (V4 ONLY). +/// +/// Contains the JSON representation of supported TCB Evaluation Data Numbers +/// and its corresponding issuer chain. +#[derive(Debug, Clone)] +pub struct TcbEvaluationDataNumbersResponse { + /// JSON containing the list of supported TCB Evaluation Data Numbers (V4 ONLY). + pub tcb_evaluation_data_numbers_json: TcbEvaluationDataNumbersJson, // String alias for now + /// PEM-encoded certificate chain for the TCB Evaluation Data Numbers signer (V4 ONLY). + /// Header: "TCB-Evaluation-Data-Numbers-Issuer-Chain". + pub issuer_chain: String, +} + +/// Response structure for Platform Configuration Key Certificate Revocation List (PCK CRL). +/// +/// Contains the CRL data and its issuer chain for validating platform configuration keys. +#[derive(Debug, Clone)] +pub struct PckCrlResponse { + /// CRL data (PEM or DER encoded). + pub crl_data: Vec, + /// PEM-encoded certificate chain for the CRL issuer. + /// Header name differs between v3 ("PCS-CRL-Issuer-Chain") and v4 ("SGX-PCK-CRL-Issuer-Chain"). + pub issuer_chain: String, +} + +/// Response structure for the request to add a package. +pub struct AddPackageResponse { + /// Platform Membership Certificates + pub pck_certs: Vec, + /// The certificate count extracted from the response header. + pub pck_cert_count: usize, +} diff --git a/crates/intel-dcap-api/src/types.rs b/crates/intel-dcap-api/src/types.rs new file mode 100644 index 0000000..07b73f1 --- /dev/null +++ b/crates/intel-dcap-api/src/types.rs @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use std::fmt; + +/// Represents the type of Certificate Authority (CA) for Intel Trusted Services. +/// +/// This enum defines the different types of Certificate Authorities used in the Intel DCAP API, +/// specifically distinguishing between processor and platform CAs. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CaType { + /// Represents a processor-specific Certificate Authority. + Processor, + /// Represents a platform-wide Certificate Authority. + Platform, +} + +impl fmt::Display for CaType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CaType::Processor => write!(f, "processor"), + CaType::Platform => write!(f, "platform"), + } + } +} + +/// Represents the encoding format for Certificate Revocation Lists (CRLs). +/// +/// This enum defines the supported encoding formats for CRLs in the Intel DCAP API, +/// distinguishing between PEM (Privacy Enhanced Mail) and DER (Distinguished Encoding Rules) formats. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CrlEncoding { + /// Represents the PEM (Privacy Enhanced Mail) encoding format. + Pem, + /// Represents the DER (Distinguished Encoding Rules) encoding format. + Der, +} + +impl fmt::Display for CrlEncoding { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CrlEncoding::Pem => write!(f, "pem"), + CrlEncoding::Der => write!(f, "der"), + } + } +} + +/// Represents the type of update for Intel Trusted Services. +/// +/// This enum defines different update types, distinguishing between early and standard updates +/// in the Intel DCAP (Data Center Attestation Primitives) API. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UpdateType { + /// Represents early updates, typically used for preview or beta releases. + Early, + /// Represents standard updates, which are the regular release cycle. + Standard, +} + +impl fmt::Display for UpdateType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + UpdateType::Early => write!(f, "early"), + UpdateType::Standard => write!(f, "standard"), + } + } +} + +/// Represents the platform filter options for Intel DCAP (Data Center Attestation Primitives) API. +/// +/// This enum allows filtering platforms based on different criteria, +/// such as selecting all platforms, client-specific platforms, or specific Intel processor generations. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PlatformFilter { + /// Represents a selection of all available platforms. + All, + /// Represents a selection of client-specific platforms. + Client, + /// Represents platforms with Intel E3 processors. + E3, + /// Represents platforms with Intel E5 processors. + E5, +} + +impl fmt::Display for PlatformFilter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PlatformFilter::All => write!(f, "all"), + PlatformFilter::Client => write!(f, "client"), + PlatformFilter::E3 => write!(f, "E3"), + PlatformFilter::E5 => write!(f, "E5"), + } + } +} + +/// Represents the version of the Intel Trusted Services API to target. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ApiVersion { + /// Represents version 3 of the Intel Trusted Services API. + V3, + /// Represents version 4 of the Intel Trusted Services API. + V4, +} + +impl ApiVersion { + /// Returns the string representation of the version for URL paths. + pub fn path_segment(&self) -> &'static str { + match self { + ApiVersion::V3 => "v3", + ApiVersion::V4 => "v4", + } + } +} + +impl fmt::Display for ApiVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ApiVersion::V3 => write!(f, "v3"), + ApiVersion::V4 => write!(f, "v4"), + } + } +} From 0e69105a43e4e8d4ee0cdaa17d26633bed817a9c Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 11 Apr 2025 11:04:17 +0200 Subject: [PATCH 074/114] refactor(intel-dcap-api): split client.rs into smaller files Signed-off-by: Harald Hoyer --- crates/intel-dcap-api/src/client.rs | 1324 ----------------- .../src/client/enclave_identity.rs | 229 +++ crates/intel-dcap-api/src/client/fmspc.rs | 134 ++ crates/intel-dcap-api/src/client/helpers.rs | 234 +++ crates/intel-dcap-api/src/client/mod.rs | 120 ++ crates/intel-dcap-api/src/client/pck_cert.rs | 353 +++++ crates/intel-dcap-api/src/client/pck_crl.rs | 67 + .../intel-dcap-api/src/client/registration.rs | 106 ++ crates/intel-dcap-api/src/client/tcb_info.rs | 167 +++ 9 files changed, 1410 insertions(+), 1324 deletions(-) delete mode 100644 crates/intel-dcap-api/src/client.rs create mode 100644 crates/intel-dcap-api/src/client/enclave_identity.rs create mode 100644 crates/intel-dcap-api/src/client/fmspc.rs create mode 100644 crates/intel-dcap-api/src/client/helpers.rs create mode 100644 crates/intel-dcap-api/src/client/mod.rs create mode 100644 crates/intel-dcap-api/src/client/pck_cert.rs create mode 100644 crates/intel-dcap-api/src/client/pck_crl.rs create mode 100644 crates/intel-dcap-api/src/client/registration.rs create mode 100644 crates/intel-dcap-api/src/client/tcb_info.rs diff --git a/crates/intel-dcap-api/src/client.rs b/crates/intel-dcap-api/src/client.rs deleted file mode 100644 index 294b6fb..0000000 --- a/crates/intel-dcap-api/src/client.rs +++ /dev/null @@ -1,1324 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2025 Matter Labs - -use crate::responses::AddPackageResponse; -use crate::{ - error::{check_status, extract_api_error_details, IntelApiError}, - requests::{PckCertRequest, PckCertsConfigRequest, PckCertsRequest}, - responses::{ - EnclaveIdentityResponse, PckCertificateResponse, PckCertificatesResponse, PckCrlResponse, - TcbEvaluationDataNumbersResponse, TcbInfoResponse, - }, - types::{ApiVersion, CaType, CrlEncoding, PlatformFilter, UpdateType}, // Import ApiVersion - FmspcJsonResponse, -}; -use percent_encoding::percent_decode_str; -use reqwest::{header, Client, IntoUrl, RequestBuilder, Response, StatusCode}; -use std::num::ParseIntError; -use url::Url; - -// Base URL for the Intel Trusted Services API -const BASE_URL: &str = "https://api.trustedservices.intel.com"; - -/// Client for interacting with Intel Trusted Services API. -/// -/// Provides methods to access both SGX and TDX certification services, -/// supporting API versions V3 and V4. This client offers functionality -/// to register platforms, retrieve PCK certificates and CRLs, fetch TCB -/// information, enclave identities, as well as TCB evaluation data numbers. -/// -/// # Examples -/// -/// ```rust,no_run -/// use intel_dcap_api::ApiClient; -/// -/// #[tokio::main] -/// async fn main() -> Result<(), Box> { -/// // Create a client with default settings (V4 API) -/// let client = ApiClient::new()?; -/// -/// // Retrieve TCB info for a specific FMSPC -/// let tcb_info = client.get_sgx_tcb_info("00606A000000", None, None).await?; -/// println!("TCB Info: {}", tcb_info.tcb_info_json); -/// -/// Ok(()) -/// } -/// ``` -#[derive(Clone)] -pub struct ApiClient { - client: Client, - base_url: Url, - api_version: ApiVersion, -} - -impl ApiClient { - /// Creates a new client targeting the latest supported API version (V4). - /// - /// # Returns - /// - /// A result containing the newly created `ApiClient` or an `IntelApiError` if there - /// was an issue building the underlying HTTP client. - /// - /// # Errors - /// - /// This function may fail if the provided TLS version or base URL - /// cannot be used to build a `reqwest` client. - pub fn new() -> Result { - Self::new_with_options(BASE_URL, ApiVersion::V4) // Default to V4 - } - - /// Creates a new client targeting a specific API version. - /// - /// # Arguments - /// - /// * `api_version` - The desired API version to use (V3 or V4). - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the `reqwest` client cannot be built - /// with the specified options. - pub fn new_with_version(api_version: ApiVersion) -> Result { - Self::new_with_options(BASE_URL, api_version) - } - - /// Creates a new client with a custom base URL, targeting the latest supported API version (V4). - /// - /// # Arguments - /// - /// * `base_url` - The custom base URL for the Intel Trusted Services API. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the `reqwest` client cannot be built - /// or if the provided base URL is invalid. - pub fn new_with_base_url(base_url: impl IntoUrl) -> Result { - Self::new_with_options(base_url, ApiVersion::V4) // Default to V4 - } - - /// Creates a new client with a custom base URL and specific API version. - /// - /// # Arguments - /// - /// * `base_url` - The custom base URL for the Intel Trusted Services API. - /// * `api_version` - The desired API version (V3 or V4). - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the `reqwest` client cannot be built - /// or if the provided base URL is invalid. - pub fn new_with_options( - base_url: impl IntoUrl, - api_version: ApiVersion, - ) -> Result { - Ok(ApiClient { - client: Client::builder() - .min_tls_version(reqwest::tls::Version::TLS_1_2) - .build()?, - base_url: base_url.into_url()?, - api_version, // Store the version - }) - } - - /// POST /sgx/registration/v1/platform - /// Registers a multi-package SGX platform with the Intel Trusted Services API. - /// - /// # Arguments - /// - /// * `platform_manifest` - Binary data representing the platform manifest. - /// - /// # Returns - /// - /// Request body is binary Platform Manifest - /// Returns the hex-encoded PPID as a `String` upon success. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails or if the response status - /// is not HTTP `201 CREATED`. - pub async fn register_platform( - &self, - platform_manifest: Vec, - ) -> Result { - // Registration paths are fixed, use the helper with "registration" service - let path = self.build_api_path("sgx", "registration", "platform")?; - let url = self.base_url.join(&path)?; - - let response = self - .client - .post(url) - .header(header::CONTENT_TYPE, "application/octet-stream") - .body(platform_manifest) - .send() - .await?; - - let response = check_status(response, &[StatusCode::CREATED]).await?; - - // Response body is hex-encoded PPID - let ppid_hex = response.text().await?; - Ok(ppid_hex) - } - - /// POST /sgx/registration/v1/package - /// Adds new package(s) to an already registered SGX platform instance. - /// - /// # Arguments - /// - /// * `add_package_request` - Binary data for the "Add Package" request body. - /// * `subscription_key` - The subscription key required by the Intel API. - /// - /// # Returns - /// - /// A [`AddPackageResponse`] containing the Platform Membership Certificates and - /// the count of them extracted from the response header. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails, if the subscription key is invalid, - /// or if the response status is not HTTP `200 OK`. - pub async fn add_package( - &self, - add_package_request: Vec, - subscription_key: &str, - ) -> Result { - if subscription_key.is_empty() { - return Err(IntelApiError::InvalidSubscriptionKey); - } - - // Registration paths are fixed - let path = self.build_api_path("sgx", "registration", "package")?; - let url = self.base_url.join(&path)?; - - let response = self - .client - .post(url) - .header("Ocp-Apim-Subscription-Key", subscription_key) - .header(header::CONTENT_TYPE, "application/octet-stream") - .body(add_package_request) - .send() - .await?; - - let response = check_status(response, &[StatusCode::OK]).await?; - - // Use the generic header helper, assuming header name is stable across reg versions - let cert_count_str = self.get_required_header(&response, "Certificate-Count", None)?; - let pck_cert_count: usize = cert_count_str.parse().map_err(|e: ParseIntError| { - IntelApiError::HeaderValueParse("Certificate-Count", e.to_string()) - })?; - - // Response body is a binary array of certificates - let pck_certs = response.bytes().await?.to_vec(); - Ok(AddPackageResponse { - pck_certs, - pck_cert_count, - }) - } - - // === Provisioning Certification Service === - - /// GET /sgx/certification/{v3,v4}/pckcert - /// Retrieves a single SGX PCK certificate using encrypted PPID and SVNs. - /// - /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter - /// is only valid for API v4 and allows specifying the PPID encryption key type (e.g. "RSA-3072"). - /// - /// # Arguments - /// - /// * `encrypted_ppid` - Hex-encoded encrypted PPID. - /// * `cpusvn` - Hex-encoded CPUSVN value. - /// * `pcesvn` - Hex-encoded PCESVN value. - /// * `pceid` - Hex-encoded PCEID value. - /// * `subscription_key` - Optional subscription key if the Intel API requires it. - /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). - /// - /// # Returns - /// - /// A [`PckCertificateResponse`] containing the PEM-encoded certificate, issuer chain, - /// TCBm, and FMSPC. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the API call fails or the response contains an invalid status. - /// Returns PEM Cert, Issuer Chain, TCBm, FMSPC. - pub async fn get_pck_certificate_by_ppid( - &self, - encrypted_ppid: &str, - cpusvn: &str, - pcesvn: &str, - pceid: &str, - subscription_key: Option<&str>, - ppid_encryption_key_type: Option<&str>, - ) -> Result { - // Check V4-only parameter - self.check_v4_only_param(ppid_encryption_key_type, "PPID-Encryption-Key")?; - - let path = self.build_api_path("sgx", "", "pckcert")?; // service is empty - let mut url = self.base_url.join(&path)?; - url.query_pairs_mut() - .append_pair("encrypted_ppid", encrypted_ppid) - .append_pair("cpusvn", cpusvn) - .append_pair("pcesvn", pcesvn) - .append_pair("pceid", pceid); - - let mut request_builder = self.client.get(url); - - request_builder = Self::maybe_add_header( - request_builder, - "Ocp-Apim-Subscription-Key", - subscription_key, - ); - - // Only add for V4 - if self.api_version == ApiVersion::V4 { - request_builder = Self::maybe_add_header( - request_builder, - "PPID-Encryption-Key", - ppid_encryption_key_type, - ); - } - - self.fetch_pck_certificate(request_builder).await - } - - /// POST /sgx/certification/{v3,v4}/pckcert - /// Retrieves a single SGX PCK certificate using a platform manifest and SVNs. - /// - /// Optionally requires a subscription key. - /// - /// # Arguments - /// - /// * `platform_manifest` - Hex-encoded platform manifest. - /// * `cpusvn` - Hex-encoded CPUSVN value. - /// * `pcesvn` - Hex-encoded PCESVN value. - /// * `pceid` - Hex-encoded PCEID value. - /// * `subscription_key` - Optional subscription key if the Intel API requires it. - /// - /// # Returns - /// - /// A [`PckCertificateResponse`] containing the PEM-encoded certificate, issuer chain, - /// TCBm, and FMSPC. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails or if the response is invalid. - /// Returns PEM Cert, Issuer Chain, TCBm, FMSPC. - pub async fn get_pck_certificate_by_manifest( - &self, - platform_manifest: &str, - cpusvn: &str, - pcesvn: &str, - pceid: &str, - subscription_key: Option<&str>, - ) -> Result { - let path = self.build_api_path("sgx", "", "pckcert")?; - let url = self.base_url.join(&path)?; - let request_body = PckCertRequest { - platform_manifest, - cpusvn, - pcesvn, - pceid, - }; - - let mut request_builder = self - .client - .post(url) - .header(header::CONTENT_TYPE, "application/json") - .json(&request_body); - - request_builder = Self::maybe_add_header( - request_builder, - "Ocp-Apim-Subscription-Key", - subscription_key, - ); - - self.fetch_pck_certificate(request_builder).await - } - - /// GET /sgx/certification/{v3,v4}/pckcerts - /// Retrieves all SGX PCK certificates for a platform using encrypted PPID. - /// - /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter - /// is only valid for API v4. - /// - /// # Arguments - /// - /// * `encrypted_ppid` - Hex-encoded encrypted PPID. - /// * `pceid` - Hex-encoded PCEID value. - /// * `subscription_key` - Optional subscription key if the Intel API requires it. - /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). - /// - /// # Returns - /// - /// A [`PckCertificatesResponse`] containing JSON with `{tcb, tcbm, cert}` entries, - /// as well as the issuer chain and FMSPC headers. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the API call fails or the response status is invalid. - pub async fn get_pck_certificates_by_ppid( - &self, - encrypted_ppid: &str, - pceid: &str, - subscription_key: Option<&str>, - ppid_encryption_key_type: Option<&str>, - ) -> Result { - // Check V4-only parameter - self.check_v4_only_param(ppid_encryption_key_type, "PPID-Encryption-Key")?; - - let path = self.build_api_path("sgx", "", "pckcerts")?; - let mut url = self.base_url.join(&path)?; - url.query_pairs_mut() - .append_pair("encrypted_ppid", encrypted_ppid) - .append_pair("pceid", pceid); - - let mut request_builder = self.client.get(url); - - request_builder = Self::maybe_add_header( - request_builder, - "Ocp-Apim-Subscription-Key", - subscription_key, - ); - - // Only add for V4 - if self.api_version == ApiVersion::V4 { - request_builder = Self::maybe_add_header( - request_builder, - "PPID-Encryption-Key", - ppid_encryption_key_type, - ); - } - - self.fetch_pck_certificates(request_builder).await - } - - /// POST /sgx/certification/{v3,v4}/pckcerts - /// Retrieves all SGX PCK certificates for a platform using a platform manifest. - /// - /// Optionally requires a subscription key. - /// - /// # Arguments - /// - /// * `platform_manifest` - Hex-encoded platform manifest. - /// * `pceid` - Hex-encoded PCEID value. - /// * `subscription_key` - Optional subscription key if the Intel API requires it. - /// - /// # Returns - /// - /// A [`PckCertificatesResponse`] containing JSON with `{tcb, tcbm, cert}` entries, - /// as well as the issuer chain and FMSPC headers. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the API call fails or the response status is invalid. - pub async fn get_pck_certificates_by_manifest( - &self, - platform_manifest: &str, - pceid: &str, - subscription_key: Option<&str>, - ) -> Result { - let path = self.build_api_path("sgx", "", "pckcerts")?; - let url = self.base_url.join(&path)?; - let request_body = PckCertsRequest { - platform_manifest, - pceid, - }; - - let mut request_builder = self - .client - .post(url) - .header(header::CONTENT_TYPE, "application/json") - .json(&request_body); - - request_builder = Self::maybe_add_header( - request_builder, - "Ocp-Apim-Subscription-Key", - subscription_key, - ); - - self.fetch_pck_certificates(request_builder).await - } - - /// GET /sgx/certification/{v3,v4}/pckcerts/config (using PPID) - /// Retrieves SGX PCK certificates for a specific configuration (CPUSVN) using encrypted PPID. - /// - /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter - /// is only valid for API v4. Returns JSON with `{tcb, tcbm, cert}` entries, - /// as well as the issuer chain and FMSPC headers. - /// - /// # Arguments - /// - /// * `encrypted_ppid` - Hex-encoded encrypted PPID. - /// * `pceid` - Hex-encoded PCEID value. - /// * `cpusvn` - Hex-encoded CPUSVN value for the requested configuration. - /// * `subscription_key` - Optional subscription key if the Intel API requires it. - /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). - /// - /// # Returns - /// - /// A [`PckCertificatesResponse`] with the requested config's certificate data. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails or if the response status - /// is not `200 OK`. - pub async fn get_pck_certificates_config_by_ppid( - &self, - encrypted_ppid: &str, - pceid: &str, - cpusvn: &str, - subscription_key: Option<&str>, - ppid_encryption_key_type: Option<&str>, - ) -> Result { - // V3 does not support PPID-Encryption-Key header/type - if self.api_version == ApiVersion::V3 && ppid_encryption_key_type.is_some() { - return Err(IntelApiError::UnsupportedApiVersion( - "PPID-Encryption-Key header is only supported in API v4".to_string(), - )); - } - - let path = self.build_api_path("sgx", "", "pckcerts/config")?; - let mut url = self.base_url.join(&path)?; - url.query_pairs_mut() - .append_pair("encrypted_ppid", encrypted_ppid) - .append_pair("pceid", pceid) - .append_pair("cpusvn", cpusvn); - - let mut request_builder = self.client.get(url); - - request_builder = Self::maybe_add_header( - request_builder, - "Ocp-Apim-Subscription-Key", - subscription_key, - ); - - // Only add for V4 - if self.api_version == ApiVersion::V4 { - request_builder = Self::maybe_add_header( - request_builder, - "PPID-Encryption-Key", - ppid_encryption_key_type, - ); - } - - self.fetch_pck_certificates(request_builder).await - } - - /// POST /sgx/certification/{v3,v4}/pckcerts/config (using Manifest) - /// Retrieves SGX PCK certificates for a specific configuration (CPUSVN) using a platform manifest. - /// - /// Optionally requires a subscription key. Returns JSON with `{tcb, tcbm, cert}` entries, - /// as well as the issuer chain and FMSPC headers. - /// - /// # Arguments - /// - /// * `platform_manifest` - Hex-encoded platform manifest. - /// * `pceid` - Hex-encoded PCEID value. - /// * `cpusvn` - Hex-encoded CPUSVN value for the requested configuration. - /// * `subscription_key` - Optional subscription key if needed by the Intel API. - /// - /// # Returns - /// - /// A [`PckCertificatesResponse`] with the requested config's certificate data. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails or if the response status - /// is not `200 OK`. - pub async fn get_pck_certificates_config_by_manifest( - &self, - platform_manifest: &str, - pceid: &str, - cpusvn: &str, - subscription_key: Option<&str>, - ) -> Result { - let path = self.build_api_path("sgx", "", "pckcerts/config")?; - let url = self.base_url.join(&path)?; - let request_body = PckCertsConfigRequest { - platform_manifest, - pceid, - cpusvn, - }; - - let mut request_builder = self - .client - .post(url) - .header(header::CONTENT_TYPE, "application/json") - .json(&request_body); - - request_builder = Self::maybe_add_header( - request_builder, - "Ocp-Apim-Subscription-Key", - subscription_key, - ); - - self.fetch_pck_certificates(request_builder).await - } - - /// GET /sgx/certification/{v3,v4}/pckcrl - /// Retrieves the PCK Certificate Revocation List (CRL) for a specified CA type. - /// - /// Optionally takes an `encoding` parameter indicating whether the CRL should be - /// returned as PEM or DER. Defaults to PEM if not specified. - /// - /// # Arguments - /// - /// * `ca_type` - The type of CA to retrieve the CRL for (e.g., "processor" or "platform"). - /// * `encoding` - An optional [`CrlEncoding`] (PEM or DER). - /// - /// # Returns - /// - /// A [`PckCrlResponse`] containing the CRL data and the issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails or if the response status - /// is not `200 OK`. - /// Optional 'encoding' parameter ("pem" or "der"). - /// Returns CRL data (PEM or DER) and Issuer Chain header. - pub async fn get_pck_crl( - &self, - ca_type: CaType, - encoding: Option, - ) -> Result { - let path = self.build_api_path("sgx", "", "pckcrl")?; - let mut url = self.base_url.join(&path)?; - url.query_pairs_mut() - .append_pair("ca", &ca_type.to_string()); - - if let Some(enc) = encoding { - url.query_pairs_mut() - .append_pair("encoding", &enc.to_string()); - } - - let request_builder = self.client.get(url); - let response = request_builder.send().await?; - let response = check_status(response, &[StatusCode::OK]).await?; - - let issuer_chain = self.get_required_header( - &response, - "SGX-PCK-CRL-Issuer-Chain", // v4 name - Some("SGX-PCK-CRL-Issuer-Chain"), // v3 name - )?; - - // Response body is PEM or DER CRL - let crl_data = response.bytes().await?.to_vec(); - - Ok(PckCrlResponse { - crl_data, - issuer_chain, - }) - } - - // --- TCB Info --- - - /// GET /sgx/certification/{v3,v4}/tcb - /// Retrieves SGX TCB information for a given FMSPC. - /// - /// Returns TCB Info JSON string (Appendix A) and Issuer Chain header. - /// This function supports both API v3 and v4. The `update` and `tcbEvaluationDataNumber` - /// parameters are only supported by API v4. If both are provided at the same time (for v4), - /// a conflict error is returned. - /// - /// # Arguments - /// - /// * `fmspc` - Hex-encoded FMSPC value. - /// * `update` - Optional [`UpdateType`] for API v4. - /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). - /// - /// # Returns - /// - /// A [`TcbInfoResponse`] containing the TCB info JSON and the issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the API request fails, if conflicting parameters are used, - /// or if the requested TCB data is not found. - pub async fn get_sgx_tcb_info( - &self, - fmspc: &str, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - // V3 does not support 'update' or 'tcbEvaluationDataNumber' - if self.api_version == ApiVersion::V3 && update.is_some() { - return Err(IntelApiError::UnsupportedApiVersion( - "'update' parameter requires API v4".to_string(), - )); - } - if self.api_version == ApiVersion::V3 && tcb_evaluation_data_number.is_some() { - return Err(IntelApiError::UnsupportedApiVersion( - "'tcbEvaluationDataNumber' parameter requires API v4".to_string(), - )); - } - if self.api_version == ApiVersion::V4 - && update.is_some() - && tcb_evaluation_data_number.is_some() - { - return Err(IntelApiError::ConflictingParameters( - "'update' and 'tcbEvaluationDataNumber'", - )); - } - - let path = self.build_api_path("sgx", "", "tcb")?; - let mut url = self.base_url.join(&path)?; - url.query_pairs_mut().append_pair("fmspc", fmspc); - - // Add V4-specific parameters - if self.api_version == ApiVersion::V4 { - if let Some(upd) = update { - url.query_pairs_mut() - .append_pair("update", &upd.to_string()); - } - if let Some(tedn) = tcb_evaluation_data_number { - url.query_pairs_mut() - .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); - } - } - - let request_builder = self.client.get(url); - - // Special handling for 404/410 when tcbEvaluationDataNumber is specified (V4 only) - if self.api_version == ApiVersion::V4 { - if let Some(tedn_val) = tcb_evaluation_data_number { - // Use the helper function to check status before proceeding - self.check_tcb_evaluation_status(&request_builder, tedn_val, "SGX TCB Info") - .await?; - // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain - } - } - - // Fetch JSON and header (header name seems same for v3/v4) - let (tcb_info_json, issuer_chain) = self - .fetch_json_with_issuer_chain( - request_builder, - "TCB-Info-Issuer-Chain", // v4 name - Some("SGX-TCB-Info-Issuer-Chain"), // v3 name - ) - .await?; - - Ok(TcbInfoResponse { - tcb_info_json, - issuer_chain, - }) - } - - /// GET /tdx/certification/v4/tcb - /// Retrieves TDX TCB information for a given FMSPC (API v4 only). - /// - /// # Arguments - /// - /// * `fmspc` - Hex-encoded FMSPC value. - /// * `update` - An optional [`UpdateType`] (v4 only). - /// * `tcb_evaluation_data_number` - An optional TCB Evaluation Data Number (v4 only). - /// - /// # Returns - /// - /// A [`TcbInfoResponse`] containing TDX TCB info JSON and the issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if an unsupported API version is used, - /// if there are conflicting parameters, or if the TDX TCB data is not found. - /// Returns TCB Info JSON string (Appendix A) and Issuer Chain header. - pub async fn get_tdx_tcb_info( - &self, - fmspc: &str, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - // Ensure V4 API - self.ensure_v4_api("get_tdx_tcb_info")?; - // Check conflicting parameters (only relevant for V4, checked inside helper) - self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; - - let path = self.build_api_path("tdx", "", "tcb")?; - let mut url = self.base_url.join(&path)?; - url.query_pairs_mut().append_pair("fmspc", fmspc); - - if let Some(upd) = update { - url.query_pairs_mut() - .append_pair("update", &upd.to_string()); - } - if let Some(tedn) = tcb_evaluation_data_number { - url.query_pairs_mut() - .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); - } - - let request_builder = self.client.get(url); - - // Special handling for 404/410 when tcbEvaluationDataNumber is specified - if let Some(tedn_val) = tcb_evaluation_data_number { - // Use the helper function to check status before proceeding - self.check_tcb_evaluation_status(&request_builder, tedn_val, "TDX TCB Info") - .await?; - // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain - } - - // Fetch JSON and header (TDX only exists in V4) - let (tcb_info_json, issuer_chain) = self - .fetch_json_with_issuer_chain(request_builder, "TCB-Info-Issuer-Chain", None) - .await?; - - Ok(TcbInfoResponse { - tcb_info_json, - issuer_chain, - }) - } - - // --- Enclave Identity --- - - /// Retrieves the SGX QE Identity from the Intel API. - /// - /// Returns Enclave Identity JSON string (Appendix B) and Issuer Chain header. - /// Supports both v3 and v4. The `update` and `tcb_evaluation_data_number` - /// parameters are only valid in API v4. Returns the enclave identity JSON - /// and an issuer chain header. - /// - /// # Arguments - /// - /// * `update` - Optional [`UpdateType`] (v4 only). - /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). - /// - /// # Returns - /// - /// An [`EnclaveIdentityResponse`] containing the JSON identity and issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails, if conflicting v4 parameters are used, - /// or if the desired identity resource is not found. - pub async fn get_sgx_qe_identity( - &self, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - self.get_sgx_enclave_identity("qe", update, tcb_evaluation_data_number) - .await - } - - /// Retrieves the TDX QE Identity from the Intel API (API v4 only). - /// - /// # Arguments - /// - /// * `update` - Optional [`UpdateType`] (v4 only). - /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). - /// - /// # Returns - /// - /// An [`EnclaveIdentityResponse`] containing the JSON identity and issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if an unsupported API version is used, - /// if conflicting parameters are provided, or if the identity resource is not found. - /// GET /tdx/certification/v4/qe/identity - V4 ONLY - pub async fn get_tdx_qe_identity( - &self, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - // Ensure V4 API - self.ensure_v4_api("get_tdx_qe_identity")?; - // Check conflicting parameters (only relevant for V4, checked inside helper) - self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; - - let path = self.build_api_path("tdx", "qe", "identity")?; - let mut url = self.base_url.join(&path)?; - - if let Some(upd) = update { - url.query_pairs_mut() - .append_pair("update", &upd.to_string()); - } - if let Some(tedn) = tcb_evaluation_data_number { - url.query_pairs_mut() - .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); - } - - let request_builder = self.client.get(url); - - // Special handling for 404/410 when tcbEvaluationDataNumber is specified - if let Some(tedn_val) = tcb_evaluation_data_number { - // Use the helper function to check status before proceeding - self.check_tcb_evaluation_status(&request_builder, tedn_val, "TDX QE Identity") - .await?; - // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain - } - - // Fetch JSON and header (TDX only exists in V4) - let (enclave_identity_json, issuer_chain) = self - .fetch_json_with_issuer_chain( - request_builder, - "SGX-Enclave-Identity-Issuer-Chain", - None, - ) - .await?; - - Ok(EnclaveIdentityResponse { - enclave_identity_json, - issuer_chain, - }) - } - - /// Retrieves the SGX QVE Identity from the Intel API. - /// - /// Supports API v3 and v4. The `update` and `tcb_evaluation_data_number` parameters - /// are v4 only. Returns the QVE identity JSON and issuer chain. - /// - /// # Arguments - /// - /// * `update` - Optional [`UpdateType`] (v4 only). - /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). - /// - /// # Returns - /// - /// An [`EnclaveIdentityResponse`] containing the QVE identity JSON and issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails, if conflicting parameters are used, - /// or if the identity resource is not found. - /// GET /sgx/certification/{v3,v4}/qve/identity - pub async fn get_sgx_qve_identity( - &self, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - self.get_sgx_enclave_identity("qve", update, tcb_evaluation_data_number) - .await - } - - /// Retrieves the SGX QAE Identity from the Intel API (API v4 only). - /// - /// # Arguments - /// - /// * `update` - Optional [`UpdateType`] (v4 only). - /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). - /// - /// # Returns - /// - /// An [`EnclaveIdentityResponse`] containing the QAE identity JSON and issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if an unsupported API version is used, - /// if conflicting parameters are provided, or if the QAE identity is not found. - /// GET /sgx/certification/v4/qae/identity - V4 ONLY - pub async fn get_sgx_qae_identity( - &self, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - // QAE endpoint requires V4 - if self.api_version != ApiVersion::V4 { - return Err(IntelApiError::UnsupportedApiVersion( - "QAE Identity endpoint requires API v4".to_string(), - )); - } - // Call the generic helper, it will handle V4 params and 404/410 checks - self.get_sgx_enclave_identity("qae", update, tcb_evaluation_data_number) - .await - } - - // --- FMSPCs & TCB Evaluation Data Numbers --- - - /// GET /sgx/certification/{v3,v4}/fmspcs - /// Retrieves a list of FMSPC values for SGX and TDX platforms (API v4 only). - /// - /// # Arguments - /// - /// * `platform_filter` - An optional filter specifying SGX or TDX platforms. - /// - /// # Returns - /// - /// Optional 'platform' filter. - /// A `String` containing the JSON array of objects, each containing `fmspc` and `platform`. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. - pub async fn get_fmspcs( - &self, - platform_filter: Option, - ) -> Result { - if self.api_version == ApiVersion::V3 { - return Err(IntelApiError::UnsupportedApiVersion( - "API v4 only function".to_string(), - )); - } - let path = self.build_api_path("sgx", "", "fmspcs")?; - let mut url = self.base_url.join(&path)?; - - if let Some(pf) = platform_filter { - url.query_pairs_mut() - .append_pair("platform", &pf.to_string()); - } - - let request_builder = self.client.get(url); - let response = request_builder.send().await?; - let response = check_status(response, &[StatusCode::OK]).await?; - - let fmspcs_json = response.text().await?; - - Ok(fmspcs_json) - } - - /// GET /sgx/certification/v4/tcbevaluationdatanumbers - V4 ONLY - /// Retrieves the currently supported SGX TCB Evaluation Data Numbers (API v4 only). - /// - /// # Returns - /// - /// A [`TcbEvaluationDataNumbersResponse`] containing the JSON structure of TCB Evaluation - /// Data Numbers and an issuer chain header. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. - pub async fn get_sgx_tcb_evaluation_data_numbers( - &self, - ) -> Result { - // Endpoint requires V4 - if self.api_version != ApiVersion::V4 { - return Err(IntelApiError::UnsupportedApiVersion( - "SGX TCB Evaluation Data Numbers endpoint requires API v4".to_string(), - )); - } - - let path = self.build_api_path("sgx", "", "tcbevaluationdatanumbers")?; - let url = self.base_url.join(&path)?; - let request_builder = self.client.get(url); - - let (tcb_evaluation_data_numbers_json, issuer_chain) = self - .fetch_json_with_issuer_chain( - request_builder, - "TCB-Evaluation-Data-Numbers-Issuer-Chain", - None, - ) - .await?; - - Ok(TcbEvaluationDataNumbersResponse { - tcb_evaluation_data_numbers_json, - issuer_chain, - }) - } - - /// GET /tdx/certification/v4/tcbevaluationdatanumbers - V4 ONLY - /// Retrieves the currently supported TDX TCB Evaluation Data Numbers (API v4 only). - /// - /// # Returns - /// - /// A [`TcbEvaluationDataNumbersResponse`] containing the JSON structure of TCB Evaluation - /// Data Numbers and an issuer chain header. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. - pub async fn get_tdx_tcb_evaluation_data_numbers( - &self, - ) -> Result { - // Endpoint requires V4 - if self.api_version != ApiVersion::V4 { - return Err(IntelApiError::UnsupportedApiVersion( - "TDX TCB Evaluation Data Numbers endpoint requires API v4".to_string(), - )); - } - - let path = self.build_api_path("tdx", "", "tcbevaluationdatanumbers")?; - let url = self.base_url.join(&path)?; - let request_builder = self.client.get(url); - - let (tcb_evaluation_data_numbers_json, issuer_chain) = self - .fetch_json_with_issuer_chain( - request_builder, - "TCB-Evaluation-Data-Numbers-Issuer-Chain", - None, - ) - .await?; - - Ok(TcbEvaluationDataNumbersResponse { - tcb_evaluation_data_numbers_json, - issuer_chain, - }) - } - - // ------------------------ - // Internal helper methods - // ------------------------ - - /// Helper to construct API paths dynamically based on version and technology (SGX/TDX). - fn build_api_path( - &self, - technology: &str, - service: &str, - endpoint: &str, - ) -> Result { - let api_segment = self.api_version.path_segment(); - - if technology == "tdx" && self.api_version == ApiVersion::V3 { - return Err(IntelApiError::UnsupportedApiVersion(format!( - "TDX endpoint /{}/{}/{} requires API v4", - service, endpoint, technology - ))); - } - if technology == "sgx" && service == "registration" { - return Ok(format!("/sgx/registration/v1/{}", endpoint).replace("//", "/")); - } - - Ok(format!( - "/{}/certification/{}/{}/{}", - technology, api_segment, service, endpoint - ) - .replace("//", "/")) - } - - /// Helper to add an optional header if the string is non-empty. - fn maybe_add_header( - builder: RequestBuilder, - header_name: &'static str, - header_value: Option<&str>, - ) -> RequestBuilder { - match header_value { - Some(value) if !value.is_empty() => builder.header(header_name, value), - _ => builder, - } - } - - /// Helper to extract a required header string value, handling potential v3/v4 differences. - fn get_required_header( - &self, - response: &Response, - v4_header_name: &'static str, - v3_header_name: Option<&'static str>, - ) -> Result { - let header_name = match self.api_version { - ApiVersion::V4 => v4_header_name, - ApiVersion::V3 => v3_header_name.unwrap_or(v4_header_name), - }; - let value = response - .headers() - .get(header_name) - .ok_or(IntelApiError::MissingOrInvalidHeader(header_name))? - .to_str() - .map_err(|e| IntelApiError::HeaderValueParse(header_name, e.to_string()))?; - - if value.contains('%') { - percent_decode_str(value) - .decode_utf8() - .map_err(|e| IntelApiError::HeaderValueParse(header_name, e.to_string())) - .map(|s| s.to_string()) - } else { - Ok(value.to_string()) - } - } - - /// Helper to execute a request that returns a single PCK certificate and associated headers. - async fn fetch_pck_certificate( - &self, - request_builder: RequestBuilder, - ) -> Result { - let response = request_builder.send().await?; - let response = check_status(response, &[StatusCode::OK]).await?; - - let issuer_chain = self.get_required_header( - &response, - "SGX-PCK-Certificate-Issuer-Chain", - Some("SGX-PCK-Certificate-Issuer-Chain"), - )?; - let tcbm = self.get_required_header(&response, "SGX-TCBm", Some("SGX-TCBm"))?; - let fmspc = self.get_required_header(&response, "SGX-FMSPC", Some("SGX-FMSPC"))?; - let pck_cert_pem = response.text().await?; - - Ok(PckCertificateResponse { - pck_cert_pem, - issuer_chain, - tcbm, - fmspc, - }) - } - - /// Helper to execute a request that returns a PCK certificates JSON array and associated headers. - async fn fetch_pck_certificates( - &self, - request_builder: RequestBuilder, - ) -> Result { - let response = request_builder.send().await?; - let response = check_status(response, &[StatusCode::OK]).await?; - - let issuer_chain = self.get_required_header( - &response, - "SGX-PCK-Certificate-Issuer-Chain", - Some("SGX-PCK-Certificate-Issuer-Chain"), - )?; - let fmspc = self.get_required_header(&response, "SGX-FMSPC", Some("SGX-FMSPC"))?; - let pck_certs_json = response.text().await?; - - Ok(PckCertificatesResponse { - pck_certs_json, - issuer_chain, - fmspc, - }) - } - - /// Helper to execute a request expected to return JSON plus an Issuer-Chain header. - async fn fetch_json_with_issuer_chain( - &self, - request_builder: RequestBuilder, - v4_issuer_chain_header: &'static str, - v3_issuer_chain_header: Option<&'static str>, - ) -> Result<(String, String), IntelApiError> { - let response = request_builder.send().await?; - let response = check_status(response, &[StatusCode::OK]).await?; - - let issuer_chain = - self.get_required_header(&response, v4_issuer_chain_header, v3_issuer_chain_header)?; - let json_body = response.text().await?; - - Ok((json_body, issuer_chain)) - } - - /// Checks for HTTP 404 or 410 status when querying TCB Evaluation Data Number based resources. - async fn check_tcb_evaluation_status( - &self, - request_builder: &RequestBuilder, - tcb_evaluation_data_number_val: u64, - resource_description: &str, - ) -> Result<(), IntelApiError> { - let builder_clone = request_builder.try_clone().ok_or_else(|| { - IntelApiError::Io(std::io::Error::new( - std::io::ErrorKind::Other, - "Failed to clone request builder for status check", - )) - })?; - - let response = builder_clone.send().await?; - let status = response.status(); - - if status == StatusCode::NOT_FOUND || status == StatusCode::GONE { - let (request_id, _, _) = extract_api_error_details(&response); - return Err(IntelApiError::ApiError { - status, - request_id, - error_code: None, - error_message: Some(format!( - "{} for TCB Evaluation Data Number {} {}", - resource_description, - tcb_evaluation_data_number_val, - if status == StatusCode::NOT_FOUND { - "not found" - } else { - "is no longer available" - } - )), - }); - } - Ok(()) - } - - /// Ensures the client is configured for API v4, otherwise returns an error. - fn ensure_v4_api(&self, function_name: &str) -> Result<(), IntelApiError> { - if self.api_version != ApiVersion::V4 { - Err(IntelApiError::UnsupportedApiVersion(format!( - "{} requires API v4", - function_name - ))) - } else { - Ok(()) - } - } - - /// Checks if a V4-only parameter is provided with a V3 API version. - fn check_v4_only_param( - &self, - param_value: Option, - param_name: &str, - ) -> Result<(), IntelApiError> { - if self.api_version == ApiVersion::V3 && param_value.is_some() { - Err(IntelApiError::UnsupportedApiVersion(format!( - "'{}' parameter requires API v4", - param_name - ))) - } else { - Ok(()) - } - } - - /// Checks for conflicting `update` and `tcb_evaluation_data_number` parameters when using V4. - fn check_conflicting_update_params( - &self, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result<(), IntelApiError> { - if self.api_version == ApiVersion::V4 - && update.is_some() - && tcb_evaluation_data_number.is_some() - { - Err(IntelApiError::ConflictingParameters( - "'update' and 'tcbEvaluationDataNumber'", - )) - } else { - Ok(()) - } - } - - /// Retrieves generic SGX enclave identity (QE, QVE, QAE) data. - /// - /// # Arguments - /// - /// * `identity_path_segment` - String slice representing the identity path segment (e.g., "qe", "qve", "qae"). - /// * `update` - Optional [`UpdateType`] for API v4. - /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number for API v4. - /// - /// # Returns - /// - /// An [`EnclaveIdentityResponse`] containing the JSON identity data and issuer chain. - /// - /// # Errors - /// - /// Returns an `IntelApiError` if the request fails or the specified resource - /// is unavailable. - async fn get_sgx_enclave_identity( - &self, - identity_path_segment: &str, - update: Option, - tcb_evaluation_data_number: Option, - ) -> Result { - self.check_v4_only_param(update, "update")?; - self.check_v4_only_param(tcb_evaluation_data_number, "tcbEvaluationDataNumber")?; - self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; - - let path = self.build_api_path("sgx", identity_path_segment, "identity")?; - let mut url = self.base_url.join(&path)?; - - if self.api_version == ApiVersion::V4 { - if let Some(upd) = update { - url.query_pairs_mut() - .append_pair("update", &upd.to_string()); - } - if let Some(tedn) = tcb_evaluation_data_number { - url.query_pairs_mut() - .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); - } - } - - let request_builder = self.client.get(url); - - if self.api_version == ApiVersion::V4 { - if let Some(tedn_val) = tcb_evaluation_data_number { - let description = format!("SGX {} Identity", identity_path_segment.to_uppercase()); - self.check_tcb_evaluation_status(&request_builder, tedn_val, &description) - .await?; - } - } - - let (enclave_identity_json, issuer_chain) = self - .fetch_json_with_issuer_chain( - request_builder, - "SGX-Enclave-Identity-Issuer-Chain", - Some("SGX-Enclave-Identity-Issuer-Chain"), - ) - .await?; - - Ok(EnclaveIdentityResponse { - enclave_identity_json, - issuer_chain, - }) - } -} diff --git a/crates/intel-dcap-api/src/client/enclave_identity.rs b/crates/intel-dcap-api/src/client/enclave_identity.rs new file mode 100644 index 0000000..eeee997 --- /dev/null +++ b/crates/intel-dcap-api/src/client/enclave_identity.rs @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::IntelApiError, + responses::EnclaveIdentityResponse, + types::{ApiVersion, UpdateType}, +}; + +impl ApiClient { + // --- Enclave Identity --- + + /// Retrieves the SGX QE Identity from the Intel API. + /// + /// Returns Enclave Identity JSON string (Appendix B) and Issuer Chain header. + /// Supports both v3 and v4. The `update` and `tcb_evaluation_data_number` + /// parameters are only valid in API v4. Returns the enclave identity JSON + /// and an issuer chain header. + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the JSON identity and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails, if conflicting v4 parameters are used, + /// or if the desired identity resource is not found. + pub async fn get_sgx_qe_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + self.get_sgx_enclave_identity("qe", update, tcb_evaluation_data_number) + .await + } + + /// Retrieves the TDX QE Identity from the Intel API (API v4 only). + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the JSON identity and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used, + /// if conflicting parameters are provided, or if the identity resource is not found. + /// GET /tdx/certification/v4/qe/identity - V4 ONLY + pub async fn get_tdx_qe_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // Ensure V4 API + self.ensure_v4_api("get_tdx_qe_identity")?; + // Check conflicting parameters (only relevant for V4, checked inside helper) + self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; + + let path = self.build_api_path("tdx", "qe", "identity")?; + let mut url = self.base_url.join(&path)?; + + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + + let request_builder = self.client.get(url); + + // Special handling for 404/410 when tcbEvaluationDataNumber is specified + if let Some(tedn_val) = tcb_evaluation_data_number { + // Use the helper function to check status before proceeding + self.check_tcb_evaluation_status(&request_builder, tedn_val, "TDX QE Identity") + .await?; + // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain + } + + // Fetch JSON and header (TDX only exists in V4) + let (enclave_identity_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "SGX-Enclave-Identity-Issuer-Chain", + None, + ) + .await?; + + Ok(EnclaveIdentityResponse { + enclave_identity_json, + issuer_chain, + }) + } + + /// Retrieves the SGX QVE Identity from the Intel API. + /// + /// Supports API v3 and v4. The `update` and `tcb_evaluation_data_number` parameters + /// are v4 only. Returns the QVE identity JSON and issuer chain. + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the QVE identity JSON and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails, if conflicting parameters are used, + /// or if the identity resource is not found. + /// GET /sgx/certification/{v3,v4}/qve/identity + pub async fn get_sgx_qve_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + self.get_sgx_enclave_identity("qve", update, tcb_evaluation_data_number) + .await + } + + /// Retrieves the SGX QAE Identity from the Intel API (API v4 only). + /// + /// # Arguments + /// + /// * `update` - Optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the QAE identity JSON and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used, + /// if conflicting parameters are provided, or if the QAE identity is not found. + /// GET /sgx/certification/v4/qae/identity - V4 ONLY + pub async fn get_sgx_qae_identity( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // QAE endpoint requires V4 + if self.api_version != ApiVersion::V4 { + return Err(IntelApiError::UnsupportedApiVersion( + "QAE Identity endpoint requires API v4".to_string(), + )); + } + // Call the generic helper, it will handle V4 params and 404/410 checks + self.get_sgx_enclave_identity("qae", update, tcb_evaluation_data_number) + .await + } + + /// Retrieves generic SGX enclave identity (QE, QVE, QAE) data. + /// + /// # Arguments + /// + /// * `identity_path_segment` - String slice representing the identity path segment (e.g., "qe", "qve", "qae"). + /// * `update` - Optional [`UpdateType`] for API v4. + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number for API v4. + /// + /// # Returns + /// + /// An [`EnclaveIdentityResponse`] containing the JSON identity data and issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or the specified resource + /// is unavailable. + async fn get_sgx_enclave_identity( + &self, + identity_path_segment: &str, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + self.check_v4_only_param(update, "update")?; + self.check_v4_only_param(tcb_evaluation_data_number, "tcbEvaluationDataNumber")?; + self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; + + let path = self.build_api_path("sgx", identity_path_segment, "identity")?; + let mut url = self.base_url.join(&path)?; + + if self.api_version == ApiVersion::V4 { + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + } + + let request_builder = self.client.get(url); + + if self.api_version == ApiVersion::V4 { + if let Some(tedn_val) = tcb_evaluation_data_number { + let description = format!("SGX {} Identity", identity_path_segment.to_uppercase()); + self.check_tcb_evaluation_status(&request_builder, tedn_val, &description) + .await?; + } + } + + let (enclave_identity_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "SGX-Enclave-Identity-Issuer-Chain", + Some("SGX-Enclave-Identity-Issuer-Chain"), + ) + .await?; + + Ok(EnclaveIdentityResponse { + enclave_identity_json, + issuer_chain, + }) + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/fmspc.rs b/crates/intel-dcap-api/src/client/fmspc.rs new file mode 100644 index 0000000..005ef7f --- /dev/null +++ b/crates/intel-dcap-api/src/client/fmspc.rs @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::{check_status, IntelApiError}, + responses::TcbEvaluationDataNumbersResponse, + types::{ApiVersion, PlatformFilter}, + FmspcJsonResponse, +}; +use reqwest::StatusCode; + +impl ApiClient { + // --- FMSPCs & TCB Evaluation Data Numbers --- + + /// GET /sgx/certification/{v3,v4}/fmspcs + /// Retrieves a list of FMSPC values for SGX and TDX platforms (API v4 only). + /// + /// # Arguments + /// + /// * `platform_filter` - An optional filter specifying SGX or TDX platforms. + /// + /// # Returns + /// + /// Optional 'platform' filter. + /// A `String` containing the JSON array of objects, each containing `fmspc` and `platform`. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. + pub async fn get_fmspcs( + &self, + platform_filter: Option, + ) -> Result { + if self.api_version == ApiVersion::V3 { + return Err(IntelApiError::UnsupportedApiVersion( + "API v4 only function".to_string(), + )); + } + let path = self.build_api_path("sgx", "", "fmspcs")?; + let mut url = self.base_url.join(&path)?; + + if let Some(pf) = platform_filter { + url.query_pairs_mut() + .append_pair("platform", &pf.to_string()); + } + + let request_builder = self.client.get(url); + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let fmspcs_json = response.text().await?; + + Ok(fmspcs_json) + } + + /// GET /sgx/certification/v4/tcbevaluationdatanumbers - V4 ONLY + /// Retrieves the currently supported SGX TCB Evaluation Data Numbers (API v4 only). + /// + /// # Returns + /// + /// A [`TcbEvaluationDataNumbersResponse`] containing the JSON structure of TCB Evaluation + /// Data Numbers and an issuer chain header. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. + pub async fn get_sgx_tcb_evaluation_data_numbers( + &self, + ) -> Result { + // Endpoint requires V4 + if self.api_version != ApiVersion::V4 { + return Err(IntelApiError::UnsupportedApiVersion( + "SGX TCB Evaluation Data Numbers endpoint requires API v4".to_string(), + )); + } + + let path = self.build_api_path("sgx", "", "tcbevaluationdatanumbers")?; + let url = self.base_url.join(&path)?; + let request_builder = self.client.get(url); + + let (tcb_evaluation_data_numbers_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "TCB-Evaluation-Data-Numbers-Issuer-Chain", + None, + ) + .await?; + + Ok(TcbEvaluationDataNumbersResponse { + tcb_evaluation_data_numbers_json, + issuer_chain, + }) + } + + /// GET /tdx/certification/v4/tcbevaluationdatanumbers - V4 ONLY + /// Retrieves the currently supported TDX TCB Evaluation Data Numbers (API v4 only). + /// + /// # Returns + /// + /// A [`TcbEvaluationDataNumbersResponse`] containing the JSON structure of TCB Evaluation + /// Data Numbers and an issuer chain header. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used or if the request fails. + pub async fn get_tdx_tcb_evaluation_data_numbers( + &self, + ) -> Result { + // Endpoint requires V4 + if self.api_version != ApiVersion::V4 { + return Err(IntelApiError::UnsupportedApiVersion( + "TDX TCB Evaluation Data Numbers endpoint requires API v4".to_string(), + )); + } + + let path = self.build_api_path("tdx", "", "tcbevaluationdatanumbers")?; + let url = self.base_url.join(&path)?; + let request_builder = self.client.get(url); + + let (tcb_evaluation_data_numbers_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "TCB-Evaluation-Data-Numbers-Issuer-Chain", + None, + ) + .await?; + + Ok(TcbEvaluationDataNumbersResponse { + tcb_evaluation_data_numbers_json, + issuer_chain, + }) + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs new file mode 100644 index 0000000..032a006 --- /dev/null +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::{check_status, extract_api_error_details, IntelApiError}, + responses::{PckCertificateResponse, PckCertificatesResponse}, + types::{ApiVersion, UpdateType}, +}; +use percent_encoding::percent_decode_str; +use reqwest::{RequestBuilder, Response, StatusCode}; +use std::io; + +impl ApiClient { + // ------------------------ + // Internal helper methods + // ------------------------ + + /// Helper to construct API paths dynamically based on version and technology (SGX/TDX). + pub(super) fn build_api_path( + &self, + technology: &str, + service: &str, + endpoint: &str, + ) -> Result { + let api_segment = self.api_version.path_segment(); + + if technology == "tdx" && self.api_version == ApiVersion::V3 { + return Err(IntelApiError::UnsupportedApiVersion(format!( + "TDX endpoint /{}/{}/{} requires API v4", + service, endpoint, technology + ))); + } + if technology == "sgx" && service == "registration" { + // Registration paths are fixed at v1 regardless of client's api_version + return Ok(format!("/sgx/registration/v1/{}", endpoint).replace("//", "/")); + } + + Ok(format!( + "/{}/certification/{}/{}/{}", + technology, api_segment, service, endpoint + ) + .replace("//", "/")) + } + + /// Helper to add an optional header if the string is non-empty. + pub(super) fn maybe_add_header( + builder: RequestBuilder, + header_name: &'static str, + header_value: Option<&str>, + ) -> RequestBuilder { + match header_value { + Some(value) if !value.is_empty() => builder.header(header_name, value), + _ => builder, + } + } + + /// Helper to extract a required header string value, handling potential v3/v4 differences. + pub(super) fn get_required_header( + &self, + response: &Response, + v4_header_name: &'static str, + v3_header_name: Option<&'static str>, + ) -> Result { + let header_name = match self.api_version { + ApiVersion::V4 => v4_header_name, + ApiVersion::V3 => v3_header_name.unwrap_or(v4_header_name), + }; + let value = response + .headers() + .get(header_name) + .ok_or(IntelApiError::MissingOrInvalidHeader(header_name))? + .to_str() + .map_err(|e| IntelApiError::HeaderValueParse(header_name, e.to_string()))?; + + if value.contains('%') { + percent_decode_str(value) + .decode_utf8() + .map_err(|e| IntelApiError::HeaderValueParse(header_name, e.to_string())) + .map(|s| s.to_string()) + } else { + Ok(value.to_string()) + } + } + + /// Helper to execute a request that returns a single PCK certificate and associated headers. + pub(super) async fn fetch_pck_certificate( + &self, + request_builder: RequestBuilder, + ) -> Result { + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = self.get_required_header( + &response, + "SGX-PCK-Certificate-Issuer-Chain", + Some("SGX-PCK-Certificate-Issuer-Chain"), + )?; + let tcbm = self.get_required_header(&response, "SGX-TCBm", Some("SGX-TCBm"))?; + let fmspc = self.get_required_header(&response, "SGX-FMSPC", Some("SGX-FMSPC"))?; + let pck_cert_pem = response.text().await?; + + Ok(PckCertificateResponse { + pck_cert_pem, + issuer_chain, + tcbm, + fmspc, + }) + } + + /// Helper to execute a request that returns a PCK certificates JSON array and associated headers. + pub(super) async fn fetch_pck_certificates( + &self, + request_builder: RequestBuilder, + ) -> Result { + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = self.get_required_header( + &response, + "SGX-PCK-Certificate-Issuer-Chain", + Some("SGX-PCK-Certificate-Issuer-Chain"), + )?; + let fmspc = self.get_required_header(&response, "SGX-FMSPC", Some("SGX-FMSPC"))?; + let pck_certs_json = response.text().await?; + + Ok(PckCertificatesResponse { + pck_certs_json, + issuer_chain, + fmspc, + }) + } + + /// Helper to execute a request expected to return JSON plus an Issuer-Chain header. + pub(super) async fn fetch_json_with_issuer_chain( + &self, + request_builder: RequestBuilder, + v4_issuer_chain_header: &'static str, + v3_issuer_chain_header: Option<&'static str>, + ) -> Result<(String, String), IntelApiError> { + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = + self.get_required_header(&response, v4_issuer_chain_header, v3_issuer_chain_header)?; + let json_body = response.text().await?; + + Ok((json_body, issuer_chain)) + } + + /// Checks for HTTP 404 or 410 status when querying TCB Evaluation Data Number based resources. + pub(super) async fn check_tcb_evaluation_status( + &self, + request_builder: &RequestBuilder, + tcb_evaluation_data_number_val: u64, + resource_description: &str, + ) -> Result<(), IntelApiError> { + let builder_clone = request_builder.try_clone().ok_or_else(|| { + IntelApiError::Io(io::Error::new( + io::ErrorKind::Other, + "Failed to clone request builder for status check", + )) + })?; + + let response = builder_clone.send().await?; + let status = response.status(); + + if status == StatusCode::NOT_FOUND || status == StatusCode::GONE { + let (request_id, _, _) = extract_api_error_details(&response); + return Err(IntelApiError::ApiError { + status, + request_id, + error_code: None, + error_message: Some(format!( + "{} for TCB Evaluation Data Number {} {}", + resource_description, + tcb_evaluation_data_number_val, + if status == StatusCode::NOT_FOUND { + "not found" + } else { + "is no longer available" + } + )), + }); + } + Ok(()) + } + + /// Ensures the client is configured for API v4, otherwise returns an error. + pub(super) fn ensure_v4_api(&self, function_name: &str) -> Result<(), IntelApiError> { + if self.api_version != ApiVersion::V4 { + Err(IntelApiError::UnsupportedApiVersion(format!( + "{} requires API v4", + function_name + ))) + } else { + Ok(()) + } + } + + /// Checks if a V4-only parameter is provided with a V3 API version. + pub(super) fn check_v4_only_param( + &self, + param_value: Option, + param_name: &str, + ) -> Result<(), IntelApiError> { + if self.api_version == ApiVersion::V3 && param_value.is_some() { + Err(IntelApiError::UnsupportedApiVersion(format!( + "'{}' parameter requires API v4", + param_name + ))) + } else { + Ok(()) + } + } + + /// Checks for conflicting `update` and `tcb_evaluation_data_number` parameters when using V4. + pub(super) fn check_conflicting_update_params( + &self, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result<(), IntelApiError> { + if self.api_version == ApiVersion::V4 + && update.is_some() + && tcb_evaluation_data_number.is_some() + { + Err(IntelApiError::ConflictingParameters( + "'update' and 'tcbEvaluationDataNumber'", + )) + } else { + Ok(()) + } + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/mod.rs b/crates/intel-dcap-api/src/client/mod.rs new file mode 100644 index 0000000..a0f2b4b --- /dev/null +++ b/crates/intel-dcap-api/src/client/mod.rs @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +mod enclave_identity; +mod fmspc; +mod helpers; +mod pck_cert; +mod pck_crl; +mod registration; +mod tcb_info; + +use crate::{ + error::IntelApiError, + types::ApiVersion, // Import ApiVersion +}; +use reqwest::Client; +use url::Url; + +// Base URL for the Intel Trusted Services API +const BASE_URL: &str = "https://api.trustedservices.intel.com"; + +/// Client for interacting with Intel Trusted Services API. +/// +/// Provides methods to access both SGX and TDX certification services, +/// supporting API versions V3 and V4. This client offers functionality +/// to register platforms, retrieve PCK certificates and CRLs, fetch TCB +/// information, enclave identities, as well as TCB evaluation data numbers. +/// +/// # Examples +/// +/// ```rust,no_run +/// use intel_dcap_api::ApiClient; +/// +/// #[tokio::main] +/// async fn main() -> Result<(), Box> { +/// // Create a client with default settings (V4 API) +/// let client = ApiClient::new()?; +/// +/// // Retrieve TCB info for a specific FMSPC +/// let tcb_info = client.get_sgx_tcb_info("00606A000000", None, None).await?; +/// println!("TCB Info: {}", tcb_info.tcb_info_json); +/// +/// Ok(()) +/// } +/// ``` +#[derive(Clone)] +pub struct ApiClient { + client: Client, + base_url: Url, + api_version: ApiVersion, +} + +impl ApiClient { + /// Creates a new client targeting the latest supported API version (V4). + /// + /// # Returns + /// + /// A result containing the newly created `ApiClient` or an `IntelApiError` if there + /// was an issue building the underlying HTTP client. + /// + /// # Errors + /// + /// This function may fail if the provided TLS version or base URL + /// cannot be used to build a `reqwest` client. + pub fn new() -> Result { + Self::new_with_options(BASE_URL, ApiVersion::V4) // Default to V4 + } + + /// Creates a new client targeting a specific API version. + /// + /// # Arguments + /// + /// * `api_version` - The desired API version to use (V3 or V4). + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the `reqwest` client cannot be built + /// with the specified options. + pub fn new_with_version(api_version: ApiVersion) -> Result { + Self::new_with_options(BASE_URL, api_version) + } + + /// Creates a new client with a custom base URL, targeting the latest supported API version (V4). + /// + /// # Arguments + /// + /// * `base_url` - The custom base URL for the Intel Trusted Services API. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the `reqwest` client cannot be built + /// or if the provided base URL is invalid. + pub fn new_with_base_url(base_url: impl reqwest::IntoUrl) -> Result { + Self::new_with_options(base_url, ApiVersion::V4) // Default to V4 + } + + /// Creates a new client with a custom base URL and specific API version. + /// + /// # Arguments + /// + /// * `base_url` - The custom base URL for the Intel Trusted Services API. + /// * `api_version` - The desired API version (V3 or V4). + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the `reqwest` client cannot be built + /// or if the provided base URL is invalid. + pub fn new_with_options( + base_url: impl reqwest::IntoUrl, + api_version: ApiVersion, + ) -> Result { + Ok(ApiClient { + client: Client::builder() + .min_tls_version(reqwest::tls::Version::TLS_1_2) + .build()?, + base_url: base_url.into_url()?, + api_version, // Store the version + }) + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/pck_cert.rs b/crates/intel-dcap-api/src/client/pck_cert.rs new file mode 100644 index 0000000..815aaf2 --- /dev/null +++ b/crates/intel-dcap-api/src/client/pck_cert.rs @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::IntelApiError, + requests::{PckCertRequest, PckCertsConfigRequest, PckCertsRequest}, + responses::{PckCertificateResponse, PckCertificatesResponse}, + types::ApiVersion, +}; +use reqwest::header; + +impl ApiClient { + // === Provisioning Certification Service === + + /// GET /sgx/certification/{v3,v4}/pckcert + /// Retrieves a single SGX PCK certificate using encrypted PPID and SVNs. + /// + /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter + /// is only valid for API v4 and allows specifying the PPID encryption key type (e.g. "RSA-3072"). + /// + /// # Arguments + /// + /// * `encrypted_ppid` - Hex-encoded encrypted PPID. + /// * `cpusvn` - Hex-encoded CPUSVN value. + /// * `pcesvn` - Hex-encoded PCESVN value. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). + /// + /// # Returns + /// + /// A [`PckCertificateResponse`] containing the PEM-encoded certificate, issuer chain, + /// TCBm, and FMSPC. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API call fails or the response contains an invalid status. + /// Returns PEM Cert, Issuer Chain, TCBm, FMSPC. + pub async fn get_pck_certificate_by_ppid( + &self, + encrypted_ppid: &str, + cpusvn: &str, + pcesvn: &str, + pceid: &str, + subscription_key: Option<&str>, + ppid_encryption_key_type: Option<&str>, + ) -> Result { + // Check V4-only parameter + self.check_v4_only_param(ppid_encryption_key_type, "PPID-Encryption-Key")?; + + let path = self.build_api_path("sgx", "", "pckcert")?; // service is empty + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("encrypted_ppid", encrypted_ppid) + .append_pair("cpusvn", cpusvn) + .append_pair("pcesvn", pcesvn) + .append_pair("pceid", pceid); + + let mut request_builder = self.client.get(url); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + // Only add for V4 + if self.api_version == ApiVersion::V4 { + request_builder = Self::maybe_add_header( + request_builder, + "PPID-Encryption-Key", + ppid_encryption_key_type, + ); + } + + self.fetch_pck_certificate(request_builder).await + } + + /// POST /sgx/certification/{v3,v4}/pckcert + /// Retrieves a single SGX PCK certificate using a platform manifest and SVNs. + /// + /// Optionally requires a subscription key. + /// + /// # Arguments + /// + /// * `platform_manifest` - Hex-encoded platform manifest. + /// * `cpusvn` - Hex-encoded CPUSVN value. + /// * `pcesvn` - Hex-encoded PCESVN value. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// + /// # Returns + /// + /// A [`PckCertificateResponse`] containing the PEM-encoded certificate, issuer chain, + /// TCBm, and FMSPC. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response is invalid. + /// Returns PEM Cert, Issuer Chain, TCBm, FMSPC. + pub async fn get_pck_certificate_by_manifest( + &self, + platform_manifest: &str, + cpusvn: &str, + pcesvn: &str, + pceid: &str, + subscription_key: Option<&str>, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcert")?; + let url = self.base_url.join(&path)?; + let request_body = PckCertRequest { + platform_manifest, + cpusvn, + pcesvn, + pceid, + }; + + let mut request_builder = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .json(&request_body); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + self.fetch_pck_certificate(request_builder).await + } + + /// GET /sgx/certification/{v3,v4}/pckcerts + /// Retrieves all SGX PCK certificates for a platform using encrypted PPID. + /// + /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter + /// is only valid for API v4. + /// + /// # Arguments + /// + /// * `encrypted_ppid` - Hex-encoded encrypted PPID. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] containing JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API call fails or the response status is invalid. + pub async fn get_pck_certificates_by_ppid( + &self, + encrypted_ppid: &str, + pceid: &str, + subscription_key: Option<&str>, + ppid_encryption_key_type: Option<&str>, + ) -> Result { + // Check V4-only parameter + self.check_v4_only_param(ppid_encryption_key_type, "PPID-Encryption-Key")?; + + let path = self.build_api_path("sgx", "", "pckcerts")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("encrypted_ppid", encrypted_ppid) + .append_pair("pceid", pceid); + + let mut request_builder = self.client.get(url); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + // Only add for V4 + if self.api_version == ApiVersion::V4 { + request_builder = Self::maybe_add_header( + request_builder, + "PPID-Encryption-Key", + ppid_encryption_key_type, + ); + } + + self.fetch_pck_certificates(request_builder).await + } + + /// POST /sgx/certification/{v3,v4}/pckcerts + /// Retrieves all SGX PCK certificates for a platform using a platform manifest. + /// + /// Optionally requires a subscription key. + /// + /// # Arguments + /// + /// * `platform_manifest` - Hex-encoded platform manifest. + /// * `pceid` - Hex-encoded PCEID value. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] containing JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API call fails or the response status is invalid. + pub async fn get_pck_certificates_by_manifest( + &self, + platform_manifest: &str, + pceid: &str, + subscription_key: Option<&str>, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcerts")?; + let url = self.base_url.join(&path)?; + let request_body = PckCertsRequest { + platform_manifest, + pceid, + }; + + let mut request_builder = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .json(&request_body); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + self.fetch_pck_certificates(request_builder).await + } + + /// GET /sgx/certification/{v3,v4}/pckcerts/config (using PPID) + /// Retrieves SGX PCK certificates for a specific configuration (CPUSVN) using encrypted PPID. + /// + /// Optionally requires a subscription key. The `ppid_encryption_key_type` parameter + /// is only valid for API v4. Returns JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Arguments + /// + /// * `encrypted_ppid` - Hex-encoded encrypted PPID. + /// * `pceid` - Hex-encoded PCEID value. + /// * `cpusvn` - Hex-encoded CPUSVN value for the requested configuration. + /// * `subscription_key` - Optional subscription key if the Intel API requires it. + /// * `ppid_encryption_key_type` - Optional PPID encryption key type (V4 only). + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] with the requested config's certificate data. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not `200 OK`. + pub async fn get_pck_certificates_config_by_ppid( + &self, + encrypted_ppid: &str, + pceid: &str, + cpusvn: &str, + subscription_key: Option<&str>, + ppid_encryption_key_type: Option<&str>, + ) -> Result { + // V3 does not support PPID-Encryption-Key header/type + if self.api_version == ApiVersion::V3 && ppid_encryption_key_type.is_some() { + return Err(IntelApiError::UnsupportedApiVersion( + "PPID-Encryption-Key header is only supported in API v4".to_string(), + )); + } + + let path = self.build_api_path("sgx", "", "pckcerts/config")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("encrypted_ppid", encrypted_ppid) + .append_pair("pceid", pceid) + .append_pair("cpusvn", cpusvn); + + let mut request_builder = self.client.get(url); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + // Only add for V4 + if self.api_version == ApiVersion::V4 { + request_builder = Self::maybe_add_header( + request_builder, + "PPID-Encryption-Key", + ppid_encryption_key_type, + ); + } + + self.fetch_pck_certificates(request_builder).await + } + + /// POST /sgx/certification/{v3,v4}/pckcerts/config (using Manifest) + /// Retrieves SGX PCK certificates for a specific configuration (CPUSVN) using a platform manifest. + /// + /// Optionally requires a subscription key. Returns JSON with `{tcb, tcbm, cert}` entries, + /// as well as the issuer chain and FMSPC headers. + /// + /// # Arguments + /// + /// * `platform_manifest` - Hex-encoded platform manifest. + /// * `pceid` - Hex-encoded PCEID value. + /// * `cpusvn` - Hex-encoded CPUSVN value for the requested configuration. + /// * `subscription_key` - Optional subscription key if needed by the Intel API. + /// + /// # Returns + /// + /// A [`PckCertificatesResponse`] with the requested config's certificate data. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not `200 OK`. + pub async fn get_pck_certificates_config_by_manifest( + &self, + platform_manifest: &str, + pceid: &str, + cpusvn: &str, + subscription_key: Option<&str>, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcerts/config")?; + let url = self.base_url.join(&path)?; + let request_body = PckCertsConfigRequest { + platform_manifest, + pceid, + cpusvn, + }; + + let mut request_builder = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/json") + .json(&request_body); + + request_builder = Self::maybe_add_header( + request_builder, + "Ocp-Apim-Subscription-Key", + subscription_key, + ); + + self.fetch_pck_certificates(request_builder).await + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/pck_crl.rs b/crates/intel-dcap-api/src/client/pck_crl.rs new file mode 100644 index 0000000..7fa6369 --- /dev/null +++ b/crates/intel-dcap-api/src/client/pck_crl.rs @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::{check_status, IntelApiError}, + responses::PckCrlResponse, + types::{CaType, CrlEncoding}, +}; +use reqwest::StatusCode; + +impl ApiClient { + /// GET /sgx/certification/{v3,v4}/pckcrl + /// Retrieves the PCK Certificate Revocation List (CRL) for a specified CA type. + /// + /// Optionally takes an `encoding` parameter indicating whether the CRL should be + /// returned as PEM or DER. Defaults to PEM if not specified. + /// + /// # Arguments + /// + /// * `ca_type` - The type of CA to retrieve the CRL for (e.g., "processor" or "platform"). + /// * `encoding` - An optional [`CrlEncoding`] (PEM or DER). + /// + /// # Returns + /// + /// A [`PckCrlResponse`] containing the CRL data and the issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not `200 OK`. + /// Optional 'encoding' parameter ("pem" or "der"). + /// Returns CRL data (PEM or DER) and Issuer Chain header. + pub async fn get_pck_crl( + &self, + ca_type: CaType, + encoding: Option, + ) -> Result { + let path = self.build_api_path("sgx", "", "pckcrl")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut() + .append_pair("ca", &ca_type.to_string()); + + if let Some(enc) = encoding { + url.query_pairs_mut() + .append_pair("encoding", &enc.to_string()); + } + + let request_builder = self.client.get(url); + let response = request_builder.send().await?; + let response = check_status(response, &[StatusCode::OK]).await?; + + let issuer_chain = self.get_required_header( + &response, + "SGX-PCK-CRL-Issuer-Chain", // v4 name + Some("SGX-PCK-CRL-Issuer-Chain"), // v3 name + )?; + + // Response body is PEM or DER CRL + let crl_data = response.bytes().await?.to_vec(); + + Ok(PckCrlResponse { + crl_data, + issuer_chain, + }) + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/registration.rs b/crates/intel-dcap-api/src/client/registration.rs new file mode 100644 index 0000000..bdecc56 --- /dev/null +++ b/crates/intel-dcap-api/src/client/registration.rs @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::{check_status, IntelApiError}, + responses::AddPackageResponse, +}; +use reqwest::{header, StatusCode}; +use std::num::ParseIntError; + +impl ApiClient { + /// POST /sgx/registration/v1/platform + /// Registers a multi-package SGX platform with the Intel Trusted Services API. + /// + /// # Arguments + /// + /// * `platform_manifest` - Binary data representing the platform manifest. + /// + /// # Returns + /// + /// Request body is binary Platform Manifest + /// Returns the hex-encoded PPID as a `String` upon success. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails or if the response status + /// is not HTTP `201 CREATED`. + pub async fn register_platform( + &self, + platform_manifest: Vec, + ) -> Result { + // Registration paths are fixed, use the helper with "registration" service + let path = self.build_api_path("sgx", "registration", "platform")?; + let url = self.base_url.join(&path)?; + + let response = self + .client + .post(url) + .header(header::CONTENT_TYPE, "application/octet-stream") + .body(platform_manifest) + .send() + .await?; + + let response = check_status(response, &[StatusCode::CREATED]).await?; + + // Response body is hex-encoded PPID + let ppid_hex = response.text().await?; + Ok(ppid_hex) + } + + /// POST /sgx/registration/v1/package + /// Adds new package(s) to an already registered SGX platform instance. + /// + /// # Arguments + /// + /// * `add_package_request` - Binary data for the "Add Package" request body. + /// * `subscription_key` - The subscription key required by the Intel API. + /// + /// # Returns + /// + /// A [`AddPackageResponse`] containing the Platform Membership Certificates and + /// the count of them extracted from the response header. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the request fails, if the subscription key is invalid, + /// or if the response status is not HTTP `200 OK`. + pub async fn add_package( + &self, + add_package_request: Vec, + subscription_key: &str, + ) -> Result { + if subscription_key.is_empty() { + return Err(IntelApiError::InvalidSubscriptionKey); + } + + // Registration paths are fixed + let path = self.build_api_path("sgx", "registration", "package")?; + let url = self.base_url.join(&path)?; + + let response = self + .client + .post(url) + .header("Ocp-Apim-Subscription-Key", subscription_key) + .header(header::CONTENT_TYPE, "application/octet-stream") + .body(add_package_request) + .send() + .await?; + + let response = check_status(response, &[StatusCode::OK]).await?; + + // Use the generic header helper, assuming header name is stable across reg versions + let cert_count_str = self.get_required_header(&response, "Certificate-Count", None)?; + let pck_cert_count: usize = cert_count_str.parse().map_err(|e: ParseIntError| { + IntelApiError::HeaderValueParse("Certificate-Count", e.to_string()) + })?; + + // Response body is a binary array of certificates + let pck_certs = response.bytes().await?.to_vec(); + Ok(AddPackageResponse { + pck_certs, + pck_cert_count, + }) + } +} \ No newline at end of file diff --git a/crates/intel-dcap-api/src/client/tcb_info.rs b/crates/intel-dcap-api/src/client/tcb_info.rs new file mode 100644 index 0000000..98c4c65 --- /dev/null +++ b/crates/intel-dcap-api/src/client/tcb_info.rs @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use super::ApiClient; // Import from parent module +use crate::{ + error::IntelApiError, + responses::TcbInfoResponse, + types::{ApiVersion, UpdateType}, +}; + +impl ApiClient { + // --- TCB Info --- + + /// GET /sgx/certification/{v3,v4}/tcb + /// Retrieves SGX TCB information for a given FMSPC. + /// + /// Returns TCB Info JSON string (Appendix A) and Issuer Chain header. + /// This function supports both API v3 and v4. The `update` and `tcbEvaluationDataNumber` + /// parameters are only supported by API v4. If both are provided at the same time (for v4), + /// a conflict error is returned. + /// + /// # Arguments + /// + /// * `fmspc` - Hex-encoded FMSPC value. + /// * `update` - Optional [`UpdateType`] for API v4. + /// * `tcb_evaluation_data_number` - Optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// A [`TcbInfoResponse`] containing the TCB info JSON and the issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if the API request fails, if conflicting parameters are used, + /// or if the requested TCB data is not found. + pub async fn get_sgx_tcb_info( + &self, + fmspc: &str, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // V3 does not support 'update' or 'tcbEvaluationDataNumber' + if self.api_version == ApiVersion::V3 && update.is_some() { + return Err(IntelApiError::UnsupportedApiVersion( + "'update' parameter requires API v4".to_string(), + )); + } + if self.api_version == ApiVersion::V3 && tcb_evaluation_data_number.is_some() { + return Err(IntelApiError::UnsupportedApiVersion( + "'tcbEvaluationDataNumber' parameter requires API v4".to_string(), + )); + } + if self.api_version == ApiVersion::V4 + && update.is_some() + && tcb_evaluation_data_number.is_some() + { + return Err(IntelApiError::ConflictingParameters( + "'update' and 'tcbEvaluationDataNumber'", + )); + } + + let path = self.build_api_path("sgx", "", "tcb")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut().append_pair("fmspc", fmspc); + + // Add V4-specific parameters + if self.api_version == ApiVersion::V4 { + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + } + + let request_builder = self.client.get(url); + + // Special handling for 404/410 when tcbEvaluationDataNumber is specified (V4 only) + if self.api_version == ApiVersion::V4 { + if let Some(tedn_val) = tcb_evaluation_data_number { + // Use the helper function to check status before proceeding + self.check_tcb_evaluation_status(&request_builder, tedn_val, "SGX TCB Info") + .await?; + // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain + } + } + + // Fetch JSON and header (header name seems same for v3/v4) + let (tcb_info_json, issuer_chain) = self + .fetch_json_with_issuer_chain( + request_builder, + "TCB-Info-Issuer-Chain", // v4 name + Some("SGX-TCB-Info-Issuer-Chain"), // v3 name + ) + .await?; + + Ok(TcbInfoResponse { + tcb_info_json, + issuer_chain, + }) + } + + /// GET /tdx/certification/v4/tcb + /// Retrieves TDX TCB information for a given FMSPC (API v4 only). + /// + /// # Arguments + /// + /// * `fmspc` - Hex-encoded FMSPC value. + /// * `update` - An optional [`UpdateType`] (v4 only). + /// * `tcb_evaluation_data_number` - An optional TCB Evaluation Data Number (v4 only). + /// + /// # Returns + /// + /// A [`TcbInfoResponse`] containing TDX TCB info JSON and the issuer chain. + /// + /// # Errors + /// + /// Returns an `IntelApiError` if an unsupported API version is used, + /// if there are conflicting parameters, or if the TDX TCB data is not found. + /// Returns TCB Info JSON string (Appendix A) and Issuer Chain header. + pub async fn get_tdx_tcb_info( + &self, + fmspc: &str, + update: Option, + tcb_evaluation_data_number: Option, + ) -> Result { + // Ensure V4 API + self.ensure_v4_api("get_tdx_tcb_info")?; + // Check conflicting parameters (only relevant for V4, checked inside helper) + self.check_conflicting_update_params(update, tcb_evaluation_data_number)?; + + let path = self.build_api_path("tdx", "", "tcb")?; + let mut url = self.base_url.join(&path)?; + url.query_pairs_mut().append_pair("fmspc", fmspc); + + if let Some(upd) = update { + url.query_pairs_mut() + .append_pair("update", &upd.to_string()); + } + if let Some(tedn) = tcb_evaluation_data_number { + url.query_pairs_mut() + .append_pair("tcbEvaluationDataNumber", &tedn.to_string()); + } + + let request_builder = self.client.get(url); + + // Special handling for 404/410 when tcbEvaluationDataNumber is specified + if let Some(tedn_val) = tcb_evaluation_data_number { + // Use the helper function to check status before proceeding + self.check_tcb_evaluation_status(&request_builder, tedn_val, "TDX TCB Info") + .await?; + // If the check passes (doesn't return Err), continue to fetch_json_with_issuer_chain + } + + // Fetch JSON and header (TDX only exists in V4) + let (tcb_info_json, issuer_chain) = self + .fetch_json_with_issuer_chain(request_builder, "TCB-Info-Issuer-Chain", None) + .await?; + + Ok(TcbInfoResponse { + tcb_info_json, + issuer_chain, + }) + } +} \ No newline at end of file From 4501b3421ca09189ebb655f58c9bce6bc336ce31 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 11 Apr 2025 12:23:53 +0200 Subject: [PATCH 075/114] fixup! refactor(intel-dcap-api): split client.rs into smaller files Signed-off-by: Harald Hoyer --- crates/intel-dcap-api/src/client/enclave_identity.rs | 2 +- crates/intel-dcap-api/src/client/fmspc.rs | 2 +- crates/intel-dcap-api/src/client/helpers.rs | 2 +- crates/intel-dcap-api/src/client/mod.rs | 2 +- crates/intel-dcap-api/src/client/pck_cert.rs | 2 +- crates/intel-dcap-api/src/client/pck_crl.rs | 2 +- crates/intel-dcap-api/src/client/registration.rs | 2 +- crates/intel-dcap-api/src/client/tcb_info.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/intel-dcap-api/src/client/enclave_identity.rs b/crates/intel-dcap-api/src/client/enclave_identity.rs index eeee997..0d20b72 100644 --- a/crates/intel-dcap-api/src/client/enclave_identity.rs +++ b/crates/intel-dcap-api/src/client/enclave_identity.rs @@ -226,4 +226,4 @@ impl ApiClient { issuer_chain, }) } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/fmspc.rs b/crates/intel-dcap-api/src/client/fmspc.rs index 005ef7f..cb74422 100644 --- a/crates/intel-dcap-api/src/client/fmspc.rs +++ b/crates/intel-dcap-api/src/client/fmspc.rs @@ -131,4 +131,4 @@ impl ApiClient { issuer_chain, }) } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs index 032a006..967df76 100644 --- a/crates/intel-dcap-api/src/client/helpers.rs +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -231,4 +231,4 @@ impl ApiClient { Ok(()) } } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/mod.rs b/crates/intel-dcap-api/src/client/mod.rs index a0f2b4b..d26a55d 100644 --- a/crates/intel-dcap-api/src/client/mod.rs +++ b/crates/intel-dcap-api/src/client/mod.rs @@ -117,4 +117,4 @@ impl ApiClient { api_version, // Store the version }) } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/pck_cert.rs b/crates/intel-dcap-api/src/client/pck_cert.rs index 815aaf2..7580abd 100644 --- a/crates/intel-dcap-api/src/client/pck_cert.rs +++ b/crates/intel-dcap-api/src/client/pck_cert.rs @@ -350,4 +350,4 @@ impl ApiClient { self.fetch_pck_certificates(request_builder).await } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/pck_crl.rs b/crates/intel-dcap-api/src/client/pck_crl.rs index 7fa6369..49ead3f 100644 --- a/crates/intel-dcap-api/src/client/pck_crl.rs +++ b/crates/intel-dcap-api/src/client/pck_crl.rs @@ -64,4 +64,4 @@ impl ApiClient { issuer_chain, }) } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/registration.rs b/crates/intel-dcap-api/src/client/registration.rs index bdecc56..d4bd2cc 100644 --- a/crates/intel-dcap-api/src/client/registration.rs +++ b/crates/intel-dcap-api/src/client/registration.rs @@ -103,4 +103,4 @@ impl ApiClient { pck_cert_count, }) } -} \ No newline at end of file +} diff --git a/crates/intel-dcap-api/src/client/tcb_info.rs b/crates/intel-dcap-api/src/client/tcb_info.rs index 98c4c65..94dc94f 100644 --- a/crates/intel-dcap-api/src/client/tcb_info.rs +++ b/crates/intel-dcap-api/src/client/tcb_info.rs @@ -164,4 +164,4 @@ impl ApiClient { issuer_chain, }) } -} \ No newline at end of file +} From 1a392e800ac4e3ead8bf4d4bfd0865e4089a9c1a Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 11 Apr 2025 12:34:09 +0200 Subject: [PATCH 076/114] fixup! refactor(intel-dcap-api): split client.rs into smaller files Signed-off-by: Harald Hoyer --- .../intel-dcap-api/src/client/enclave_identity.rs | 4 ++-- crates/intel-dcap-api/src/client/fmspc.rs | 4 ++-- crates/intel-dcap-api/src/client/helpers.rs | 6 ++---- crates/intel-dcap-api/src/client/mod.rs | 13 ++++++------- crates/intel-dcap-api/src/client/pck_cert.rs | 4 ++-- crates/intel-dcap-api/src/client/pck_crl.rs | 6 ++++-- crates/intel-dcap-api/src/client/registration.rs | 2 ++ crates/intel-dcap-api/src/client/tcb_info.rs | 8 ++++---- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/crates/intel-dcap-api/src/client/enclave_identity.rs b/crates/intel-dcap-api/src/client/enclave_identity.rs index 0d20b72..64e760b 100644 --- a/crates/intel-dcap-api/src/client/enclave_identity.rs +++ b/crates/intel-dcap-api/src/client/enclave_identity.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! Enclave Identity + use super::ApiClient; // Import from parent module use crate::{ error::IntelApiError, @@ -9,8 +11,6 @@ use crate::{ }; impl ApiClient { - // --- Enclave Identity --- - /// Retrieves the SGX QE Identity from the Intel API. /// /// Returns Enclave Identity JSON string (Appendix B) and Issuer Chain header. diff --git a/crates/intel-dcap-api/src/client/fmspc.rs b/crates/intel-dcap-api/src/client/fmspc.rs index cb74422..3963f1f 100644 --- a/crates/intel-dcap-api/src/client/fmspc.rs +++ b/crates/intel-dcap-api/src/client/fmspc.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! FMSPCs & TCB Evaluation Data Numbers + use super::ApiClient; // Import from parent module use crate::{ error::{check_status, IntelApiError}, @@ -11,8 +13,6 @@ use crate::{ use reqwest::StatusCode; impl ApiClient { - // --- FMSPCs & TCB Evaluation Data Numbers --- - /// GET /sgx/certification/{v3,v4}/fmspcs /// Retrieves a list of FMSPC values for SGX and TDX platforms (API v4 only). /// diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs index 967df76..8ebc887 100644 --- a/crates/intel-dcap-api/src/client/helpers.rs +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! Internal helper methods + use super::ApiClient; // Import from parent module use crate::{ error::{check_status, extract_api_error_details, IntelApiError}, @@ -12,10 +14,6 @@ use reqwest::{RequestBuilder, Response, StatusCode}; use std::io; impl ApiClient { - // ------------------------ - // Internal helper methods - // ------------------------ - /// Helper to construct API paths dynamically based on version and technology (SGX/TDX). pub(super) fn build_api_path( &self, diff --git a/crates/intel-dcap-api/src/client/mod.rs b/crates/intel-dcap-api/src/client/mod.rs index d26a55d..d2d618d 100644 --- a/crates/intel-dcap-api/src/client/mod.rs +++ b/crates/intel-dcap-api/src/client/mod.rs @@ -9,10 +9,7 @@ mod pck_crl; mod registration; mod tcb_info; -use crate::{ - error::IntelApiError, - types::ApiVersion, // Import ApiVersion -}; +use crate::{error::IntelApiError, types::ApiVersion}; use reqwest::Client; use url::Url; @@ -63,7 +60,8 @@ impl ApiClient { /// This function may fail if the provided TLS version or base URL /// cannot be used to build a `reqwest` client. pub fn new() -> Result { - Self::new_with_options(BASE_URL, ApiVersion::V4) // Default to V4 + // Default to V4 + Self::new_with_options(BASE_URL, ApiVersion::V4) } /// Creates a new client targeting a specific API version. @@ -91,7 +89,8 @@ impl ApiClient { /// Returns an `IntelApiError` if the `reqwest` client cannot be built /// or if the provided base URL is invalid. pub fn new_with_base_url(base_url: impl reqwest::IntoUrl) -> Result { - Self::new_with_options(base_url, ApiVersion::V4) // Default to V4 + // Default to V4 + Self::new_with_options(base_url, ApiVersion::V4) } /// Creates a new client with a custom base URL and specific API version. @@ -114,7 +113,7 @@ impl ApiClient { .min_tls_version(reqwest::tls::Version::TLS_1_2) .build()?, base_url: base_url.into_url()?, - api_version, // Store the version + api_version, }) } } diff --git a/crates/intel-dcap-api/src/client/pck_cert.rs b/crates/intel-dcap-api/src/client/pck_cert.rs index 7580abd..fdc4842 100644 --- a/crates/intel-dcap-api/src/client/pck_cert.rs +++ b/crates/intel-dcap-api/src/client/pck_cert.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! Provisioning Certification Service + use super::ApiClient; // Import from parent module use crate::{ error::IntelApiError, @@ -11,8 +13,6 @@ use crate::{ use reqwest::header; impl ApiClient { - // === Provisioning Certification Service === - /// GET /sgx/certification/{v3,v4}/pckcert /// Retrieves a single SGX PCK certificate using encrypted PPID and SVNs. /// diff --git a/crates/intel-dcap-api/src/client/pck_crl.rs b/crates/intel-dcap-api/src/client/pck_crl.rs index 49ead3f..0226b11 100644 --- a/crates/intel-dcap-api/src/client/pck_crl.rs +++ b/crates/intel-dcap-api/src/client/pck_crl.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! PCK Certificate Revocation List + use super::ApiClient; // Import from parent module use crate::{ error::{check_status, IntelApiError}, @@ -52,8 +54,8 @@ impl ApiClient { let issuer_chain = self.get_required_header( &response, - "SGX-PCK-CRL-Issuer-Chain", // v4 name - Some("SGX-PCK-CRL-Issuer-Chain"), // v3 name + "SGX-PCK-CRL-Issuer-Chain", + Some("SGX-PCK-CRL-Issuer-Chain"), )?; // Response body is PEM or DER CRL diff --git a/crates/intel-dcap-api/src/client/registration.rs b/crates/intel-dcap-api/src/client/registration.rs index d4bd2cc..136c8c0 100644 --- a/crates/intel-dcap-api/src/client/registration.rs +++ b/crates/intel-dcap-api/src/client/registration.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! Registration + use super::ApiClient; // Import from parent module use crate::{ error::{check_status, IntelApiError}, diff --git a/crates/intel-dcap-api/src/client/tcb_info.rs b/crates/intel-dcap-api/src/client/tcb_info.rs index 94dc94f..9c001ca 100644 --- a/crates/intel-dcap-api/src/client/tcb_info.rs +++ b/crates/intel-dcap-api/src/client/tcb_info.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2025 Matter Labs +//! TCB Info + use super::ApiClient; // Import from parent module use crate::{ error::IntelApiError, @@ -9,8 +11,6 @@ use crate::{ }; impl ApiClient { - // --- TCB Info --- - /// GET /sgx/certification/{v3,v4}/tcb /// Retrieves SGX TCB information for a given FMSPC. /// @@ -91,8 +91,8 @@ impl ApiClient { let (tcb_info_json, issuer_chain) = self .fetch_json_with_issuer_chain( request_builder, - "TCB-Info-Issuer-Chain", // v4 name - Some("SGX-TCB-Info-Issuer-Chain"), // v3 name + "TCB-Info-Issuer-Chain", + Some("SGX-TCB-Info-Issuer-Chain"), ) .await?; From 7b1c386e14608d4cb9c6f50ac8c3fdcb2526b571 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 14 Apr 2025 17:07:35 +0200 Subject: [PATCH 077/114] refactor(shells): simplify environment variable declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactored the environment variable setup by consolidating into a single `env` map for better clarity. - Removed `TEE_LD_LIBRARY_PATH` and inlined its logic directly within `LD_LIBRARY_PATH`. - Improved structure and readability of configuration-specific variables like `QCNL_CONF_PATH`. Let us run directly on x86_64: ``` ❯ cargo run --bin verify-era-proof-attestation -- \ --rpc https://mainnet.era.zksync.io \ --continuous 493220 \ --attestation-policy-file bin/verify-era-proof-attestation/examples/attestation_policy.yaml \ --tee-types sgx \ --log-level info ``` --- shells/teepot/default.nix | 40 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index 7fed35a..ac783f4 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -42,31 +42,23 @@ mkShell { google-cloud-sdk ]; - TEE_LD_LIBRARY_PATH = lib.makeLibraryPath ( - lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [ - pkgs.curl - nixsgx.sgx-dcap - nixsgx.sgx-dcap.quote_verify - nixsgx.sgx-dcap.default_qpl - ] - ); - - QCNL_CONF_PATH = - if (stdenv.hostPlatform.system != "x86_64-linux") then - "" - else - "${nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf"; - OPENSSL_NO_VENDOR = "1"; - RUST_SRC_PATH = "${toolchain_with_src}/lib/rustlib/src/rust/library"; + env = { + QCNL_CONF_PATH = + if (stdenv.hostPlatform.system != "x86_64-linux") then + "" + else + "${nixsgx.sgx-dcap.default_qpl}/etc/sgx_default_qcnl.conf"; + OPENSSL_NO_VENDOR = "1"; + RUST_SRC_PATH = "${toolchain_with_src}/lib/rustlib/src/rust/"; + }; shellHook = '' - if [ "x$NIX_LD" = "x" ]; then - export NIX_LD=$(<${stdenv.cc}/nix-support/dynamic-linker) - fi - if [ "x$NIX_LD_LIBRARY_PATH" = "x" ]; then - export NIX_LD_LIBRARY_PATH="$TEE_LD_LIBRARY_PATH" - else - export NIX_LD_LIBRARY_PATH="$NIX_LD_LIBRARY_PATH:$TEE_LD_LIBRARY_PATH" - fi + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${ + pkgs.lib.makeLibraryPath (lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [ + pkgs.curl + nixsgx.sgx-dcap + nixsgx.sgx-dcap.quote_verify + nixsgx.sgx-dcap.default_qpl + ])}" ''; } From d03ed96bb847058bf1833c6f050387907abdcf41 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 14 Apr 2025 17:26:21 +0200 Subject: [PATCH 078/114] feat: add description to intel-dcap-api package - Added a description field to the Cargo.toml for the intel-dcap-api crate. --- crates/intel-dcap-api/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/intel-dcap-api/Cargo.toml b/crates/intel-dcap-api/Cargo.toml index df51592..d51993f 100644 --- a/crates/intel-dcap-api/Cargo.toml +++ b/crates/intel-dcap-api/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "intel-dcap-api" +description = "Intel DCAP API Client" version.workspace = true edition.workspace = true authors.workspace = true From 71a04ad4e24e1c7556e69b32441c9b6141951785 Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 15:40:54 +0100 Subject: [PATCH 079/114] refactor: bring items to top level of files --- bin/rtmr-calc/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs index 7a6cef5..a3ab72c 100644 --- a/bin/rtmr-calc/src/main.rs +++ b/bin/rtmr-calc/src/main.rs @@ -65,6 +65,8 @@ impl Display for Rtmr { } } +const CHUNK_SIZE: u64 = 1024 * 128; + fn main() -> Result<()> { let args = Arguments::parse(); tracing::subscriber::set_global_default(setup_logging( @@ -182,7 +184,6 @@ fn main() -> Result<()> { let mut hasher = Sha384::new(); - const CHUNK_SIZE: u64 = 1024 * 128; loop { if start >= end { break; From 2dea589c0e6e567b75696eb3ee05c2632c8c3db5 Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 15:48:56 +0100 Subject: [PATCH 080/114] refactor: prefer inline format args --- bin/sha384-extend/src/main.rs | 6 ++--- bin/tee-self-attestation-test/src/main.rs | 2 +- bin/verify-attestation/src/main.rs | 2 +- .../src/client/json_rpc.rs | 12 ++++----- .../src/core/config.rs | 7 ++---- .../src/core/types.rs | 9 +++---- bin/verify-era-proof-attestation/src/main.rs | 2 +- .../src/proof/parsing.rs | 2 +- .../src/verification/attestation.rs | 2 +- .../src/verification/policy.rs | 6 ++--- .../src/verification/signature.rs | 7 +++--- crates/intel-dcap-api/src/client/helpers.rs | 25 ++++++++----------- crates/teepot/src/log/mod.rs | 5 +--- crates/teepot/src/prover/reportdata.rs | 3 +-- crates/teepot/src/quote/error.rs | 2 +- crates/teepot/src/quote/mod.rs | 2 +- crates/teepot/src/quote/phala.rs | 4 +-- crates/teepot/src/quote/tcblevel.rs | 6 ++--- 18 files changed, 42 insertions(+), 62 deletions(-) diff --git a/bin/sha384-extend/src/main.rs b/bin/sha384-extend/src/main.rs index f2ace5e..be496f0 100644 --- a/bin/sha384-extend/src/main.rs +++ b/bin/sha384-extend/src/main.rs @@ -61,13 +61,11 @@ pub fn extend_sha384(base: &str, extend: &str) -> Result { let mut hasher = sha2::Sha384::new(); hasher.update(pad::<48>(&hex::decode(base).context(format!( - "Failed to decode base digest '{}' - expected hex string", - base + "Failed to decode base digest '{base}' - expected hex string", ))?)?); hasher.update(pad::<48>(&hex::decode(extend).context(format!( - "Failed to decode extend digest '{}' - expected hex string", - extend + "Failed to decode extend digest '{extend}' - expected hex string", ))?)?); Ok(hex::encode(hasher.finalize())) diff --git a/bin/tee-self-attestation-test/src/main.rs b/bin/tee-self-attestation-test/src/main.rs index ee90314..4c9437f 100644 --- a/bin/tee-self-attestation-test/src/main.rs +++ b/bin/tee-self-attestation-test/src/main.rs @@ -26,7 +26,7 @@ async fn main() -> Result<()> { .context("failed to get quote and collateral")?; let base64_string = general_purpose::STANDARD.encode(report.quote.as_ref()); - print!("{}", base64_string); + print!("{base64_string}"); Ok(()) } diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs index 4eb84f1..b33b7ad 100644 --- a/bin/verify-attestation/src/main.rs +++ b/bin/verify-attestation/src/main.rs @@ -81,7 +81,7 @@ fn print_quote_verification_summary(quote_verification_result: &QuoteVerificatio for advisory in advisories { println!("\tInfo: Advisory ID: {advisory}"); } - println!("Quote verification result: {}", tcblevel); + println!("Quote verification result: {tcblevel}"); println!("{:#}", "e.report); } diff --git a/bin/verify-era-proof-attestation/src/client/json_rpc.rs b/bin/verify-era-proof-attestation/src/client/json_rpc.rs index a9417ff..407b819 100644 --- a/bin/verify-era-proof-attestation/src/client/json_rpc.rs +++ b/bin/verify-era-proof-attestation/src/client/json_rpc.rs @@ -26,12 +26,10 @@ impl MainNodeClient { /// Create a new client for the main node pub fn new(rpc_url: Url, chain_id: u64) -> error::Result { let chain_id = L2ChainId::try_from(chain_id) - .map_err(|e| error::Error::Internal(format!("Invalid chain ID: {}", e)))?; + .map_err(|e| error::Error::Internal(format!("Invalid chain ID: {e}")))?; let node_client = NodeClient::http(rpc_url.into()) - .map_err(|e| { - error::Error::Internal(format!("Failed to create JSON-RPC client: {}", e)) - })? + .map_err(|e| error::Error::Internal(format!("Failed to create JSON-RPC client: {e}")))? .for_network(chain_id.into()) .build(); @@ -46,13 +44,13 @@ impl JsonRpcClient for MainNodeClient { .get_l1_batch_details(batch_number) .rpc_context("get_l1_batch_details") .await - .map_err(|e| error::Error::JsonRpc(format!("Failed to get batch details: {}", e)))? + .map_err(|e| error::Error::JsonRpc(format!("Failed to get batch details: {e}")))? .ok_or_else(|| { - error::Error::JsonRpc(format!("No details found for batch #{}", batch_number)) + error::Error::JsonRpc(format!("No details found for batch #{batch_number}")) })?; batch_details.base.root_hash.ok_or_else(|| { - error::Error::JsonRpc(format!("No root hash found for batch #{}", batch_number)) + error::Error::JsonRpc(format!("No root hash found for batch #{batch_number}")) }) } } diff --git a/bin/verify-era-proof-attestation/src/core/config.rs b/bin/verify-era-proof-attestation/src/core/config.rs index 8132ddc..d77566b 100644 --- a/bin/verify-era-proof-attestation/src/core/config.rs +++ b/bin/verify-era-proof-attestation/src/core/config.rs @@ -190,15 +190,12 @@ impl VerifierConfig { pub fn new(args: VerifierConfigArgs) -> error::Result { let policy = if let Some(path) = &args.attestation_policy_file { let policy_content = fs::read_to_string(path).map_err(|e| { - error::Error::internal(format!("Failed to read attestation policy file: {}", e)) + error::Error::internal(format!("Failed to read attestation policy file: {e}")) })?; let policy_config: AttestationPolicyConfig = serde_yaml::from_str(&policy_content) .map_err(|e| { - error::Error::internal(format!( - "Failed to parse attestation policy file: {}", - e - )) + error::Error::internal(format!("Failed to parse attestation policy file: {e}")) })?; tracing::info!("Loaded attestation policy from file: {:?}", path); diff --git a/bin/verify-era-proof-attestation/src/core/types.rs b/bin/verify-era-proof-attestation/src/core/types.rs index 11636c2..0f8b7d7 100644 --- a/bin/verify-era-proof-attestation/src/core/types.rs +++ b/bin/verify-era-proof-attestation/src/core/types.rs @@ -31,13 +31,13 @@ impl fmt::Display for VerifierMode { end_batch, } => { if start_batch == end_batch { - write!(f, "one-shot mode (batch {})", start_batch) + write!(f, "one-shot mode (batch {start_batch})") } else { - write!(f, "one-shot mode (batches {}-{})", start_batch, end_batch) + write!(f, "one-shot mode (batches {start_batch}-{end_batch})") } } VerifierMode::Continuous { start_batch } => { - write!(f, "continuous mode (starting from batch {})", start_batch) + write!(f, "continuous mode (starting from batch {start_batch})") } } } @@ -89,8 +89,7 @@ impl fmt::Display for VerificationResult { } => { write!( f, - "Partial Success ({} verified, {} failed)", - verified_count, unverified_count + "Partial Success ({verified_count} verified, {unverified_count} failed)" ) } VerificationResult::Failure => write!(f, "Failure"), diff --git a/bin/verify-era-proof-attestation/src/main.rs b/bin/verify-era-proof-attestation/src/main.rs index 2f66b43..9b45203 100644 --- a/bin/verify-era-proof-attestation/src/main.rs +++ b/bin/verify-era-proof-attestation/src/main.rs @@ -74,7 +74,7 @@ async fn main() -> Result<()> { }, Err(e) => { tracing::error!("Task panicked: {}", e); - Err(Error::internal(format!("Task panicked: {}", e))) + Err(Error::internal(format!("Task panicked: {e}"))) } } }, diff --git a/bin/verify-era-proof-attestation/src/proof/parsing.rs b/bin/verify-era-proof-attestation/src/proof/parsing.rs index 6519e17..8611741 100644 --- a/bin/verify-era-proof-attestation/src/proof/parsing.rs +++ b/bin/verify-era-proof-attestation/src/proof/parsing.rs @@ -21,7 +21,7 @@ impl ProofResponseParser { } } - return Err(error::Error::JsonRpc(format!("JSONRPC error: {:?}", error))); + return Err(error::Error::JsonRpc(format!("JSONRPC error: {error:?}"))); } // Extract proofs from the result diff --git a/bin/verify-era-proof-attestation/src/verification/attestation.rs b/bin/verify-era-proof-attestation/src/verification/attestation.rs index 656ab57..e37527f 100644 --- a/bin/verify-era-proof-attestation/src/verification/attestation.rs +++ b/bin/verify-era-proof-attestation/src/verification/attestation.rs @@ -17,7 +17,7 @@ impl AttestationVerifier { // Get current time for verification let unix_time: i64 = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) - .map_err(|e| error::Error::internal(format!("Failed to get system time: {}", e)))? + .map_err(|e| error::Error::internal(format!("Failed to get system time: {e}")))? .as_secs() as _; // Verify the quote with the collateral diff --git a/bin/verify-era-proof-attestation/src/verification/policy.rs b/bin/verify-era-proof-attestation/src/verification/policy.rs index 8130075..b925aab 100644 --- a/bin/verify-era-proof-attestation/src/verification/policy.rs +++ b/bin/verify-era-proof-attestation/src/verification/policy.rs @@ -107,8 +107,7 @@ impl PolicyEnforcer { ) -> Result<()> { if !allowed_levels.contains(actual_level) { let error_msg = format!( - "Quote verification failed: TCB level mismatch (expected one of: {:?}, actual: {})", - allowed_levels, actual_level + "Quote verification failed: TCB level mismatch (expected one of: {allowed_levels:?}, actual: {actual_level})", ); return Err(Error::policy_violation(error_msg)); } @@ -152,8 +151,7 @@ impl PolicyEnforcer { .collect::>() .join(", "); let error_msg = format!( - "Quote verification failed: {} mismatch (expected one of: [ {} ], actual: {:x})", - field_name, valid_values, actual_value + "Quote verification failed: {field_name} mismatch (expected one of: [ {valid_values} ], actual: {actual_value:x})" ); return Err(Error::policy_violation(error_msg)); } diff --git a/bin/verify-era-proof-attestation/src/verification/signature.rs b/bin/verify-era-proof-attestation/src/verification/signature.rs index 314218a..f940ba4 100644 --- a/bin/verify-era-proof-attestation/src/verification/signature.rs +++ b/bin/verify-era-proof-attestation/src/verification/signature.rs @@ -30,9 +30,8 @@ impl SignatureVerifier { let report_data_bytes = quote_verification_result.quote.get_report_data(); tracing::trace!(?report_data_bytes); - let report_data = ReportData::try_from(report_data_bytes).map_err(|e| { - error::Error::internal(format!("Could not convert to ReportData: {}", e)) - })?; + let report_data = ReportData::try_from(report_data_bytes) + .map_err(|e| error::Error::internal(format!("Could not convert to ReportData: {e}")))?; Self::verify(&report_data, &root_hash, signature) } @@ -100,7 +99,7 @@ impl SignatureVerifier { })?; recover_signer(&signature_bytes, &root_hash_msg).map_err(|e| { - error::Error::signature_verification(format!("Failed to recover signer: {}", e)) + error::Error::signature_verification(format!("Failed to recover signer: {e}")) })? } // Any other length is invalid diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs index 8ebc887..1f37070 100644 --- a/crates/intel-dcap-api/src/client/helpers.rs +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -25,20 +25,18 @@ impl ApiClient { if technology == "tdx" && self.api_version == ApiVersion::V3 { return Err(IntelApiError::UnsupportedApiVersion(format!( - "TDX endpoint /{}/{}/{} requires API v4", - service, endpoint, technology + "TDX endpoint /{service}/{endpoint}/{technology} requires API v4", ))); } if technology == "sgx" && service == "registration" { // Registration paths are fixed at v1 regardless of client's api_version - return Ok(format!("/sgx/registration/v1/{}", endpoint).replace("//", "/")); + return Ok(format!("/sgx/registration/v1/{endpoint}").replace("//", "/")); } - Ok(format!( - "/{}/certification/{}/{}/{}", - technology, api_segment, service, endpoint + Ok( + format!("/{technology}/certification/{api_segment}/{service}/{endpoint}") + .replace("//", "/"), ) - .replace("//", "/")) } /// Helper to add an optional header if the string is non-empty. @@ -187,13 +185,11 @@ impl ApiClient { /// Ensures the client is configured for API v4, otherwise returns an error. pub(super) fn ensure_v4_api(&self, function_name: &str) -> Result<(), IntelApiError> { if self.api_version != ApiVersion::V4 { - Err(IntelApiError::UnsupportedApiVersion(format!( - "{} requires API v4", - function_name - ))) - } else { - Ok(()) + return Err(IntelApiError::UnsupportedApiVersion(format!( + "{function_name} requires API v4", + ))); } + Ok(()) } /// Checks if a V4-only parameter is provided with a V3 API version. @@ -204,8 +200,7 @@ impl ApiClient { ) -> Result<(), IntelApiError> { if self.api_version == ApiVersion::V3 && param_value.is_some() { Err(IntelApiError::UnsupportedApiVersion(format!( - "'{}' parameter requires API v4", - param_name + "'{param_name}' parameter requires API v4", ))) } else { Ok(()) diff --git a/crates/teepot/src/log/mod.rs b/crates/teepot/src/log/mod.rs index d0fd107..795cc10 100644 --- a/crates/teepot/src/log/mod.rs +++ b/crates/teepot/src/log/mod.rs @@ -53,10 +53,7 @@ pub fn setup_logging( .try_from_env() .unwrap_or(match *log_level { LevelFilter::OFF => EnvFilter::new("off"), - _ => EnvFilter::new(format!( - "warn,{crate_name}={log_level},teepot={log_level}", - log_level = log_level - )), + _ => EnvFilter::new(format!("warn,{crate_name}={log_level},teepot={log_level}")), }); let fmt_layer = tracing_subscriber::fmt::layer() diff --git a/crates/teepot/src/prover/reportdata.rs b/crates/teepot/src/prover/reportdata.rs index bcff688..fd849bf 100644 --- a/crates/teepot/src/prover/reportdata.rs +++ b/crates/teepot/src/prover/reportdata.rs @@ -37,8 +37,7 @@ pub enum ReportData { fn report_data_to_bytes(data: &[u8], version: u8) -> [u8; REPORT_DATA_LENGTH] { debug_assert!( data.len() < REPORT_DATA_LENGTH, // Ensure there is space for the version byte - "Data length exceeds maximum of {} bytes", - REPORT_DATA_LENGTH + "Data length exceeds maximum of {REPORT_DATA_LENGTH} bytes", ); let mut bytes = [0u8; REPORT_DATA_LENGTH]; bytes[..data.len()].copy_from_slice(data); diff --git a/crates/teepot/src/quote/error.rs b/crates/teepot/src/quote/error.rs index b469161..cf121d4 100644 --- a/crates/teepot/src/quote/error.rs +++ b/crates/teepot/src/quote/error.rs @@ -104,7 +104,7 @@ pub trait QuoteContextErr { impl QuoteContextErr for Result { type Ok = T; fn str_context(self, msg: I) -> Result { - self.map_err(|e| QuoteError::Unexpected(format!("{}: {}", msg, e))) + self.map_err(|e| QuoteError::Unexpected(format!("{msg}: {e}"))) } } diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 8a373cf..c9bead8 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -583,7 +583,7 @@ impl Display for TEEType { TEEType::TDX => "tdx", TEEType::SNP => "snp", }; - write!(f, "{}", str) + write!(f, "{str}") } } diff --git a/crates/teepot/src/quote/phala.rs b/crates/teepot/src/quote/phala.rs index e416110..0fdafbc 100644 --- a/crates/teepot/src/quote/phala.rs +++ b/crates/teepot/src/quote/phala.rs @@ -134,14 +134,14 @@ fn convert_to_collateral( /// Split the last zero byte fn get_str_from_bytes(bytes: &[u8], context: &str) -> Result { let c_str = CStr::from_bytes_until_nul(bytes) - .str_context(format!("Failed to extract CString: {}", context))?; + .str_context(format!("Failed to extract CString: {context}"))?; Ok(c_str.to_string_lossy().into_owned()) } /// Parse JSON field from collateral data fn parse_json_field(data: &[u8], context: &str) -> Result { serde_json::from_str(&get_str_from_bytes(data, context)?) - .str_context(format!("Failed to parse JSON: {}", context)) + .str_context(format!("Failed to parse JSON: {context}")) } /// Convert Collateral to QuoteCollateralV3 diff --git a/crates/teepot/src/quote/tcblevel.rs b/crates/teepot/src/quote/tcblevel.rs index f2baee5..19561a2 100644 --- a/crates/teepot/src/quote/tcblevel.rs +++ b/crates/teepot/src/quote/tcblevel.rs @@ -46,7 +46,7 @@ impl FromStr for TcbLevel { "outofdate" => Ok(TcbLevel::OutOfDate), "outofdateconfigneeded" => Ok(TcbLevel::OutOfDateConfigNeeded), "invalid" => Ok(TcbLevel::Invalid), - _ => Err(format!("Invalid TCB level: {}", s)), + _ => Err(format!("Invalid TCB level: {s}")), } } } @@ -72,8 +72,8 @@ pub fn parse_tcb_levels( let mut set = EnumSet::new(); for level_str in s.split(',') { let level_str = level_str.trim(); - let level = TcbLevel::from_str(level_str) - .map_err(|_| format!("Invalid TCB level: {}", level_str))?; + let level = + TcbLevel::from_str(level_str).map_err(|_| format!("Invalid TCB level: {level_str}"))?; set.insert(level); } Ok(set) From 0768b0ad67ad525570eb85faa9b20d17736324fa Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 15:53:55 +0100 Subject: [PATCH 081/114] refactor: prefer conversion methods to infallable casts --- bin/rtmr-calc/src/main.rs | 6 +++--- crates/teepot/src/ethereum/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs index a3ab72c..d104e82 100644 --- a/bin/rtmr-calc/src/main.rs +++ b/bin/rtmr-calc/src/main.rs @@ -129,7 +129,7 @@ fn main() -> Result<()> { let _ = device.seek(SeekFrom::Start(pstart))?; assert_eq!(header.part_size, 128); - assert!(header.num_parts < u8::MAX as _); + assert!(header.num_parts < u32::from(u8::MAX)); let empty_bytes = [0u8; 128]; @@ -177,8 +177,8 @@ fn main() -> Result<()> { .find(|s| s.name().unwrap().eq(sect)) .ok_or(anyhow!("Failed to find section `{sect}`"))?; - let mut start = s.pointer_to_raw_data as u64; - let end = start + s.virtual_size as u64; + let mut start = u64::from(s.pointer_to_raw_data); + let end = start + u64::from(s.virtual_size); debug!(sect, start, end, len = (s.virtual_size)); diff --git a/crates/teepot/src/ethereum/mod.rs b/crates/teepot/src/ethereum/mod.rs index 637565a..12dbe11 100644 --- a/crates/teepot/src/ethereum/mod.rs +++ b/crates/teepot/src/ethereum/mod.rs @@ -15,7 +15,7 @@ use sha3::{Digest, Keccak256}; pub fn recover_signer(sig: &[u8; 65], root_hash: &Message) -> Result<[u8; 20]> { let sig = RecoverableSignature::from_compact( &sig[0..64], - RecoveryId::try_from(sig[64] as i32 - 27)?, + RecoveryId::try_from(i32::from(sig[64]) - 27)?, )?; let public = SECP256K1.recover_ecdsa(root_hash, &sig)?; Ok(public_key_to_ethereum_address(&public)) From 2ff169da9f9fc40cebb8db6c8f7c13890f0766ce Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 16:03:42 +0100 Subject: [PATCH 082/114] refactor: improve type ergonomics --- bin/rtmr-calc/src/main.rs | 2 +- bin/verify-era-proof-attestation/src/core/config.rs | 6 +++--- bin/verify-era-proof-attestation/src/error.rs | 2 +- .../src/processor/batch_processor.rs | 2 +- .../src/processor/mod.rs | 4 ++-- .../src/proof/fetcher.rs | 2 +- bin/verify-era-proof-attestation/src/proof/types.rs | 2 +- .../src/verification/batch.rs | 2 +- .../src/verification/policy.rs | 13 +++++-------- crates/intel-dcap-api/src/client/helpers.rs | 2 +- crates/teepot/src/quote/phala.rs | 10 +++++----- 11 files changed, 22 insertions(+), 25 deletions(-) diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs index d104e82..2817da3 100644 --- a/bin/rtmr-calc/src/main.rs +++ b/bin/rtmr-calc/src/main.rs @@ -160,7 +160,7 @@ fn main() -> Result<()> { let section_table = pe.get_section_table()?; - for section in section_table.iter() { + for section in §ion_table { debug!(section_name = ?section.name()?); } diff --git a/bin/verify-era-proof-attestation/src/core/config.rs b/bin/verify-era-proof-attestation/src/core/config.rs index d77566b..4e0607f 100644 --- a/bin/verify-era-proof-attestation/src/core/config.rs +++ b/bin/verify-era-proof-attestation/src/core/config.rs @@ -260,7 +260,7 @@ fn decode_tdx_mrs( Some(mrs_array) => { let result = mrs_array .into_iter() - .map(|strings| decode_and_combine_mrs(strings, bytes_length)) + .map(|strings| decode_and_combine_mrs(&strings, bytes_length)) .collect::, _>>()?; Ok(Some(result)) } @@ -269,12 +269,12 @@ fn decode_tdx_mrs( // Helper function to decode and combine MRs fn decode_and_combine_mrs( - strings: [String; 5], + strings: &[String; 5], bytes_length: usize, ) -> Result { let mut buffer = BytesMut::with_capacity(bytes_length * 5); - for s in &strings { + for s in strings { if s.len() > (bytes_length * 2) { return Err(hex::FromHexError::InvalidStringLength); } diff --git a/bin/verify-era-proof-attestation/src/error.rs b/bin/verify-era-proof-attestation/src/error.rs index ced5a6a..ec58c78 100644 --- a/bin/verify-era-proof-attestation/src/error.rs +++ b/bin/verify-era-proof-attestation/src/error.rs @@ -96,7 +96,7 @@ impl Error { impl From for Error { fn from(value: reqwest::Error) -> Self { Self::Http { - status_code: value.status().map(|v| v.as_u16()).unwrap_or(0), + status_code: value.status().map_or(0, |v| v.as_u16()), message: value.to_string(), } } diff --git a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs index c7e8cbf..1e814d4 100644 --- a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs @@ -53,7 +53,7 @@ impl BatchProcessor { // Fetch proofs for the current batch across different TEE types let mut proofs = Vec::new(); - for tee_type in self.config.args.tee_types.iter() { + for tee_type in self.config.args.tee_types.iter().copied() { match self .proof_fetcher .get_proofs(token, batch_number, tee_type) diff --git a/bin/verify-era-proof-attestation/src/processor/mod.rs b/bin/verify-era-proof-attestation/src/processor/mod.rs index 75df936..a2bac5b 100644 --- a/bin/verify-era-proof-attestation/src/processor/mod.rs +++ b/bin/verify-era-proof-attestation/src/processor/mod.rs @@ -43,14 +43,14 @@ impl ProcessorFactory { /// Create a new processor based on the provided configuration pub fn create(config: VerifierConfig) -> Result<(ProcessorType, VerifierMode)> { let mode = if let Some((start, end)) = config.args.batch_range { - let processor = OneShotProcessor::new(config.clone(), start, end)?; + let processor = OneShotProcessor::new(config, start, end)?; let mode = VerifierMode::OneShot { start_batch: start, end_batch: end, }; (ProcessorType::OneShot(processor), mode) } else if let Some(start) = config.args.continuous { - let processor = ContinuousProcessor::new(config.clone(), start)?; + let processor = ContinuousProcessor::new(config, start)?; let mode = VerifierMode::Continuous { start_batch: start }; (ProcessorType::Continuous(processor), mode) } else { diff --git a/bin/verify-era-proof-attestation/src/proof/fetcher.rs b/bin/verify-era-proof-attestation/src/proof/fetcher.rs index d8d0322..5da8643 100644 --- a/bin/verify-era-proof-attestation/src/proof/fetcher.rs +++ b/bin/verify-era-proof-attestation/src/proof/fetcher.rs @@ -36,7 +36,7 @@ impl ProofFetcher { &self, token: &CancellationToken, batch_number: L1BatchNumber, - tee_type: &TeeType, + tee_type: TeeType, ) -> Result> { let mut proofs_request = GetProofsRequest::new(batch_number, tee_type); let mut backoff = Duration::from_secs(1); diff --git a/bin/verify-era-proof-attestation/src/proof/types.rs b/bin/verify-era-proof-attestation/src/proof/types.rs index e2362e6..2957083 100644 --- a/bin/verify-era-proof-attestation/src/proof/types.rs +++ b/bin/verify-era-proof-attestation/src/proof/types.rs @@ -17,7 +17,7 @@ pub struct GetProofsRequest { impl GetProofsRequest { /// Create a new request for the given batch number - pub fn new(batch_number: L1BatchNumber, tee_type: &TeeType) -> Self { + pub fn new(batch_number: L1BatchNumber, tee_type: TeeType) -> Self { GetProofsRequest { jsonrpc: "2.0".to_string(), id: 1, diff --git a/bin/verify-era-proof-attestation/src/verification/batch.rs b/bin/verify-era-proof-attestation/src/verification/batch.rs index 5542f05..9eb9200 100644 --- a/bin/verify-era-proof-attestation/src/verification/batch.rs +++ b/bin/verify-era-proof-attestation/src/verification/batch.rs @@ -48,7 +48,7 @@ impl BatchVerifier { let mut total_proofs_count: u32 = 0; let mut verified_proofs_count: u32 = 0; - for proof in proofs.into_iter() { + for proof in proofs { if token.is_cancelled() { tracing::warn!("Stop signal received during batch verification"); return Ok(BatchVerificationResult { diff --git a/bin/verify-era-proof-attestation/src/verification/policy.rs b/bin/verify-era-proof-attestation/src/verification/policy.rs index b925aab..b283e81 100644 --- a/bin/verify-era-proof-attestation/src/verification/policy.rs +++ b/bin/verify-era-proof-attestation/src/verification/policy.rs @@ -24,7 +24,7 @@ impl PolicyEnforcer { match "e.report { Report::SgxEnclave(report_body) => { // Validate TCB level - Self::validate_tcb_level(&attestation_policy.sgx_allowed_tcb_levels, tcblevel)?; + Self::validate_tcb_level(attestation_policy.sgx_allowed_tcb_levels, tcblevel)?; // Validate SGX Advisories for advisory in "e_verification_result.advisories { @@ -50,7 +50,7 @@ impl PolicyEnforcer { } Report::TD10(report_body) => { // Validate TCB level - Self::validate_tcb_level(&attestation_policy.tdx_allowed_tcb_levels, tcblevel)?; + Self::validate_tcb_level(attestation_policy.tdx_allowed_tcb_levels, tcblevel)?; // Validate TDX Advisories for advisory in "e_verification_result.advisories { @@ -74,7 +74,7 @@ impl PolicyEnforcer { } Report::TD15(report_body) => { // Validate TCB level - Self::validate_tcb_level(&attestation_policy.tdx_allowed_tcb_levels, tcblevel)?; + Self::validate_tcb_level(attestation_policy.tdx_allowed_tcb_levels, tcblevel)?; // Validate TDX Advisories for advisory in "e_verification_result.advisories { @@ -101,10 +101,7 @@ impl PolicyEnforcer { } /// Helper method to validate TCB levels - fn validate_tcb_level( - allowed_levels: &EnumSet, - actual_level: TcbLevel, - ) -> Result<()> { + fn validate_tcb_level(allowed_levels: EnumSet, actual_level: TcbLevel) -> Result<()> { if !allowed_levels.contains(actual_level) { let error_msg = format!( "Quote verification failed: TCB level mismatch (expected one of: {allowed_levels:?}, actual: {actual_level})", @@ -116,7 +113,7 @@ impl PolicyEnforcer { /// Helper method to build combined TDX measurement register fn build_tdx_mr(parts: [&[u8]; N]) -> Vec { - parts.into_iter().flatten().cloned().collect() + parts.into_iter().flatten().copied().collect() } /// Check if a policy value matches the actual value diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs index 1f37070..ee53cc3 100644 --- a/crates/intel-dcap-api/src/client/helpers.rs +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -193,7 +193,7 @@ impl ApiClient { } /// Checks if a V4-only parameter is provided with a V3 API version. - pub(super) fn check_v4_only_param( + pub(super) fn check_v4_only_param( &self, param_value: Option, param_name: &str, diff --git a/crates/teepot/src/quote/phala.rs b/crates/teepot/src/quote/phala.rs index 0fdafbc..fcbd48e 100644 --- a/crates/teepot/src/quote/phala.rs +++ b/crates/teepot/src/quote/phala.rs @@ -24,7 +24,7 @@ fn extract_header_value( .ok_or_else(|| QuoteError::Unexpected(format!("Missing required header: {header_name}")))? .to_str() .map_err(|e| QuoteError::Unexpected(format!("Invalid header value: {e}"))) - .map(|val| val.to_string()) + .map(str::to_string) } /// Fetch collateral data from Intel's Provisioning Certification Service @@ -74,14 +74,14 @@ pub(crate) fn get_collateral(quote: &[u8]) -> Result { let (collateral, pck_crl, pck_issuer_chain) = result; // Convert QuoteCollateralV3 to Collateral - convert_to_collateral(collateral, pck_crl, pck_issuer_chain) + convert_to_collateral(collateral, &pck_crl, &pck_issuer_chain) } // Helper function to convert QuoteCollateralV3 to Collateral fn convert_to_collateral( collateral: QuoteCollateralV3, - pck_crl: String, - pck_issuer_chain: Bytes, + pck_crl: &str, + pck_issuer_chain: &[u8], ) -> Result { let QuoteCollateralV3 { tcb_info_issuer_chain, @@ -119,7 +119,7 @@ fn convert_to_collateral( root_ca_crl: Box::new([]), // Converted values - pck_crl_issuer_chain: pck_issuer_chain.as_ref().into(), + pck_crl_issuer_chain: pck_issuer_chain.into(), pck_crl: pck_crl.as_bytes().into(), tcb_info_issuer_chain: to_bytes_with_nul(tcb_info_issuer_chain, "tcb_info_issuer_chain")?, tcb_info: to_bytes_with_nul(tcb_info_json, "tcb_info")?, From 36afc85d3891fac8aa36ce1ecfd81b6dc11d182b Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 16:05:47 +0100 Subject: [PATCH 083/114] refactor: prefer if let to single variant match --- .../src/core/config.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/core/config.rs b/bin/verify-era-proof-attestation/src/core/config.rs index 4e0607f..c6f219b 100644 --- a/bin/verify-era-proof-attestation/src/core/config.rs +++ b/bin/verify-era-proof-attestation/src/core/config.rs @@ -292,19 +292,16 @@ fn parse_batch_range(s: &str) -> error::Result<(L1BatchNumber, L1BatchNumber)> { .map(L1BatchNumber::from) .map_err(|e| error::Error::internal(format!("Can't convert batch {s} to number: {e}"))) }; - match s.split_once('-') { - Some((start, end)) => { - let (start, end) = (parse(start)?, parse(end)?); - if start > end { - Err(error::Error::InvalidBatchRange(s.into())) - } else { - Ok((start, end)) - } - } - None => { - let batch_number = parse(s)?; - Ok((batch_number, batch_number)) + if let Some((start, end)) = s.split_once('-') { + let (start, end) = (parse(start)?, parse(end)?); + if start > end { + Err(error::Error::InvalidBatchRange(s.into())) + } else { + Ok((start, end)) } + } else { + let batch_number = parse(s)?; + Ok((batch_number, batch_number)) } } From 6a9e035d19414100f88eabd8ba3a7517a63c8a08 Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 16:06:24 +0100 Subject: [PATCH 084/114] refactor: combine equivalent match branches --- bin/verify-era-proof-attestation/src/core/types.rs | 6 +++--- .../src/processor/continuous_processor.rs | 5 +++-- .../src/processor/one_shot_processor.rs | 5 +++-- crates/teepot/src/quote/tcblevel.rs | 3 +-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/core/types.rs b/bin/verify-era-proof-attestation/src/core/types.rs index 0f8b7d7..e9d64b2 100644 --- a/bin/verify-era-proof-attestation/src/core/types.rs +++ b/bin/verify-era-proof-attestation/src/core/types.rs @@ -72,9 +72,9 @@ impl VerificationResult { verified_count, unverified_count, } => verified_count > unverified_count, - VerificationResult::Failure => false, - VerificationResult::Interrupted => false, - VerificationResult::NoProofsFound => false, + VerificationResult::Failure + | VerificationResult::Interrupted + | VerificationResult::NoProofsFound => false, } } } diff --git a/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs b/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs index 9796367..f9fb152 100644 --- a/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/continuous_processor.rs @@ -50,8 +50,9 @@ impl ContinuousProcessor { match self.batch_processor.process_batch(token, batch).await { Ok(result) => { match result { - VerificationResult::Success => success_count += 1, - VerificationResult::PartialSuccess { .. } => success_count += 1, + VerificationResult::Success | VerificationResult::PartialSuccess { .. } => { + success_count += 1; + } VerificationResult::Failure => failure_count += 1, VerificationResult::Interrupted => { results.push((current_batch, result)); diff --git a/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs b/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs index 1bd7d77..994724b 100644 --- a/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/one_shot_processor.rs @@ -55,8 +55,9 @@ impl OneShotProcessor { let result = self.batch_processor.process_batch(token, batch).await?; match result { - VerificationResult::Success => success_count += 1, - VerificationResult::PartialSuccess { .. } => success_count += 1, + VerificationResult::Success | VerificationResult::PartialSuccess { .. } => { + success_count += 1; + } VerificationResult::Failure => failure_count += 1, VerificationResult::Interrupted => { results.push((batch_number, result)); diff --git a/crates/teepot/src/quote/tcblevel.rs b/crates/teepot/src/quote/tcblevel.rs index 19561a2..96cd5a0 100644 --- a/crates/teepot/src/quote/tcblevel.rs +++ b/crates/teepot/src/quote/tcblevel.rs @@ -38,8 +38,7 @@ impl FromStr for TcbLevel { fn from_str(s: &str) -> Result { match s.to_ascii_lowercase().as_str() { - "ok" => Ok(TcbLevel::Ok), - "uptodate" => Ok(TcbLevel::Ok), + "ok" | "uptodate" => Ok(TcbLevel::Ok), "configneeded" => Ok(TcbLevel::ConfigNeeded), "configandswhardeningneeded" => Ok(TcbLevel::ConfigAndSwHardeningNeeded), "swhardeningneeded" => Ok(TcbLevel::SwHardeningNeeded), From 2ca0b471696862a157c2cbed7cf320bf50470252 Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 16:07:13 +0100 Subject: [PATCH 085/114] refactor: improve punctuation readability --- .../src/verification/batch.rs | 2 +- crates/teepot/src/config/mod.rs | 8 ++++---- crates/teepot/src/quote/mod.rs | 4 ++-- crates/teepot/src/sgx/sign.rs | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/verify-era-proof-attestation/src/verification/batch.rs b/bin/verify-era-proof-attestation/src/verification/batch.rs index 9eb9200..db26815 100644 --- a/bin/verify-era-proof-attestation/src/verification/batch.rs +++ b/bin/verify-era-proof-attestation/src/verification/batch.rs @@ -119,7 +119,7 @@ impl BatchVerifier { ); verified_proofs_count += 1; } else { - tracing::warn!(batch_no, proof.proved_at, tee_type, "Verification failed!",); + tracing::warn!(batch_no, proof.proved_at, tee_type, "Verification failed!"); } } diff --git a/crates/teepot/src/config/mod.rs b/crates/teepot/src/config/mod.rs index 100317a..95ae15f 100644 --- a/crates/teepot/src/config/mod.rs +++ b/crates/teepot/src/config/mod.rs @@ -312,13 +312,13 @@ fn init_telemetry( if config.logging.console { // Optionally configure JSON logging if config.logging.json { - subscriber.with(fmt_layer.json()).init() + subscriber.with(fmt_layer.json()).init(); } else { - subscriber.with(fmt_layer.pretty()).init() + subscriber.with(fmt_layer.pretty()).init(); } } else { - subscriber.init() - }; + subscriber.init(); + } Ok(()) } diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index c9bead8..1d28371 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -31,9 +31,9 @@ use std::{ use tracing::trace; #[allow(missing_docs)] -pub const TEE_TYPE_SGX: u32 = 0x00000000; +pub const TEE_TYPE_SGX: u32 = 0x0000_0000; #[allow(missing_docs)] -pub const TEE_TYPE_TDX: u32 = 0x00000081; +pub const TEE_TYPE_TDX: u32 = 0x0000_0081; #[allow(missing_docs)] pub const BODY_SGX_ENCLAVE_REPORT_TYPE: u16 = 1; diff --git a/crates/teepot/src/sgx/sign.rs b/crates/teepot/src/sgx/sign.rs index 4019590..6d136a3 100644 --- a/crates/teepot/src/sgx/sign.rs +++ b/crates/teepot/src/sgx/sign.rs @@ -50,8 +50,8 @@ pub struct Author { unsafe impl Zeroable for Author {} impl Author { - const HEADER1: [u8; 16] = 0x06000000E10000000000010000000000u128.to_be_bytes(); - const HEADER2: [u8; 16] = 0x01010000600000006000000001000000u128.to_be_bytes(); + const HEADER1: [u8; 16] = 0x0600_0000_E100_0000_0000_0100_0000_0000u128.to_be_bytes(); + const HEADER2: [u8; 16] = 0x0101_0000_6000_0000_6000_0000_0100_0000u128.to_be_bytes(); #[allow(clippy::unreadable_literal)] /// Creates a new Author from a date and software defined value. @@ -245,7 +245,7 @@ impl Digest for S256Digest { #[inline] fn update(&mut self, bytes: &[u8]) { - self.0.update(bytes) + self.0.update(bytes); } #[inline] From d54f7b14ade1710db5fb80be43093ce1ab2ec4e1 Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Thu, 17 Apr 2025 16:07:24 +0100 Subject: [PATCH 086/114] refactor: remove redundant continue --- .../src/processor/batch_processor.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs index 1e814d4..ad0ae2c 100644 --- a/bin/verify-era-proof-attestation/src/processor/batch_processor.rs +++ b/bin/verify-era-proof-attestation/src/processor/batch_processor.rs @@ -68,7 +68,6 @@ impl BatchProcessor { batch_number.0, e ); - continue; } } } From 2118466a8a6e773dffcb9caf8e8c485e14316b25 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 5 May 2025 14:49:57 +0200 Subject: [PATCH 087/114] refactor: replace custom Quote parsing with library version - Removed custom `Quote` structure and parsing logic in `teepot/src/sgx/mod.rs`. - Updated references to use the library-provided `Quote` methods, such as `Quote::parse` and `get_report_data`. - Simplified code and reduced redundancy by leveraging existing library functionality. --- crates/teepot-vault/src/client/mod.rs | 8 +-- crates/teepot/src/sgx/mod.rs | 75 --------------------------- 2 files changed, 4 insertions(+), 79 deletions(-) diff --git a/crates/teepot-vault/src/client/mod.rs b/crates/teepot-vault/src/client/mod.rs index 97625d7..85fa871 100644 --- a/crates/teepot-vault/src/client/mod.rs +++ b/crates/teepot-vault/src/client/mod.rs @@ -31,7 +31,7 @@ pub use teepot::quote::{ tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}, verify_quote_with_collateral, QuoteVerificationResult, }; -use teepot::{quote::Report, sgx::Quote}; +use teepot::quote::{Quote, Report}; use tracing::{debug, error, info, trace, warn}; use x509_cert::{ der::{Decode as _, Encode as _}, @@ -174,17 +174,17 @@ impl TeeConnection { debug!("Failed to get collateral in certificate"); } - let quote = Quote::try_from_bytes(quote_bytes).map_err(|e| { + let quote = Quote::parse(quote_bytes).map_err(|e| { Error::General(format!("Failed get quote in certificate {e:?}")) })?; - if "e.report_body.reportdata[..32] != hash.as_slice() { + if "e.get_report_data()[..32] != hash.as_slice() { error!("Report data mismatch"); return Err(Error::General("Report data mismatch".to_string())); } else { info!( "Report data matches `{}`", - hex::encode("e.report_body.reportdata[..32]) + hex::encode("e.get_report_data()[..32]) ); } diff --git a/crates/teepot/src/sgx/mod.rs b/crates/teepot/src/sgx/mod.rs index 8a9f85d..2b66c78 100644 --- a/crates/teepot/src/sgx/mod.rs +++ b/crates/teepot/src/sgx/mod.rs @@ -9,86 +9,11 @@ pub mod sign; use crate::quote::error::QuoteContext; pub use crate::quote::{error::QuoteError, Collateral}; -use bytemuck::{try_from_bytes, AnyBitPattern, PodCastError}; use std::{ fs::OpenOptions, io::{Read, Write}, - mem, }; -/// Structure of a quote -#[derive(Copy, Clone, Debug, AnyBitPattern)] -#[repr(C)] -pub struct Quote { - version: [u8; 2], - key_type: [u8; 2], - reserved: [u8; 4], - qe_svn: [u8; 2], - pce_svn: [u8; 2], - qe_vendor_id: [u8; 16], - /// The user data that was passed, when creating the enclave - pub user_data: [u8; 20], - /// The report body - pub report_body: ReportBody, -} - -impl Quote { - /// Creates a quote from a byte slice - pub fn try_from_bytes(bytes: &[u8]) -> Result<&Self, QuoteError> { - if bytes.len() < mem::size_of::() { - return Err(PodCastError::SizeMismatch.into()); - } - let this: &Self = try_from_bytes(&bytes[..mem::size_of::()])?; - if this.version() != 3 { - return Err(QuoteError::InvalidVersion); - } - Ok(this) - } - - /// Version of the `Quote` structure - pub fn version(&self) -> u16 { - u16::from_le_bytes(self.version) - } -} - -/// The enclave report body. -/// -/// For more information see the following documents: -/// -/// [Intel® Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: ECDSA Quote Library API](https://download.01.org/intel-sgx/dcap-1.0/docs/SGX_ECDSA_QuoteGenReference_DCAP_API_Linux_1.0.pdf) -/// -/// Table 5, A.4. Quote Format -/// -/// [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide](https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3d-part-4-manual.html) -/// -/// Table 38-21. Layout of REPORT -#[derive(Copy, Clone, Debug, AnyBitPattern)] -#[repr(C)] -pub struct ReportBody { - /// The security version number of the enclave. - pub cpusvn: [u8; 16], - /// The Misc section of the StateSaveArea of the enclave - pub miscselect: [u8; 4], - reserved1: [u8; 28], - /// The allowed Features of the enclave. - pub features: [u8; 8], - /// The allowed XCr0Flags of the enclave. - pub xfrm: [u8; 8], - /// The measurement of the enclave - pub mrenclave: [u8; 32], - reserved2: [u8; 32], - /// The hash of the public key, that signed the enclave - pub mrsigner: [u8; 32], - reserved3: [u8; 96], - /// ISV assigned Product ID of the enclave. - pub isv_prodid: [u8; 2], - /// ISV assigned SVN (security version number) of the enclave. - pub isv_svn: [u8; 2], - reserved4: [u8; 60], - /// The enclave report data, injected when requesting the quote, that is used for attestation. - pub reportdata: [u8; 64], -} - /// Get the attestation report in a Gramine enclave pub fn sgx_gramine_get_quote(report_data: &[u8; 64]) -> Result, QuoteError> { let mut file = OpenOptions::new() From 2bbfb2415c9e69c5ea2f912eb9290e499c988ba6 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 6 May 2025 11:22:33 +0200 Subject: [PATCH 088/114] feat(quote): add FMSPC and CPUSVN extraction support - Introduced new types `Fmspc`, `CpuSvn`, and `Svn` for SGX metadata. - Added methods to extract raw certificate chains and FMSPC from SGX quotes. - Created new test file for validating FMSPC extraction with example quotes. Signed-off-by: Harald Hoyer --- Cargo.lock | 1 + Cargo.toml | 1 + crates/teepot/Cargo.toml | 1 + crates/teepot/src/quote/mod.rs | 44 + crates/teepot/src/quote/utils.rs | 106 ++ crates/teepot/tests/sgx_quote_fmspc.rs | 1394 ++++++++++++++++++++++++ 6 files changed, 1547 insertions(+) create mode 100644 crates/teepot/src/quote/utils.rs create mode 100644 crates/teepot/tests/sgx_quote_fmspc.rs diff --git a/Cargo.lock b/Cargo.lock index 35f1966..6df8448 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4936,6 +4936,7 @@ name = "teepot" version = "0.3.0" dependencies = [ "anyhow", + "asn1_der", "async-trait", "base64", "bytemuck", diff --git a/Cargo.toml b/Cargo.toml index ae48f3c..e7304fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ homepage = "https://github.com/matter-labs/teepot" [workspace.dependencies] actix-web = { version = "4.5", features = ["rustls-0_23"] } anyhow = "1.0.82" +asn1_der = { version = "0.7", default-features = false, features = ["native_types"] } async-trait = "0.1.86" awc = { version = "3.5", features = ["rustls-0_23-webpki-roots"] } base64 = "0.22.0" diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index c848a92..357238c 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -21,6 +21,7 @@ bytes.workspace = true [dependencies] anyhow.workspace = true +asn1_der.workspace = true async-trait.workspace = true bytemuck.workspace = true clap.workspace = true diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 1d28371..b2ba8ea 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -16,6 +16,7 @@ pub mod tcblevel; path = "phala.rs" )] mod os; +mod utils; use crate::quote::{ error::{QuoteContext as _, QuoteError}, @@ -547,6 +548,23 @@ impl Decode for Quote { } } +/// FMSPC (Family-Model-Stepping-Platform-CustomSKU) is a 6-byte identifier +/// that uniquely identifies a platform's SGX TCB level. +/// It is extracted from the PCK certificate in the SGX quote and is used to +/// fetch TCB information from Intel's Provisioning Certification Service. +pub type Fmspc = [u8; 6]; + +/// CPU Security Version Number (CPUSVN) is a 16-byte value representing +/// the security version of the CPU microcode and firmware. +/// It is used in SGX attestation to determine the security patch level +/// of the platform. +pub type CpuSvn = [u8; 16]; + +/// Security Version Number (SVN) is a 16-bit value representing the +/// security version of a component (like PCE or QE). +/// Higher values indicate newer security patches have been applied. +pub type Svn = u16; + impl Quote { /// Parse a TEE quote from a byte slice. pub fn parse(quote: &[u8]) -> Result { @@ -555,6 +573,32 @@ impl Quote { Ok(quote) } + /// Get the raw certificate chain from the quote. + pub fn raw_cert_chain(&self) -> Result<&[u8], QuoteError> { + let cert_data = match &self.auth_data { + AuthData::V3(data) => &data.certification_data, + AuthData::V4(data) => &data.qe_report_data.certification_data, + }; + if cert_data.cert_type != 5 { + QuoteError::QuoteCertificationDataUnsupported(format!( + "Unsupported cert type: {}", + cert_data.cert_type + )); + } + Ok(&cert_data.body.data) + } + + /// Get the FMSPC from the quote. + pub fn fmspc(&self) -> Result { + let raw_cert_chain = self.raw_cert_chain()?; + let certs = utils::extract_certs(raw_cert_chain)?; + let cert = certs + .first() + .ok_or(QuoteError::Unexpected("Invalid certificate".into()))?; + let extension_section = utils::get_intel_extension(cert)?; + utils::get_fmspc(&extension_section) + } + /// Get the report data pub fn get_report_data(&self) -> &[u8] { match &self.report { diff --git a/crates/teepot/src/quote/utils.rs b/crates/teepot/src/quote/utils.rs new file mode 100644 index 0000000..23faa0e --- /dev/null +++ b/crates/teepot/src/quote/utils.rs @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024-2025 Matter Labs + +// Parts of it are Copyright (c) 2024 Phala Network +// and copied from https://github.com/Phala-Network/dcap-qvl + +use crate::quote::{error::QuoteError, Fmspc}; +use asn1_der::{ + typed::{DerDecodable, Sequence}, + DerObject, +}; +use x509_cert::certificate::CertificateInner; + +pub mod oids { + use const_oid::ObjectIdentifier as OID; + + const fn oid(s: &str) -> OID { + OID::new_unwrap(s) + } + + pub const SGX_EXTENSION: OID = oid("1.2.840.113741.1.13.1"); + pub const FMSPC: OID = oid("1.2.840.113741.1.13.1.4"); + + #[test] + fn const_oid_works() { + assert_eq!( + SGX_EXTENSION.as_bytes(), + oid("1.2.840.113741.1.13.1").as_bytes() + ); + } +} +pub fn get_intel_extension(cert: &CertificateInner) -> Result, QuoteError> { + let mut extension_iter = cert + .tbs_certificate + .extensions + .as_deref() + .unwrap_or(&[]) + .iter() + .filter(|e| e.extn_id == oids::SGX_EXTENSION) + .map(|e| e.extn_value.clone()); + + let extension = extension_iter + .next() + .ok_or_else(|| QuoteError::Unexpected("Intel extension not found".into()))?; + if extension_iter.next().is_some() { + //"There should only be one section containing Intel extensions" + return Err(QuoteError::Unexpected("Intel extension ambiguity".into())); + } + Ok(extension.into_bytes()) +} + +pub fn find_extension(path: &[&[u8]], raw: &[u8]) -> Result, QuoteError> { + let obj = DerObject::decode(raw) + .map_err(|_| QuoteError::Unexpected("Failed to decode DER object".into()))?; + let subobj = + get_obj(path, obj).map_err(|_| QuoteError::Unexpected("Failed to get subobject".into()))?; + Ok(subobj.value().to_vec()) +} + +fn get_obj<'a>(path: &[&[u8]], mut obj: DerObject<'a>) -> Result, QuoteError> { + for oid in path { + let seq = Sequence::load(obj) + .map_err(|_| QuoteError::Unexpected("Failed to load sequence".into()))?; + obj = sub_obj(oid, seq) + .map_err(|_| QuoteError::Unexpected("Failed to get subobject".into()))?; + } + Ok(obj) +} + +fn sub_obj<'a>(oid: &[u8], seq: Sequence<'a>) -> Result, QuoteError> { + for i in 0..seq.len() { + let entry = seq + .get(i) + .map_err(|_| QuoteError::Unexpected("Failed to get entry".into()))?; + let entry = Sequence::load(entry) + .map_err(|_| QuoteError::Unexpected("Failed to load sequence".into()))?; + let name = entry + .get(0) + .map_err(|_| QuoteError::Unexpected("Failed to get name".into()))?; + let value = entry + .get(1) + .map_err(|_| QuoteError::Unexpected("Failed to get value".into()))?; + if name.value() == oid { + return Ok(value); + } + } + Err(QuoteError::Unexpected("Oid is missing".into())) +} + +pub fn get_fmspc(extension_section: &[u8]) -> Result { + let data = find_extension(&[oids::FMSPC.as_bytes()], extension_section) + .map_err(|_| QuoteError::Unexpected("Failed to find Fmspc".into()))?; + if data.len() != 6 { + return Err(QuoteError::Unexpected("Fmspc length mismatch".into())); + } + + data.try_into() + .map_err(|_| QuoteError::Unexpected("Failed to decode Fmspc".into())) +} + +pub fn extract_certs(cert_chain: &[u8]) -> Result, QuoteError> { + let cert_chain = cert_chain.strip_suffix(&[0]).unwrap_or(cert_chain); + + CertificateInner::::load_pem_chain(cert_chain) + .map_err(|e| QuoteError::Unexpected(format!("Could not load a PEM chain: {}", e))) +} diff --git a/crates/teepot/tests/sgx_quote_fmspc.rs b/crates/teepot/tests/sgx_quote_fmspc.rs new file mode 100644 index 0000000..4924643 --- /dev/null +++ b/crates/teepot/tests/sgx_quote_fmspc.rs @@ -0,0 +1,1394 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024-2025 Matter Labs + +mod fmspc { + use anyhow::Result; + use teepot::quote::{Fmspc, Quote}; + + fn check_quote(raw_quote: &[u8], expected_result: &Fmspc) -> Result<()> { + let quote = Quote::parse(raw_quote).unwrap(); + let fmspc = quote.fmspc().unwrap(); + assert_eq!(&fmspc, expected_result); + Ok(()) + } + + #[test] + // alternative quote verification cannot cope with old collateral data format + fn sw_hardening() { + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, + 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, + 0xe2, 0x5d, 0x0f, 0x4e, 0x64, 0x9c, 0xd7, 0xd8, 0xc7, 0x88, 0xbf, 0xc2, 0x7b, 0xca, + 0x4f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x0f, 0x0e, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0xfb, 0xda, 0x9c, 0x05, 0x62, 0xfb, 0xab, 0x7d, 0x5c, 0x11, 0xeb, 0xcb, 0xd2, + 0x93, 0x32, 0x63, 0x97, 0xb4, 0x3e, 0x18, 0x20, 0x55, 0x0a, 0x0b, 0xb0, 0x92, 0x93, + 0x08, 0x8c, 0x8d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x80, 0x37, 0xd8, 0x87, 0x82, + 0xe0, 0x22, 0xe0, 0x19, 0xb3, 0x02, 0x07, 0x45, 0xb7, 0x8a, 0xa4, 0x0e, 0xd9, 0x5c, + 0x77, 0xda, 0x4b, 0xf7, 0xf3, 0x25, 0x3d, 0x3a, 0x44, 0xc4, 0xfd, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0xca, 0x10, + 0x00, 0x00, 0x83, 0x90, 0x4f, 0x15, 0x14, 0x92, 0xe7, 0xfb, 0xcf, 0xa9, 0xf6, 0x11, + 0xf9, 0xce, 0x13, 0xc1, 0xb9, 0x80, 0xbc, 0x39, 0x38, 0x15, 0x18, 0x1f, 0x4a, 0x75, + 0x18, 0x70, 0x69, 0xb9, 0x1c, 0x1c, 0x8c, 0x7a, 0x38, 0x9d, 0x93, 0x77, 0x32, 0x14, + 0x05, 0xd3, 0x97, 0x22, 0x4f, 0x7d, 0xa8, 0x83, 0x40, 0xcc, 0x4f, 0x7a, 0x20, 0x9d, + 0xfe, 0x9b, 0xfe, 0x9c, 0xf0, 0x29, 0xa9, 0xd9, 0x03, 0xb7, 0xcd, 0xd2, 0x06, 0xa2, + 0xec, 0x48, 0x1b, 0xd8, 0x66, 0x0b, 0xbb, 0xa3, 0xed, 0xcc, 0xa7, 0x75, 0x2c, 0x12, + 0x30, 0xd9, 0x23, 0xfd, 0x37, 0x7f, 0x38, 0x45, 0xa5, 0x87, 0x03, 0xbe, 0x5d, 0x02, + 0x03, 0xbe, 0x4a, 0x16, 0xd3, 0x8c, 0x88, 0xc5, 0xd4, 0x75, 0x51, 0x20, 0x5e, 0xbd, + 0xc5, 0xfc, 0x41, 0x36, 0xc8, 0xe4, 0x80, 0x60, 0x3e, 0x0f, 0xbb, 0x36, 0x76, 0x07, + 0x34, 0x3e, 0xac, 0x85, 0x0b, 0x0b, 0x0f, 0x0e, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, + 0xa5, 0x0c, 0xe1, 0xc0, 0xce, 0xf0, 0x3c, 0xcf, 0x89, 0xe7, 0xb5, 0xb1, 0x6b, 0x0d, + 0x79, 0x78, 0xf5, 0xc2, 0xb1, 0xed, 0xcf, 0x77, 0x4d, 0x87, 0x70, 0x2e, 0x81, 0x54, + 0xd8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, + 0x14, 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7a, 0xce, 0x06, 0x57, 0x43, 0xb2, 0x7d, 0x7e, 0xf9, 0x2d, 0x74, 0xf6, + 0x68, 0x1e, 0x6b, 0x61, 0x34, 0x08, 0xfc, 0xe1, 0x9b, 0xcf, 0x73, 0xda, 0x46, 0xab, + 0xaa, 0xe8, 0xb3, 0x99, 0xd9, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x6a, 0x09, 0x0d, + 0xd1, 0x55, 0xb5, 0x8c, 0x29, 0xd8, 0x73, 0x2d, 0x82, 0xf2, 0x76, 0x0b, 0xad, 0x26, + 0x5e, 0xa5, 0x4b, 0x95, 0x18, 0x4a, 0xf5, 0x6d, 0xa5, 0xd4, 0xe1, 0x34, 0x78, 0x11, + 0xcc, 0x78, 0x7c, 0x40, 0xe2, 0xa0, 0xb1, 0x5a, 0x79, 0x88, 0x1b, 0x4f, 0xa1, 0xf4, + 0x32, 0x5c, 0x74, 0x16, 0xf6, 0x9c, 0xfe, 0x56, 0xd5, 0x47, 0x58, 0x93, 0x7a, 0x70, + 0x49, 0xf5, 0xa6, 0x9b, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x05, 0x00, 0x62, 0x0e, + 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x38, 0x6a, 0x43, 0x43, 0x42, 0x4a, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x4a, 0x66, 0x43, 0x6a, 0x2b, 0x35, + 0x73, 0x48, 0x74, 0x48, 0x47, 0x68, 0x55, 0x78, 0x45, 0x36, 0x45, 0x4d, 0x71, 0x79, + 0x6e, 0x34, 0x73, 0x43, 0x6c, 0x4a, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, + 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x63, 0x44, 0x45, + 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x5a, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, + 0x44, 0x53, 0x79, 0x42, 0x51, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, + 0x53, 0x42, 0x44, 0x51, 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x67, 0x77, 0x52, 0x0a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, + 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, + 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, + 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, + 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, + 0x0a, 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x6a, 0x4d, 0x77, 0x4e, 0x44, 0x45, 0x7a, 0x4d, 0x54, 0x63, 0x7a, 0x4e, + 0x7a, 0x41, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x41, 0x77, 0x4e, 0x44, 0x45, + 0x7a, 0x4d, 0x54, 0x63, 0x7a, 0x4e, 0x7a, 0x41, 0x33, 0x0a, 0x57, 0x6a, 0x42, 0x77, + 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, + 0x6c, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x54, 0x52, 0x31, 0x67, 0x67, + 0x55, 0x45, 0x4e, 0x4c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, + 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, + 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, + 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, + 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, + 0x41, 0x30, 0x49, 0x41, 0x42, 0x47, 0x5a, 0x4c, 0x0a, 0x48, 0x38, 0x70, 0x47, 0x4f, + 0x5a, 0x69, 0x7a, 0x38, 0x6a, 0x4e, 0x34, 0x37, 0x4e, 0x2b, 0x50, 0x59, 0x6b, 0x58, + 0x65, 0x42, 0x31, 0x57, 0x79, 0x6e, 0x53, 0x4a, 0x34, 0x48, 0x2f, 0x53, 0x49, 0x61, + 0x30, 0x30, 0x47, 0x6a, 0x57, 0x5a, 0x78, 0x4b, 0x55, 0x62, 0x44, 0x67, 0x32, 0x58, + 0x4d, 0x78, 0x47, 0x45, 0x64, 0x4d, 0x74, 0x4c, 0x47, 0x7a, 0x79, 0x79, 0x4c, 0x50, + 0x35, 0x63, 0x70, 0x0a, 0x7a, 0x30, 0x62, 0x4d, 0x32, 0x6f, 0x58, 0x32, 0x57, 0x2b, + 0x6a, 0x4d, 0x51, 0x39, 0x5a, 0x2f, 0x4a, 0x36, 0x79, 0x6a, 0x67, 0x67, 0x4d, 0x4f, + 0x4d, 0x49, 0x49, 0x44, 0x43, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, + 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x56, 0x62, 0x31, 0x33, 0x4e, + 0x76, 0x52, 0x76, 0x68, 0x36, 0x55, 0x42, 0x4a, 0x79, 0x64, 0x54, 0x30, 0x0a, 0x4d, + 0x38, 0x34, 0x42, 0x56, 0x77, 0x76, 0x65, 0x56, 0x44, 0x42, 0x72, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x52, 0x38, 0x45, 0x5a, 0x44, 0x42, 0x69, 0x4d, 0x47, 0x43, 0x67, 0x58, + 0x71, 0x42, 0x63, 0x68, 0x6c, 0x70, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, + 0x76, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, + 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4c, 0x33, 0x4e, 0x6e, 0x65, 0x43, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4c, 0x33, 0x59, 0x7a, + 0x4c, 0x33, 0x42, 0x6a, 0x61, 0x32, 0x4e, 0x79, 0x62, 0x44, 0x39, 0x6a, 0x59, 0x54, + 0x31, 0x77, 0x0a, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, 0x53, 0x5a, + 0x6c, 0x62, 0x6d, 0x4e, 0x76, 0x5a, 0x47, 0x6c, 0x75, 0x5a, 0x7a, 0x31, 0x6b, 0x5a, + 0x58, 0x49, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x4b, 0x47, 0x44, 0x38, 0x50, 0x75, 0x50, 0x42, 0x63, 0x63, 0x54, 0x43, + 0x64, 0x76, 0x6e, 0x41, 0x75, 0x58, 0x46, 0x49, 0x56, 0x66, 0x36, 0x0a, 0x76, 0x49, + 0x6b, 0x48, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x47, 0x77, 0x44, 0x41, 0x4d, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, 0x41, 0x41, + 0x4d, 0x49, 0x49, 0x43, 0x4f, 0x77, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x0a, 0x42, 0x49, 0x49, 0x43, 0x4c, 0x44, 0x43, + 0x43, 0x41, 0x69, 0x67, 0x77, 0x48, 0x67, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x51, 0x51, 0x51, 0x55, 0x59, 0x50, + 0x38, 0x65, 0x34, 0x73, 0x4c, 0x7a, 0x66, 0x73, 0x45, 0x34, 0x54, 0x64, 0x62, 0x6f, + 0x53, 0x79, 0x44, 0x52, 0x54, 0x43, 0x43, 0x41, 0x57, 0x55, 0x47, 0x43, 0x69, 0x71, + 0x47, 0x0a, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x77, + 0x67, 0x67, 0x46, 0x56, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x42, 0x41, 0x67, 0x45, 0x4c, + 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, + 0x45, 0x4e, 0x41, 0x51, 0x49, 0x43, 0x41, 0x67, 0x45, 0x4c, 0x0a, 0x4d, 0x42, 0x41, + 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, + 0x51, 0x49, 0x44, 0x41, 0x67, 0x45, 0x44, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x45, 0x41, + 0x67, 0x45, 0x44, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x34, 0x54, 0x51, 0x45, 0x4e, 0x0a, 0x41, 0x51, 0x49, 0x46, 0x41, 0x67, 0x49, 0x41, + 0x2f, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, + 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x42, 0x67, 0x49, 0x43, 0x41, 0x50, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, 0x45, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x67, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6b, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x30, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0a, 0x45, 0x41, 0x73, 0x4c, 0x41, + 0x77, 0x50, 0x2f, 0x2f, 0x77, 0x45, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x47, 0x42, 0x71, 0x41, 0x41, + 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x48, 0x67, + 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, + 0x42, 0x67, 0x51, 0x51, 0x55, 0x48, 0x50, 0x72, 0x61, 0x78, 0x7a, 0x61, 0x0a, 0x57, + 0x6e, 0x42, 0x4d, 0x69, 0x67, 0x2f, 0x42, 0x49, 0x75, 0x44, 0x66, 0x75, 0x6a, 0x42, + 0x45, 0x42, 0x67, 0x6f, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, + 0x51, 0x45, 0x48, 0x4d, 0x44, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x45, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x49, 0x42, 0x41, 0x66, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x42, 0x77, 0x4d, 0x42, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x41, + 0x41, 0x77, 0x0a, 0x52, 0x51, 0x49, 0x67, 0x52, 0x35, 0x4e, 0x4e, 0x76, 0x6d, 0x77, + 0x73, 0x50, 0x61, 0x77, 0x78, 0x48, 0x4b, 0x61, 0x76, 0x5a, 0x74, 0x33, 0x59, 0x79, + 0x6a, 0x69, 0x58, 0x4e, 0x76, 0x55, 0x7a, 0x79, 0x30, 0x58, 0x31, 0x4a, 0x70, 0x6d, + 0x45, 0x66, 0x77, 0x2b, 0x4c, 0x4a, 0x58, 0x30, 0x43, 0x49, 0x51, 0x44, 0x43, 0x67, + 0x74, 0x76, 0x2f, 0x74, 0x78, 0x42, 0x67, 0x74, 0x6c, 0x54, 0x6b, 0x0a, 0x70, 0x6e, + 0x45, 0x47, 0x73, 0x6c, 0x51, 0x6a, 0x51, 0x6c, 0x39, 0x51, 0x30, 0x46, 0x62, 0x35, + 0x79, 0x73, 0x2f, 0x73, 0x42, 0x51, 0x4e, 0x42, 0x31, 0x75, 0x65, 0x68, 0x75, 0x67, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4a, 0x56, 0x76, 0x58, 0x63, 0x32, + 0x39, 0x47, 0x2b, 0x48, 0x70, 0x51, 0x45, 0x6e, 0x4a, 0x31, 0x50, 0x51, 0x7a, 0x7a, + 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, 0x55, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, 0x67, 0x78, + 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x55, + 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, + 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, + 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x0a, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, + 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x7a, + 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, + 0x4d, 0x48, 0x41, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x47, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, + 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, 0x64, + 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, + 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, + 0x47, 0x56, 0x73, 0x0a, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, + 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x0a, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4e, 0x53, 0x42, 0x2f, 0x37, + 0x74, 0x32, 0x31, 0x6c, 0x58, 0x53, 0x4f, 0x0a, 0x32, 0x43, 0x75, 0x7a, 0x70, 0x78, + 0x77, 0x37, 0x34, 0x65, 0x4a, 0x42, 0x37, 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, + 0x35, 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, 0x54, 0x4c, 0x71, 0x36, 0x68, + 0x4b, 0x6b, 0x36, 0x7a, 0x2b, 0x55, 0x69, 0x52, 0x5a, 0x43, 0x6e, 0x71, 0x52, 0x37, + 0x70, 0x73, 0x4f, 0x76, 0x67, 0x71, 0x46, 0x65, 0x53, 0x78, 0x6c, 0x6d, 0x54, 0x6c, + 0x4a, 0x6c, 0x0a, 0x65, 0x54, 0x6d, 0x69, 0x32, 0x57, 0x59, 0x7a, 0x33, 0x71, 0x4f, + 0x42, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, + 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, + 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x4d, 0x45, 0x65, 0x67, + 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, + 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, + 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, + 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, + 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, + 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6c, 0x57, 0x39, + 0x64, 0x0a, 0x7a, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, 0x63, 0x6e, 0x55, + 0x39, 0x44, 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x0a, 0x41, 0x66, 0x38, + 0x43, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x52, 0x77, 0x41, 0x77, 0x52, 0x41, 0x49, + 0x67, 0x58, 0x73, 0x56, 0x6b, 0x69, 0x30, 0x77, 0x2b, 0x69, 0x36, 0x56, 0x59, 0x47, + 0x57, 0x33, 0x55, 0x46, 0x2f, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, 0x30, 0x59, 0x4a, + 0x44, 0x6a, 0x31, 0x55, 0x65, 0x0a, 0x6e, 0x41, 0x2b, 0x54, 0x6a, 0x44, 0x31, 0x61, + 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, 0x31, 0x53, 0x41, 0x6d, 0x44, 0x35, + 0x78, 0x6b, 0x66, 0x54, 0x56, 0x70, 0x76, 0x6f, 0x34, 0x55, 0x6f, 0x79, 0x69, 0x53, + 0x59, 0x78, 0x72, 0x44, 0x57, 0x4c, 0x6d, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, 0x4e, + 0x4b, 0x79, 0x66, 0x50, 0x4e, 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, + 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, + 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, + 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, + 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, + 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, + 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, + 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, + 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, + 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, + 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, + 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, + 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, + 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, + 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, + 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, + 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, + 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, + 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, + 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, + 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, + 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, + 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, + 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, + 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, + 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, + 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, + 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, + 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, + 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, + 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, + 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, + 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, + 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, + 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, + 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, + 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, + 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, + 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, + 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, + 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, + 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, + 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, + 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x00, + ]; + + check_quote("e, &[0, 96, 106, 0, 0, 0]).unwrap(); + } + + #[test] + // alternative quote verification cannot cope with old collateral data format + fn out_of_date() { + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, + 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, + 0x46, 0x72, 0x07, 0x77, 0x7b, 0x2a, 0x56, 0xdf, 0xa2, 0xb1, 0x0e, 0xdd, 0x20, 0x16, + 0x0d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb1, 0xab, 0x35, 0x6e, 0xa0, 0x6e, 0x53, 0x25, 0xae, 0x16, 0x7d, 0x29, 0x0b, 0x3a, + 0x66, 0xb6, 0x1b, 0x89, 0x79, 0xd1, 0x2e, 0x6b, 0xbd, 0x5a, 0x97, 0xf3, 0x85, 0x72, + 0xc0, 0x32, 0x38, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x80, 0x37, 0xd8, 0x87, 0x82, + 0xe0, 0x22, 0xe0, 0x19, 0xb3, 0x02, 0x07, 0x45, 0xb7, 0x8a, 0xa4, 0x0e, 0xd9, 0x5c, + 0x77, 0xda, 0x4b, 0xf7, 0xf3, 0x25, 0x3d, 0x3a, 0x44, 0xc4, 0xfd, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x44, 0x10, + 0x00, 0x00, 0xb6, 0xdc, 0x93, 0xed, 0xc9, 0x25, 0x9d, 0x21, 0x6b, 0x17, 0xe4, 0xfa, + 0x00, 0x68, 0x21, 0x80, 0x5a, 0x8e, 0xbd, 0x81, 0x9a, 0x39, 0xc5, 0xb0, 0xb1, 0xbd, + 0x0b, 0xfc, 0x4b, 0x4b, 0xe3, 0x5c, 0x7a, 0x44, 0x46, 0xe1, 0x5a, 0xc6, 0xb1, 0x2e, + 0x8c, 0xee, 0x58, 0xce, 0x09, 0x3c, 0xed, 0xe6, 0xe5, 0xdc, 0x2c, 0xbe, 0xef, 0xbe, + 0xee, 0x21, 0x96, 0xd6, 0xa3, 0x6e, 0x4f, 0x7c, 0xc8, 0x21, 0xdc, 0x8c, 0x78, 0xda, + 0x8c, 0x50, 0xe0, 0xb3, 0x86, 0xa1, 0x4d, 0x55, 0x96, 0x93, 0xb2, 0xc7, 0xf7, 0x97, + 0xe9, 0x75, 0x5f, 0xc7, 0x22, 0xdd, 0x23, 0xe7, 0xab, 0x8c, 0x97, 0xe9, 0xe9, 0x1d, + 0xa5, 0x1a, 0x02, 0xe8, 0x23, 0xf7, 0xbe, 0x88, 0xa0, 0x8b, 0x1a, 0x6b, 0xdc, 0x58, + 0x44, 0xa0, 0xaf, 0x68, 0xdc, 0x16, 0xb0, 0x8c, 0xe5, 0x3a, 0x53, 0xb2, 0xba, 0xf1, + 0x36, 0xd1, 0x4f, 0x7d, 0x0b, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, + 0xa5, 0x0c, 0xe1, 0xc0, 0xce, 0xf0, 0x3c, 0xcf, 0x89, 0xe7, 0xb5, 0xb1, 0x6b, 0x0d, + 0x79, 0x78, 0xf5, 0xc2, 0xb1, 0xed, 0xcf, 0x77, 0x4d, 0x87, 0x70, 0x2e, 0x81, 0x54, + 0xd8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, + 0x14, 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4b, 0xba, 0x65, 0x76, 0x56, 0xb9, 0xb1, 0x19, 0x79, 0xbd, 0x5c, 0x8e, + 0xf7, 0x68, 0x82, 0xf7, 0x54, 0x82, 0x12, 0xf6, 0x85, 0xa2, 0x37, 0x65, 0x04, 0x3f, + 0x46, 0x54, 0x3e, 0x64, 0x18, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xd6, 0xbf, 0x3d, + 0x17, 0x99, 0x41, 0xbb, 0xf2, 0xd1, 0x94, 0xd7, 0xce, 0x30, 0xa0, 0xaa, 0xf9, 0x4e, + 0x8f, 0xe3, 0x46, 0xb6, 0xd8, 0x07, 0x7e, 0x6a, 0x06, 0xcb, 0x80, 0x15, 0x3f, 0xd1, + 0x00, 0xcc, 0x6c, 0x46, 0xd2, 0xd0, 0x2c, 0x02, 0x8d, 0xd9, 0x2c, 0x7d, 0x95, 0xff, + 0x13, 0x10, 0xed, 0xf8, 0x69, 0x00, 0xc8, 0x9c, 0x67, 0x68, 0x59, 0xbe, 0xc6, 0xfa, + 0x1e, 0x79, 0x74, 0x50, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x05, 0x00, 0xdc, 0x0d, + 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x6a, 0x44, 0x43, 0x43, 0x42, 0x44, 0x4b, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x57, 0x74, 0x46, 0x4d, 0x63, 0x4b, + 0x63, 0x64, 0x75, 0x30, 0x43, 0x37, 0x62, 0x39, 0x30, 0x65, 0x38, 0x32, 0x67, 0x46, + 0x2f, 0x4d, 0x36, 0x63, 0x56, 0x2b, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, + 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x63, 0x54, 0x45, + 0x6a, 0x4d, 0x43, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x61, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, + 0x44, 0x53, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x39, 0x6a, 0x5a, 0x58, 0x4e, 0x7a, 0x62, + 0x33, 0x49, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x0a, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, + 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, + 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, + 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, + 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0a, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x49, 0x7a, 0x4d, 0x44, 0x55, 0x77, 0x4f, 0x54, 0x45, 0x79, 0x4e, + 0x44, 0x59, 0x78, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x77, 0x4d, 0x44, 0x55, + 0x77, 0x4f, 0x54, 0x45, 0x79, 0x4e, 0x44, 0x59, 0x78, 0x0a, 0x4e, 0x6c, 0x6f, 0x77, + 0x63, 0x44, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x5a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x42, 0x44, 0x53, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x67, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, + 0x57, 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, + 0x70, 0x62, 0x32, 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x63, 0x4d, 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, + 0x73, 0x59, 0x58, 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, + 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x77, + 0x57, 0x54, 0x41, 0x54, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, + 0x49, 0x42, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x4d, 0x42, + 0x42, 0x77, 0x4e, 0x43, 0x41, 0x41, 0x51, 0x57, 0x0a, 0x49, 0x41, 0x6e, 0x45, 0x63, + 0x72, 0x51, 0x43, 0x78, 0x51, 0x48, 0x41, 0x77, 0x6d, 0x66, 0x43, 0x2f, 0x6d, 0x53, + 0x5a, 0x37, 0x33, 0x59, 0x4d, 0x31, 0x39, 0x45, 0x76, 0x43, 0x30, 0x2b, 0x62, 0x75, + 0x51, 0x6c, 0x35, 0x6e, 0x65, 0x6a, 0x65, 0x64, 0x77, 0x36, 0x6c, 0x6d, 0x62, 0x5a, + 0x55, 0x31, 0x4e, 0x45, 0x39, 0x5a, 0x55, 0x52, 0x48, 0x4d, 0x31, 0x57, 0x44, 0x44, + 0x4b, 0x72, 0x4e, 0x0a, 0x6d, 0x62, 0x35, 0x53, 0x7a, 0x6c, 0x79, 0x33, 0x46, 0x66, + 0x57, 0x79, 0x4f, 0x4a, 0x59, 0x67, 0x4f, 0x6b, 0x4e, 0x49, 0x6f, 0x34, 0x49, 0x43, + 0x70, 0x7a, 0x43, 0x43, 0x41, 0x71, 0x4d, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x30, 0x4f, 0x69, 0x71, + 0x32, 0x6e, 0x58, 0x58, 0x2b, 0x53, 0x35, 0x4a, 0x46, 0x35, 0x67, 0x38, 0x0a, 0x65, + 0x78, 0x52, 0x6c, 0x30, 0x4e, 0x58, 0x79, 0x57, 0x55, 0x30, 0x77, 0x62, 0x41, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x47, 0x55, 0x77, 0x59, 0x7a, 0x42, 0x68, 0x6f, + 0x46, 0x2b, 0x67, 0x58, 0x59, 0x5a, 0x62, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, + 0x36, 0x4c, 0x79, 0x39, 0x68, 0x63, 0x47, 0x6b, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x52, 0x6c, 0x5a, 0x48, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, + 0x56, 0x7a, 0x4c, 0x6d, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x4c, 0x6d, 0x4e, 0x76, + 0x62, 0x53, 0x39, 0x7a, 0x5a, 0x33, 0x67, 0x76, 0x59, 0x32, 0x56, 0x79, 0x64, 0x47, + 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x39, 0x32, + 0x4d, 0x79, 0x39, 0x77, 0x59, 0x32, 0x74, 0x6a, 0x63, 0x6d, 0x77, 0x2f, 0x59, 0x32, + 0x45, 0x39, 0x0a, 0x63, 0x48, 0x4a, 0x76, 0x59, 0x32, 0x56, 0x7a, 0x63, 0x32, 0x39, + 0x79, 0x4a, 0x6d, 0x56, 0x75, 0x59, 0x32, 0x39, 0x6b, 0x61, 0x57, 0x35, 0x6e, 0x50, + 0x57, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, + 0x45, 0x46, 0x67, 0x51, 0x55, 0x77, 0x48, 0x49, 0x6e, 0x51, 0x41, 0x52, 0x6c, 0x67, + 0x30, 0x44, 0x4a, 0x51, 0x6c, 0x45, 0x46, 0x4b, 0x4d, 0x4e, 0x5a, 0x0a, 0x56, 0x53, + 0x4b, 0x62, 0x59, 0x42, 0x51, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x62, 0x41, 0x4d, 0x41, + 0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x43, + 0x4d, 0x41, 0x41, 0x77, 0x67, 0x67, 0x48, 0x54, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x0a, 0x44, 0x51, 0x45, 0x45, 0x67, 0x67, 0x48, + 0x45, 0x4d, 0x49, 0x49, 0x42, 0x77, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6f, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x42, 0x42, 0x42, 0x42, + 0x5a, 0x4c, 0x56, 0x4a, 0x69, 0x69, 0x5a, 0x4b, 0x39, 0x78, 0x4a, 0x33, 0x30, 0x41, + 0x33, 0x37, 0x6b, 0x72, 0x6b, 0x4a, 0x6b, 0x4d, 0x49, 0x49, 0x42, 0x59, 0x77, 0x59, + 0x4b, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, + 0x41, 0x6a, 0x43, 0x43, 0x41, 0x56, 0x4d, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x45, 0x43, + 0x41, 0x51, 0x6f, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x49, 0x43, 0x0a, 0x41, 0x51, 0x6f, + 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x41, 0x67, 0x4d, 0x43, 0x41, 0x51, 0x49, 0x77, 0x45, 0x41, 0x59, + 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x51, 0x43, 0x41, 0x51, 0x49, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x55, 0x43, + 0x41, 0x51, 0x49, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x59, 0x43, 0x41, 0x51, 0x45, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, 0x51, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x67, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6b, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x73, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0a, 0x45, 0x41, 0x6f, 0x4b, 0x41, + 0x67, 0x49, 0x43, 0x41, 0x51, 0x51, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x48, 0x42, 0x75, 0x52, 0x77, + 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, 0x4b, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, + 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, + 0x53, 0x41, 0x41, 0x77, 0x52, 0x51, 0x49, 0x67, 0x4b, 0x64, 0x36, 0x2b, 0x0a, 0x58, + 0x62, 0x4e, 0x42, 0x64, 0x66, 0x49, 0x73, 0x4f, 0x30, 0x4c, 0x56, 0x48, 0x45, 0x49, + 0x50, 0x75, 0x39, 0x49, 0x66, 0x4a, 0x52, 0x7a, 0x39, 0x70, 0x4f, 0x58, 0x73, 0x4f, + 0x74, 0x68, 0x78, 0x56, 0x4d, 0x59, 0x72, 0x58, 0x48, 0x49, 0x43, 0x49, 0x51, 0x44, + 0x5a, 0x71, 0x79, 0x6c, 0x61, 0x6f, 0x52, 0x36, 0x77, 0x5a, 0x76, 0x54, 0x48, 0x49, + 0x33, 0x51, 0x55, 0x59, 0x55, 0x7a, 0x6a, 0x0a, 0x77, 0x67, 0x62, 0x6b, 0x65, 0x35, + 0x77, 0x52, 0x48, 0x4c, 0x74, 0x6c, 0x31, 0x39, 0x34, 0x79, 0x53, 0x5a, 0x75, 0x4a, + 0x55, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6d, 0x44, 0x43, 0x43, 0x41, 0x6a, 0x36, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4e, 0x44, 0x6f, 0x71, + 0x74, 0x70, 0x31, 0x31, 0x2f, 0x6b, 0x75, 0x53, 0x52, 0x65, 0x59, 0x50, 0x48, 0x73, + 0x55, 0x5a, 0x64, 0x44, 0x56, 0x38, 0x6c, 0x6c, 0x4e, 0x4d, 0x41, 0x6f, 0x47, 0x43, + 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, + 0x67, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, + 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, + 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, + 0x52, 0x6c, 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, + 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, + 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, + 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, + 0x55, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, + 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, + 0x4d, 0x7a, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, + 0x42, 0x61, 0x4d, 0x48, 0x45, 0x78, 0x49, 0x7a, 0x41, 0x68, 0x0a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x47, 0x6b, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, + 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x48, 0x4a, + 0x76, 0x59, 0x32, 0x56, 0x7a, 0x63, 0x32, 0x39, 0x79, 0x49, 0x45, 0x4e, 0x42, 0x4d, + 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, + 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x0a, 0x62, 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, + 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, + 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, + 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, + 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, + 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, 0x41, 0x30, 0x49, 0x41, 0x42, 0x4c, 0x39, + 0x71, 0x2b, 0x4e, 0x4d, 0x70, 0x32, 0x49, 0x4f, 0x67, 0x0a, 0x74, 0x64, 0x6c, 0x31, + 0x62, 0x6b, 0x2f, 0x75, 0x57, 0x5a, 0x35, 0x2b, 0x54, 0x47, 0x51, 0x6d, 0x38, 0x61, + 0x43, 0x69, 0x38, 0x7a, 0x37, 0x38, 0x66, 0x73, 0x2b, 0x66, 0x4b, 0x43, 0x51, 0x33, + 0x64, 0x2b, 0x75, 0x44, 0x7a, 0x58, 0x6e, 0x56, 0x54, 0x41, 0x54, 0x32, 0x5a, 0x68, + 0x44, 0x43, 0x69, 0x66, 0x79, 0x49, 0x75, 0x4a, 0x77, 0x76, 0x4e, 0x33, 0x77, 0x4e, + 0x42, 0x70, 0x39, 0x69, 0x0a, 0x48, 0x42, 0x53, 0x53, 0x4d, 0x4a, 0x4d, 0x4a, 0x72, + 0x42, 0x4f, 0x6a, 0x67, 0x62, 0x73, 0x77, 0x67, 0x62, 0x67, 0x77, 0x48, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x49, + 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, + 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x0a, + 0x55, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x45, 0x73, 0x77, 0x53, 0x54, + 0x42, 0x48, 0x6f, 0x45, 0x57, 0x67, 0x51, 0x34, 0x5a, 0x42, 0x61, 0x48, 0x52, 0x30, + 0x63, 0x48, 0x4d, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x58, 0x4d, 0x75, 0x64, 0x48, 0x4a, 0x31, + 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x48, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x70, 0x59, + 0x32, 0x56, 0x7a, 0x4c, 0x6d, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x4c, 0x6d, 0x4e, + 0x76, 0x62, 0x53, 0x39, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x46, 0x4e, 0x48, 0x57, + 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x53, 0x35, 0x6b, 0x5a, 0x58, 0x49, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, + 0x4e, 0x44, 0x6f, 0x0a, 0x71, 0x74, 0x70, 0x31, 0x31, 0x2f, 0x6b, 0x75, 0x53, 0x52, + 0x65, 0x59, 0x50, 0x48, 0x73, 0x55, 0x5a, 0x64, 0x44, 0x56, 0x38, 0x6c, 0x6c, 0x4e, + 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, + 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x43, 0x44, 0x41, 0x47, 0x0a, 0x41, + 0x51, 0x48, 0x2f, 0x41, 0x67, 0x45, 0x41, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x30, 0x67, 0x41, 0x4d, + 0x45, 0x55, 0x43, 0x49, 0x51, 0x43, 0x4a, 0x67, 0x54, 0x62, 0x74, 0x56, 0x71, 0x4f, + 0x79, 0x5a, 0x31, 0x6d, 0x33, 0x6a, 0x71, 0x69, 0x41, 0x58, 0x4d, 0x36, 0x51, 0x59, + 0x61, 0x36, 0x72, 0x35, 0x73, 0x57, 0x53, 0x0a, 0x34, 0x79, 0x2f, 0x47, 0x37, 0x79, + 0x38, 0x75, 0x49, 0x4a, 0x47, 0x78, 0x64, 0x77, 0x49, 0x67, 0x52, 0x71, 0x50, 0x76, + 0x42, 0x53, 0x4b, 0x7a, 0x7a, 0x51, 0x61, 0x67, 0x42, 0x4c, 0x51, 0x71, 0x35, 0x73, + 0x35, 0x41, 0x37, 0x30, 0x70, 0x64, 0x6f, 0x69, 0x61, 0x52, 0x4a, 0x38, 0x7a, 0x2f, + 0x30, 0x75, 0x44, 0x7a, 0x34, 0x4e, 0x67, 0x56, 0x39, 0x31, 0x6b, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, + 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, + 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, + 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, + 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, + 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, + 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, + 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, + 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, + 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, + 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, + 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, + 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, + 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, + 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, + 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, + 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, + 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, + 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, + 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, + 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, + 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, + 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, + 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, + 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, + 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, + 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, + 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, + 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, + 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, + 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, + 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, + 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, + 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, + 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, + 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, + 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, + 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, + 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, + 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, + 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, + 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, + 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, + 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, + 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, + 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, + ]; + + check_quote("e, &[0, 112, 110, 71, 0, 0]).unwrap(); + } + + #[test] + fn azure() { + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, + 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, + 0x1a, 0x24, 0xf2, 0x9c, 0x17, 0x78, 0x4f, 0x6a, 0x1b, 0xac, 0xff, 0x9b, 0x40, 0xc2, + 0x5f, 0x58, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x10, 0x0f, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0xd0, 0xe3, 0xeb, 0xfb, 0xb9, 0x8f, 0xd0, 0x61, 0xac, 0x2e, 0x9d, 0x21, 0x97, + 0x78, 0x0f, 0x81, 0x9c, 0x91, 0x72, 0xce, 0xef, 0xf4, 0xb3, 0x13, 0x0d, 0x72, 0x47, + 0xa6, 0x42, 0x1a, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x80, 0x37, 0xd8, 0x87, 0x82, + 0xe0, 0x22, 0xe0, 0x19, 0xb3, 0x02, 0x07, 0x45, 0xb7, 0x8a, 0xa4, 0x0e, 0xd9, 0x5c, + 0x77, 0xda, 0x4b, 0xf7, 0xf3, 0x25, 0x3d, 0x3a, 0x44, 0xc4, 0xfd, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0xca, 0x10, + 0x00, 0x00, 0x4d, 0xce, 0x39, 0x7e, 0x12, 0x4f, 0xd5, 0x09, 0xb6, 0x2b, 0x47, 0x97, + 0x79, 0xa8, 0x78, 0xae, 0xfe, 0x3a, 0x45, 0x42, 0x98, 0x74, 0x36, 0x06, 0xd6, 0x9e, + 0xf4, 0xce, 0x7c, 0x17, 0x67, 0xeb, 0x5a, 0xdf, 0x43, 0x3b, 0x11, 0x13, 0x40, 0x8a, + 0xa6, 0xaf, 0xb2, 0xa5, 0xd1, 0xa4, 0xd9, 0xaa, 0xa3, 0xd2, 0x40, 0x88, 0xc5, 0x50, + 0xa1, 0x4b, 0x04, 0xfc, 0x52, 0x05, 0x10, 0x2c, 0x97, 0xe7, 0x36, 0x40, 0xd7, 0x3d, + 0x6b, 0x83, 0xf0, 0xc4, 0xe1, 0x34, 0x2b, 0x4b, 0x36, 0x24, 0xba, 0x11, 0xf3, 0x51, + 0x92, 0x24, 0x59, 0x50, 0x5e, 0x54, 0xc0, 0x51, 0x59, 0xc9, 0x5d, 0x3a, 0xae, 0x00, + 0xa2, 0x3e, 0x46, 0xe0, 0x34, 0xfd, 0xee, 0x89, 0xb3, 0x85, 0xb7, 0x9f, 0xe2, 0x12, + 0xa5, 0x74, 0xea, 0x00, 0xbd, 0x8f, 0xae, 0xe2, 0xbb, 0x0c, 0x73, 0x22, 0x71, 0xc7, + 0x15, 0xad, 0x82, 0xea, 0x0b, 0x0b, 0x10, 0x0f, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, + 0xa5, 0x0c, 0xe1, 0xc0, 0xce, 0xf0, 0x3c, 0xcf, 0x89, 0xe7, 0xb5, 0xb1, 0x6b, 0x0d, + 0x79, 0x78, 0xf5, 0xc2, 0xb1, 0xed, 0xcf, 0x77, 0x4d, 0x87, 0x70, 0x2e, 0x81, 0x54, + 0xd8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, + 0x14, 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x71, 0x4e, 0x58, 0xe9, 0x48, 0x14, 0x59, 0x70, 0x69, 0x71, 0x4b, 0x5e, + 0x68, 0x78, 0xfb, 0x3a, 0xcf, 0x58, 0x32, 0xaa, 0xf9, 0x6d, 0x30, 0xa0, 0x45, 0x5d, + 0x78, 0xa4, 0xd9, 0xae, 0xd2, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x63, 0x7f, 0x0b, + 0x53, 0xdd, 0x15, 0xdd, 0x0d, 0xfd, 0x3e, 0x70, 0x16, 0x0a, 0x70, 0x62, 0x67, 0x25, + 0xd0, 0x3c, 0x9e, 0x1c, 0x4a, 0x63, 0x6e, 0x8d, 0xb4, 0xfd, 0x52, 0xe1, 0x41, 0xb9, + 0x74, 0xf7, 0x9b, 0x34, 0x65, 0xb4, 0x5f, 0xfd, 0x51, 0xbd, 0x4f, 0x92, 0xdf, 0x66, + 0xd3, 0x05, 0xf3, 0x88, 0x9f, 0xb5, 0x50, 0xb0, 0x97, 0x1e, 0xc8, 0xb9, 0x0e, 0x0c, + 0x08, 0x1d, 0x65, 0xa1, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x05, 0x00, 0x62, 0x0e, + 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x38, 0x6a, 0x43, 0x43, 0x42, 0x4a, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x57, 0x30, 0x71, 0x70, 0x4d, 0x78, + 0x45, 0x37, 0x52, 0x37, 0x69, 0x75, 0x30, 0x4b, 0x39, 0x38, 0x62, 0x55, 0x6a, 0x37, + 0x66, 0x4b, 0x73, 0x66, 0x75, 0x71, 0x63, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, + 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x63, 0x44, 0x45, + 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x5a, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, + 0x44, 0x53, 0x79, 0x42, 0x51, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, + 0x53, 0x42, 0x44, 0x51, 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x67, 0x77, 0x52, 0x0a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, + 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, + 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, + 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, + 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, + 0x0a, 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x6a, 0x4d, 0x77, 0x4e, 0x44, 0x41, 0x79, 0x4d, 0x54, 0x63, 0x79, 0x4d, + 0x54, 0x45, 0x35, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x41, 0x77, 0x4e, 0x44, 0x41, + 0x79, 0x4d, 0x54, 0x63, 0x79, 0x4d, 0x54, 0x45, 0x35, 0x0a, 0x57, 0x6a, 0x42, 0x77, + 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, + 0x6c, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x54, 0x52, 0x31, 0x67, 0x67, + 0x55, 0x45, 0x4e, 0x4c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, + 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, + 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, + 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, + 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, + 0x41, 0x30, 0x49, 0x41, 0x42, 0x45, 0x37, 0x45, 0x0a, 0x46, 0x50, 0x4d, 0x68, 0x61, + 0x55, 0x47, 0x45, 0x57, 0x6b, 0x68, 0x6b, 0x4f, 0x43, 0x78, 0x36, 0x51, 0x4c, 0x63, + 0x75, 0x71, 0x72, 0x56, 0x45, 0x32, 0x55, 0x6b, 0x62, 0x36, 0x31, 0x2f, 0x6d, 0x62, + 0x6d, 0x54, 0x66, 0x47, 0x33, 0x64, 0x69, 0x43, 0x62, 0x68, 0x56, 0x77, 0x4c, 0x38, + 0x49, 0x79, 0x4b, 0x73, 0x31, 0x33, 0x46, 0x75, 0x6b, 0x50, 0x52, 0x59, 0x58, 0x2b, + 0x64, 0x70, 0x79, 0x0a, 0x7a, 0x38, 0x6a, 0x7a, 0x76, 0x36, 0x58, 0x4a, 0x6e, 0x67, + 0x76, 0x47, 0x4c, 0x51, 0x41, 0x70, 0x37, 0x59, 0x65, 0x6a, 0x67, 0x67, 0x4d, 0x4f, + 0x4d, 0x49, 0x49, 0x44, 0x43, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, + 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x56, 0x62, 0x31, 0x33, 0x4e, + 0x76, 0x52, 0x76, 0x68, 0x36, 0x55, 0x42, 0x4a, 0x79, 0x64, 0x54, 0x30, 0x0a, 0x4d, + 0x38, 0x34, 0x42, 0x56, 0x77, 0x76, 0x65, 0x56, 0x44, 0x42, 0x72, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x52, 0x38, 0x45, 0x5a, 0x44, 0x42, 0x69, 0x4d, 0x47, 0x43, 0x67, 0x58, + 0x71, 0x42, 0x63, 0x68, 0x6c, 0x70, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, + 0x76, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, + 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4c, 0x33, 0x4e, 0x6e, 0x65, 0x43, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4c, 0x33, 0x59, 0x7a, + 0x4c, 0x33, 0x42, 0x6a, 0x61, 0x32, 0x4e, 0x79, 0x62, 0x44, 0x39, 0x6a, 0x59, 0x54, + 0x31, 0x77, 0x0a, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, 0x53, 0x5a, + 0x6c, 0x62, 0x6d, 0x4e, 0x76, 0x5a, 0x47, 0x6c, 0x75, 0x5a, 0x7a, 0x31, 0x6b, 0x5a, + 0x58, 0x49, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x41, 0x48, 0x70, 0x48, 0x38, 0x49, 0x61, 0x72, 0x51, 0x76, 0x79, 0x51, + 0x39, 0x67, 0x6d, 0x53, 0x70, 0x59, 0x35, 0x4d, 0x30, 0x49, 0x59, 0x0a, 0x4c, 0x53, + 0x34, 0x71, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x47, 0x77, 0x44, 0x41, 0x4d, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, 0x41, 0x41, + 0x4d, 0x49, 0x49, 0x43, 0x4f, 0x77, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x0a, 0x42, 0x49, 0x49, 0x43, 0x4c, 0x44, 0x43, + 0x43, 0x41, 0x69, 0x67, 0x77, 0x48, 0x67, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x51, 0x51, 0x51, 0x57, 0x6f, 0x72, + 0x76, 0x4e, 0x78, 0x69, 0x57, 0x62, 0x65, 0x49, 0x32, 0x70, 0x6e, 0x62, 0x53, 0x77, + 0x61, 0x6e, 0x6f, 0x78, 0x44, 0x43, 0x43, 0x41, 0x57, 0x55, 0x47, 0x43, 0x69, 0x71, + 0x47, 0x0a, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x77, + 0x67, 0x67, 0x46, 0x56, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x42, 0x41, 0x67, 0x45, 0x4c, + 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, + 0x45, 0x4e, 0x41, 0x51, 0x49, 0x43, 0x41, 0x67, 0x45, 0x4c, 0x0a, 0x4d, 0x42, 0x41, + 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, + 0x51, 0x49, 0x44, 0x41, 0x67, 0x45, 0x44, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x45, 0x41, + 0x67, 0x45, 0x44, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x34, 0x54, 0x51, 0x45, 0x4e, 0x0a, 0x41, 0x51, 0x49, 0x46, 0x41, 0x67, 0x49, 0x41, + 0x2f, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, + 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x42, 0x67, 0x49, 0x43, 0x41, 0x50, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, 0x45, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x67, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6b, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x30, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0a, 0x45, 0x41, 0x73, 0x4c, 0x41, + 0x77, 0x50, 0x2f, 0x2f, 0x77, 0x45, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x47, 0x42, 0x71, 0x41, 0x41, + 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x48, 0x67, + 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, + 0x42, 0x67, 0x51, 0x51, 0x70, 0x4a, 0x75, 0x73, 0x2f, 0x64, 0x35, 0x79, 0x0a, 0x7a, + 0x76, 0x39, 0x38, 0x45, 0x56, 0x63, 0x79, 0x75, 0x47, 0x47, 0x58, 0x2b, 0x54, 0x42, + 0x45, 0x42, 0x67, 0x6f, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, + 0x51, 0x45, 0x48, 0x4d, 0x44, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x45, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x49, 0x42, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x42, 0x77, 0x4d, 0x42, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x41, + 0x41, 0x77, 0x0a, 0x52, 0x51, 0x49, 0x68, 0x41, 0x50, 0x48, 0x62, 0x5a, 0x76, 0x49, + 0x6d, 0x50, 0x68, 0x74, 0x7a, 0x53, 0x59, 0x4f, 0x53, 0x4c, 0x47, 0x45, 0x47, 0x55, + 0x46, 0x51, 0x32, 0x68, 0x30, 0x58, 0x36, 0x70, 0x67, 0x65, 0x48, 0x77, 0x6f, 0x51, + 0x33, 0x6e, 0x6a, 0x4a, 0x37, 0x76, 0x48, 0x74, 0x57, 0x41, 0x69, 0x42, 0x43, 0x37, + 0x78, 0x75, 0x57, 0x65, 0x6e, 0x79, 0x4f, 0x46, 0x68, 0x6e, 0x6d, 0x0a, 0x71, 0x58, + 0x38, 0x6d, 0x63, 0x57, 0x76, 0x71, 0x34, 0x58, 0x32, 0x72, 0x6d, 0x64, 0x63, 0x4f, + 0x56, 0x63, 0x64, 0x53, 0x4c, 0x50, 0x5a, 0x4c, 0x4f, 0x4e, 0x4b, 0x41, 0x54, 0x77, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4a, 0x56, 0x76, 0x58, 0x63, 0x32, + 0x39, 0x47, 0x2b, 0x48, 0x70, 0x51, 0x45, 0x6e, 0x4a, 0x31, 0x50, 0x51, 0x7a, 0x7a, + 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, 0x55, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, 0x67, 0x78, + 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x55, + 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, + 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, + 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x0a, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, + 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x7a, + 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, + 0x4d, 0x48, 0x41, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x47, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, + 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, 0x64, + 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, + 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, + 0x47, 0x56, 0x73, 0x0a, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, + 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x0a, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4e, 0x53, 0x42, 0x2f, 0x37, + 0x74, 0x32, 0x31, 0x6c, 0x58, 0x53, 0x4f, 0x0a, 0x32, 0x43, 0x75, 0x7a, 0x70, 0x78, + 0x77, 0x37, 0x34, 0x65, 0x4a, 0x42, 0x37, 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, + 0x35, 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, 0x54, 0x4c, 0x71, 0x36, 0x68, + 0x4b, 0x6b, 0x36, 0x7a, 0x2b, 0x55, 0x69, 0x52, 0x5a, 0x43, 0x6e, 0x71, 0x52, 0x37, + 0x70, 0x73, 0x4f, 0x76, 0x67, 0x71, 0x46, 0x65, 0x53, 0x78, 0x6c, 0x6d, 0x54, 0x6c, + 0x4a, 0x6c, 0x0a, 0x65, 0x54, 0x6d, 0x69, 0x32, 0x57, 0x59, 0x7a, 0x33, 0x71, 0x4f, + 0x42, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, + 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, + 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x4d, 0x45, 0x65, 0x67, + 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, + 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, + 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, + 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, + 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, + 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6c, 0x57, 0x39, + 0x64, 0x0a, 0x7a, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, 0x63, 0x6e, 0x55, + 0x39, 0x44, 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x0a, 0x41, 0x66, 0x38, + 0x43, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x52, 0x77, 0x41, 0x77, 0x52, 0x41, 0x49, + 0x67, 0x58, 0x73, 0x56, 0x6b, 0x69, 0x30, 0x77, 0x2b, 0x69, 0x36, 0x56, 0x59, 0x47, + 0x57, 0x33, 0x55, 0x46, 0x2f, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, 0x30, 0x59, 0x4a, + 0x44, 0x6a, 0x31, 0x55, 0x65, 0x0a, 0x6e, 0x41, 0x2b, 0x54, 0x6a, 0x44, 0x31, 0x61, + 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, 0x31, 0x53, 0x41, 0x6d, 0x44, 0x35, + 0x78, 0x6b, 0x66, 0x54, 0x56, 0x70, 0x76, 0x6f, 0x34, 0x55, 0x6f, 0x79, 0x69, 0x53, + 0x59, 0x78, 0x72, 0x44, 0x57, 0x4c, 0x6d, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, 0x4e, + 0x4b, 0x79, 0x66, 0x50, 0x4e, 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, + 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, + 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, + 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, + 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, + 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, + 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, + 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, + 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, + 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, + 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, + 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, + 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, + 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, + 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, + 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, + 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, + 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, + 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, + 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, + 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, + 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, + 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, + 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, + 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, + 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, + 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, + 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, + 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, + 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, + 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, + 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, + 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, + 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, + 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, + 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, + 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, + 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, + 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, + 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, + 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, + 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, + 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, + 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x00, + ]; + check_quote("e, &[0, 96, 106, 0, 0, 0]).unwrap(); + } + + #[test] + fn tdx_1() { + let quote = [ + 4, 0, 2, 0, 129, 0, 0, 0, 0, 0, 0, 0, 147, 154, 114, 51, 247, 156, 76, 169, 148, 10, + 13, 179, 149, 127, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, + 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 112, 245, 193, 194, 193, 97, 11, 242, + 221, 173, 52, 138, 136, 235, 246, 165, 80, 37, 110, 148, 158, 82, 18, 44, 116, 61, 201, + 124, 222, 80, 204, 175, 173, 47, 197, 146, 125, 21, 15, 48, 127, 186, 59, 140, 162, 24, + 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 0, 0, 0, 0, 231, 0, 6, 0, 0, 0, 0, 0, 93, 86, 8, 14, 185, 239, 140, 224, + 187, 175, 107, 220, 218, 222, 235, 6, 231, 197, 176, 164, 209, 236, 22, 190, 134, 138, + 133, 169, 83, 186, 190, 12, 94, 84, 208, 28, 142, 5, 10, 84, 254, 28, 160, 120, 55, 37, + 48, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 66, 22, 233, 37, 247, 150, 244, 226, 130, 207, 166, 231, 45, 76, 119, 168, 5, 96, + 152, 122, 250, 41, 21, 90, 97, 253, 195, 58, 219, 128, 234, 176, 212, 17, 42, 189, 82, + 56, 126, 94, 37, 166, 13, 238, 251, 138, 82, 135, 117, 24, 106, 53, 86, 81, 215, 130, + 41, 226, 43, 72, 182, 103, 79, 0, 108, 212, 45, 139, 179, 112, 234, 46, 145, 248, 100, + 217, 148, 78, 7, 193, 13, 107, 37, 15, 181, 32, 72, 204, 252, 93, 110, 234, 107, 135, + 143, 164, 209, 17, 30, 60, 72, 25, 158, 84, 78, 146, 66, 178, 218, 227, 55, 134, 247, + 30, 251, 51, 88, 64, 181, 222, 201, 202, 60, 114, 188, 65, 7, 6, 17, 253, 30, 60, 185, + 130, 97, 201, 148, 120, 72, 216, 131, 106, 163, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 16, 0, 0, 173, 106, 32, 109, 219, 200, 128, + 152, 193, 7, 155, 122, 125, 105, 155, 215, 213, 138, 170, 109, 16, 164, 39, 124, 85, + 23, 81, 166, 93, 155, 21, 180, 75, 204, 181, 76, 63, 176, 74, 232, 187, 105, 12, 6, + 252, 251, 184, 232, 245, 64, 217, 15, 193, 251, 48, 39, 120, 210, 6, 165, 79, 192, 101, + 165, 146, 8, 244, 170, 53, 52, 105, 26, 27, 111, 7, 237, 192, 22, 93, 124, 74, 31, 173, + 205, 119, 80, 167, 54, 215, 90, 6, 0, 234, 108, 253, 234, 29, 165, 67, 157, 15, 111, + 174, 243, 248, 207, 172, 69, 217, 220, 251, 85, 85, 184, 153, 126, 192, 253, 143, 167, + 105, 23, 73, 81, 110, 247, 117, 96, 6, 0, 69, 16, 0, 0, 7, 7, 255, 27, 3, 255, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 229, + 163, 167, 181, 216, 48, 194, 149, 59, 152, 83, 76, 108, 89, 163, 163, 79, 220, 52, 233, + 51, 247, 245, 137, 143, 10, 133, 207, 8, 132, 107, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 158, 42, 124, + 111, 148, 143, 23, 71, 78, 52, 167, 252, 67, 237, 3, 15, 124, 21, 99, 241, 186, 189, + 223, 99, 64, 200, 46, 14, 84, 168, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, + 251, 252, 166, 90, 191, 174, 148, 208, 101, 246, 199, 76, 45, 11, 45, 3, 58, 105, 166, + 8, 54, 250, 244, 81, 54, 176, 166, 141, 248, 70, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 2, 162, 97, 38, 185, + 42, 4, 183, 177, 168, 67, 207, 162, 237, 225, 183, 89, 224, 19, 4, 86, 108, 202, 197, + 108, 151, 18, 255, 142, 246, 86, 143, 11, 27, 240, 45, 133, 132, 182, 25, 177, 123, + 186, 98, 132, 113, 180, 86, 63, 3, 10, 8, 152, 75, 152, 211, 9, 149, 235, 147, 51, 209, + 203, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 93, 14, 0, 0, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 69, 56, + 68, 67, 67, 66, 74, 97, 103, 65, 119, 73, 66, 65, 103, 73, 85, 89, 71, 99, 82, 76, 89, + 53, 43, 114, 99, 119, 67, 65, 88, 84, 72, 48, 71, 109, 83, 71, 98, 119, 115, 104, 113, + 119, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 99, + 68, 69, 105, 77, 67, 65, 71, 65, 49, 85, 69, 65, 119, 119, 90, 83, 87, 53, 48, 90, 87, + 119, 103, 85, 48, 100, 89, 73, 70, 66, 68, 83, 121, 66, 81, 98, 71, 70, 48, 90, 109, + 57, 121, 98, 83, 66, 68, 81, 84, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 67, 103, 119, + 82, 10, 83, 87, 53, 48, 90, 87, 119, 103, 81, 50, 57, 121, 99, 71, 57, 121, 89, 88, 82, + 112, 98, 50, 52, 120, 70, 68, 65, 83, 66, 103, 78, 86, 66, 65, 99, 77, 67, 49, 78, 104, + 98, 110, 82, 104, 73, 69, 78, 115, 89, 88, 74, 104, 77, 81, 115, 119, 67, 81, 89, 68, + 86, 81, 81, 73, 10, 68, 65, 74, 68, 81, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, + 66, 104, 77, 67, 86, 86, 77, 119, 72, 104, 99, 78, 77, 106, 81, 120, 77, 106, 65, 49, + 77, 68, 65, 120, 79, 68, 85, 122, 87, 104, 99, 78, 77, 122, 69, 120, 77, 106, 65, 49, + 77, 68, 65, 120, 79, 68, 85, 122, 10, 87, 106, 66, 119, 77, 83, 73, 119, 73, 65, 89, + 68, 86, 81, 81, 68, 68, 66, 108, 74, 98, 110, 82, 108, 98, 67, 66, 84, 82, 49, 103, + 103, 85, 69, 78, 76, 73, 69, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, + 108, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 10, 68, 66, 70, 74, 98, 110, 82, + 108, 98, 67, 66, 68, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, + 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, + 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 10, 66, 65, + 103, 77, 65, 107, 78, 66, 77, 81, 115, 119, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, + 74, 86, 85, 122, 66, 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, + 71, 67, 67, 113, 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 79, 122, 117, + 10, 122, 56, 66, 78, 78, 88, 71, 102, 48, 48, 85, 66, 100, 53, 52, 90, 97, 120, 85, + 113, 79, 110, 79, 81, 103, 53, 81, 109, 51, 54, 115, 105, 49, 74, 111, 112, 97, 110, + 88, 114, 80, 112, 117, 78, 86, 102, 73, 98, 50, 77, 114, 54, 104, 75, 68, 106, 107, 75, + 107, 100, 114, 82, 81, 103, 10, 55, 101, 117, 57, 84, 73, 76, 86, 57, 53, 82, 43, 55, + 80, 118, 90, 102, 120, 101, 106, 103, 103, 77, 77, 77, 73, 73, 68, 67, 68, 65, 102, 66, + 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 83, 86, 98, 49, 51, 78, 118, 82, + 118, 104, 54, 85, 66, 74, 121, 100, 84, 48, 10, 77, 56, 52, 66, 86, 119, 118, 101, 86, + 68, 66, 114, 66, 103, 78, 86, 72, 82, 56, 69, 90, 68, 66, 105, 77, 71, 67, 103, 88, + 113, 66, 99, 104, 108, 112, 111, 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 70, 119, + 97, 83, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 10, 100, 109, 108, + 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, 119, 117, 89, 50, 57, 116, 76, 51, 78, + 110, 101, 67, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 97, 87, 57, + 117, 76, 51, 89, 48, 76, 51, 66, 106, 97, 50, 78, 121, 98, 68, 57, 106, 89, 84, 49, + 119, 10, 98, 71, 70, 48, 90, 109, 57, 121, 98, 83, 90, 108, 98, 109, 78, 118, 90, 71, + 108, 117, 90, 122, 49, 107, 90, 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, + 89, 69, 70, 74, 97, 84, 121, 67, 67, 48, 49, 71, 76, 117, 52, 105, 65, 104, 100, 119, + 98, 111, 115, 84, 105, 112, 10, 75, 119, 90, 87, 77, 65, 52, 71, 65, 49, 85, 100, 68, + 119, 69, 66, 47, 119, 81, 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, + 82, 77, 66, 65, 102, 56, 69, 65, 106, 65, 65, 77, 73, 73, 67, 79, 81, 89, 74, 75, 111, + 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 10, 66, 73, 73, 67, 75, 106, 67, 67, 65, + 105, 89, 119, 72, 103, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, + 81, 81, 81, 78, 107, 122, 43, 57, 54, 111, 121, 99, 107, 71, 79, 47, 106, 70, 47, 56, + 72, 90, 56, 101, 84, 67, 67, 65, 87, 77, 71, 67, 105, 113, 71, 10, 83, 73, 98, 52, 84, + 81, 69, 78, 65, 81, 73, 119, 103, 103, 70, 84, 77, 66, 65, 71, 67, 121, 113, 71, 83, + 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 66, 65, 103, 69, 72, 77, 66, 65, 71, 67, 121, + 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 67, 65, 103, 69, 72, 10, 77, 66, + 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 68, 65, 103, 69, + 67, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 69, + 65, 103, 69, 67, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 10, + 65, 81, 73, 70, 65, 103, 69, 68, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, + 81, 69, 78, 65, 81, 73, 71, 65, 103, 69, 66, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, + 98, 52, 84, 81, 69, 78, 65, 81, 73, 72, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, + 71, 10, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 73, 65, 103, 69, 68, 77, 66, 65, + 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 74, 65, 103, 69, 65, + 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 75, 65, + 103, 69, 65, 10, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, + 81, 73, 76, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, + 69, 78, 65, 81, 73, 77, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, + 52, 84, 81, 69, 78, 10, 65, 81, 73, 78, 65, 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, + 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 79, 65, 103, 69, 65, 77, 66, 65, 71, + 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 80, 65, 103, 69, 65, 77, + 66, 65, 71, 67, 121, 113, 71, 10, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 81, 65, + 103, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, + 73, 82, 65, 103, 69, 76, 77, 66, 56, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, + 78, 65, 81, 73, 83, 66, 66, 65, 72, 10, 66, 119, 73, 67, 65, 119, 69, 65, 65, 119, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 77, 66, 65, 71, 67, 105, 113, 71, 83, 73, 98, 52, + 84, 81, 69, 78, 65, 81, 77, 69, 65, 103, 65, 65, 77, 66, 81, 71, 67, 105, 113, 71, 83, + 73, 98, 52, 84, 81, 69, 78, 65, 81, 81, 69, 10, 66, 103, 67, 65, 98, 119, 85, 65, 65, + 68, 65, 80, 66, 103, 111, 113, 104, 107, 105, 71, 43, 69, 48, 66, 68, 81, 69, 70, 67, + 103, 69, 66, 77, 66, 52, 71, 67, 105, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, + 89, 69, 69, 73, 89, 81, 78, 89, 69, 43, 108, 116, 89, 109, 10, 76, 85, 69, 101, 65, 74, + 83, 109, 67, 116, 65, 119, 82, 65, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, + 48, 66, 66, 122, 65, 50, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, + 78, 65, 81, 99, 66, 65, 81, 72, 47, 77, 66, 65, 71, 67, 121, 113, 71, 10, 83, 73, 98, + 52, 84, 81, 69, 78, 65, 81, 99, 67, 65, 81, 69, 65, 77, 66, 65, 71, 67, 121, 113, 71, + 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 99, 68, 65, 81, 72, 47, 77, 65, 111, 71, 67, + 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 65, 48, 103, 65, 77, 69, 85, 67, 10, 73, + 65, 74, 88, 103, 116, 73, 109, 88, 71, 51, 97, 104, 113, 81, 82, 122, 48, 90, 66, 43, + 66, 83, 107, 97, 70, 43, 88, 87, 110, 110, 119, 90, 49, 88, 102, 110, 106, 67, 79, 102, + 54, 115, 87, 65, 105, 69, 65, 115, 76, 57, 52, 110, 57, 53, 55, 86, 89, 65, 47, 118, + 109, 77, 119, 10, 103, 65, 56, 104, 78, 115, 112, 97, 66, 71, 80, 106, 99, 105, 50, 43, + 107, 104, 98, 120, 80, 112, 100, 43, 86, 100, 89, 61, 10, 45, 45, 45, 45, 45, 69, 78, + 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, + 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, + 45, 45, 10, 77, 73, 73, 67, 108, 106, 67, 67, 65, 106, 50, 103, 65, 119, 73, 66, 65, + 103, 73, 86, 65, 74, 86, 118, 88, 99, 50, 57, 71, 43, 72, 112, 81, 69, 110, 74, 49, 80, + 81, 122, 122, 103, 70, 88, 67, 57, 53, 85, 77, 65, 111, 71, 67, 67, 113, 71, 83, 77, + 52, 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, + 77, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 83, 98, 50, 57, + 48, 73, 69, 78, 66, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, + 98, 110, 82, 108, 98, 67, 66, 68, 10, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, + 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, + 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, + 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, + 81, 71, 69, 119, 74, 86, 85, 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, + 69, 120, 77, 68, 85, 119, 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, + 69, 120, 77, 68, 85, 119, 77, 84, 66, 97, 77, 72, 65, 120, 73, 106, 65, 103, 10, 66, + 103, 78, 86, 66, 65, 77, 77, 71, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, + 67, 66, 81, 81, 48, 115, 103, 85, 71, 120, 104, 100, 71, 90, 118, 99, 109, 48, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, + 71, 86, 115, 10, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, + 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, + 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, + 119, 67, 81, 48, 69, 120, 10, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 65, + 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, + 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 78, 83, + 66, 47, 55, 116, 50, 49, 108, 88, 83, 79, 10, 50, 67, 117, 122, 112, 120, 119, 55, 52, + 101, 74, 66, 55, 50, 69, 121, 68, 71, 103, 87, 53, 114, 88, 67, 116, 120, 50, 116, 86, + 84, 76, 113, 54, 104, 75, 107, 54, 122, 43, 85, 105, 82, 90, 67, 110, 113, 82, 55, 112, + 115, 79, 118, 103, 113, 70, 101, 83, 120, 108, 109, 84, 108, 74, 108, 10, 101, 84, 109, + 105, 50, 87, 89, 122, 51, 113, 79, 66, 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, + 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, + 105, 102, 79, 68, 116, 74, 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, + 10, 66, 103, 78, 86, 72, 82, 56, 69, 83, 122, 66, 74, 77, 69, 101, 103, 82, 97, 66, 68, + 104, 107, 70, 111, 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, + 112, 90, 109, 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, + 86, 107, 99, 50, 86, 121, 10, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, + 87, 119, 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, + 109, 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 108, 87, 57, 100, 10, 122, 98, 48, 98, 52, 101, 108, 65, + 83, 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 68, 103, 89, 68, 86, + 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, + 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 10, 65, 102, 56, 67, 65, 81, + 65, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 82, 119, + 65, 119, 82, 65, 73, 103, 88, 115, 86, 107, 105, 48, 119, 43, 105, 54, 86, 89, 71, 87, + 51, 85, 70, 47, 50, 50, 117, 97, 88, 101, 48, 89, 74, 68, 106, 49, 85, 101, 10, 110, + 65, 43, 84, 106, 68, 49, 97, 105, 53, 99, 67, 73, 67, 89, 98, 49, 83, 65, 109, 68, 53, + 120, 107, 102, 84, 86, 112, 118, 111, 52, 85, 111, 121, 105, 83, 89, 120, 114, 68, 87, + 76, 109, 85, 82, 52, 67, 73, 57, 78, 75, 121, 102, 80, 78, 43, 10, 45, 45, 45, 45, 45, + 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, + 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, + 45, 45, 45, 45, 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, + 66, 65, 103, 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, + 86, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, + 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, + 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, + 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, + 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, + 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, + 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, 66, + 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, + 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, 77, 84, 73, + 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, 97, 77, 66, 103, + 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, + 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, + 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, + 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, + 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, + 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, + 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, + 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, + 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, + 106, 47, 105, 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, + 82, 70, 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, + 106, 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, + 97, 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, + 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, + 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, + 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, + 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, + 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, 109, + 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, 116, 76, + 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, 69, 78, 66, 76, + 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, 70, 103, 81, 85, 73, + 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 10, 85, 114, 57, 81, + 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, + 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, + 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, + 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, + 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, + 117, 80, 82, 76, 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, + 84, 119, 103, 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, + 53, 111, 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, + 82, 81, 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, + 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + + check_quote("e, &[0, 128, 111, 5, 0, 0]).unwrap(); + } +} From 2a8614c08f265efc72f12e847d5a4f73dad91c2b Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Mon, 5 May 2025 14:27:18 +0200 Subject: [PATCH 089/114] feat: add platform-specific implementations for quote verification - Introduced conditional compilation for Intel SGX/TDX quote verification based on target OS and architecture. - Moved Intel-specific logic to a separate module and added a fallback for unsupported platforms. This is done, so we can pull in the `teepot` crate even on `linux-x86_64` without the Intel SGX SDK lib dependency. Signed-off-by: Harald Hoyer --- Cargo.lock | 2 +- .../Cargo.toml | 1 + .../src/empty.rs | 4 + .../src/intel.rs | 561 ++++++++++++++++++ .../src/lib.rs | 560 +---------------- crates/teepot/Cargo.toml | 9 +- crates/teepot/src/lib.rs | 1 + crates/teepot/src/quote/error.rs | 10 +- crates/teepot/src/quote/intel.rs | 2 +- crates/teepot/src/quote/mod.rs | 5 + crates/teepot/src/tdx/mod.rs | 2 +- crates/teepot/src/tdx/rtmr.rs | 5 +- crates/teepot/tests/sgx_quote_verification.rs | 1 + 13 files changed, 596 insertions(+), 567 deletions(-) create mode 100644 crates/teepot-tee-quote-verification-rs/src/empty.rs create mode 100644 crates/teepot-tee-quote-verification-rs/src/intel.rs diff --git a/Cargo.lock b/Cargo.lock index 6df8448..36007b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4968,7 +4968,6 @@ dependencies = [ "sha2", "sha3", "signature", - "tdx-attest-rs", "teepot-tee-quote-verification-rs", "testaso", "thiserror 2.0.11", @@ -5003,6 +5002,7 @@ version = "0.3.0" dependencies = [ "intel-tee-quote-verification-sys", "serde", + "tdx-attest-rs", ] [[package]] diff --git a/crates/teepot-tee-quote-verification-rs/Cargo.toml b/crates/teepot-tee-quote-verification-rs/Cargo.toml index b267be8..8c0b6f3 100644 --- a/crates/teepot-tee-quote-verification-rs/Cargo.toml +++ b/crates/teepot-tee-quote-verification-rs/Cargo.toml @@ -14,3 +14,4 @@ serde = { version = "1", features = ["derive", "rc"] } [target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] intel-tee-quote-verification-sys = { version = "0.2.1" } +tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } diff --git a/crates/teepot-tee-quote-verification-rs/src/empty.rs b/crates/teepot-tee-quote-verification-rs/src/empty.rs new file mode 100644 index 0000000..9753abc --- /dev/null +++ b/crates/teepot-tee-quote-verification-rs/src/empty.rs @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +pub const NOTHING_TO_SEE_HERE: u8 = 0; diff --git a/crates/teepot-tee-quote-verification-rs/src/intel.rs b/crates/teepot-tee-quote-verification-rs/src/intel.rs new file mode 100644 index 0000000..2ce66e3 --- /dev/null +++ b/crates/teepot-tee-quote-verification-rs/src/intel.rs @@ -0,0 +1,561 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2024-2025 Matter Labs + +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +//! Intel(R) Software Guard Extensions Data Center Attestation Primitives (Intel(R) SGX DCAP) +//! Rust wrapper for Quote Verification Library +//! ================================================ +//! +//! This is a safe wrapper for **sgx-dcap-quoteverify-sys**. + +pub mod tdx_attest_rs { + pub use tdx_attest_rs::*; +} + +use serde::{Deserialize, Serialize}; +use std::{marker::PhantomData, ops::Deref, slice}; + +use intel_tee_quote_verification_sys as qvl_sys; +pub use qvl_sys::{ + quote3_error_t, sgx_ql_qe_report_info_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, + sgx_ql_qve_collateral_t, sgx_ql_request_policy_t, sgx_qv_path_type_t, tdx_ql_qve_collateral_t, + tee_qv_free_collateral, tee_supp_data_descriptor_t, +}; + +/// When the Quoting Verification Library is linked to a process, it needs to know the proper enclave loading policy. +/// The library may be linked with a long lived process, such as a service, where it can load the enclaves and leave +/// them loaded (persistent). This better ensures that the enclaves will be available upon quote requests and not subject +/// to EPC limitations if loaded on demand. However, if the Quoting library is linked with an application process, there +/// may be many applications with the Quoting library and a better utilization of EPC is to load and unloaded the quoting +/// enclaves on demand (ephemeral). The library will be shipped with a default policy of loading enclaves and leaving +/// them loaded until the library is unloaded (PERSISTENT). If the policy is set to EPHEMERAL, then the QE and PCE will +/// be loaded and unloaded on-demand. If either enclave is already loaded when the policy is change to EPHEMERAL, the +/// enclaves will be unloaded before returning. +/// +/// # Param +/// - **policy**\ +/// Set the requested enclave loading policy to either *SGX_QL_PERSISTENT*, *SGX_QL_EPHEMERAL* or *SGX_QL_DEFAULT*. +/// +/// # Return +/// - ***SGX_QL_SUCCESS***\ +/// Successfully set the enclave loading policy for the quoting library's enclaves.\ +/// - ***SGX_QL_UNSUPPORTED_LOADING_POLICY***\ +/// The selected policy is not support by the quoting library.\ +/// - ***SGX_QL_ERROR_UNEXPECTED***\ +/// Unexpected internal error. +/// +/// # Examples +/// ``` +/// use teepot_tee_quote_verification_rs::*; +/// +/// let policy = sgx_ql_request_policy_t::SGX_QL_DEFAULT; +/// let ret = sgx_qv_set_enclave_load_policy(policy); +/// +/// assert_eq!(ret, quote3_error_t::SGX_QL_SUCCESS); +/// ``` +pub fn sgx_qv_set_enclave_load_policy(policy: sgx_ql_request_policy_t) -> quote3_error_t { + unsafe { qvl_sys::sgx_qv_set_enclave_load_policy(policy) } +} + +/// Get SGX supplemental data required size. +/// +/// # Return +/// Size of the supplemental data in bytes. +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_ERROR_QVL_QVE_MISMATCH* +/// - *SGX_QL_ENCLAVE_LOAD_ERROR* +/// +/// # Examples +/// ``` +/// use teepot_tee_quote_verification_rs::*; +/// +/// let data_size = sgx_qv_get_quote_supplemental_data_size().unwrap(); +/// +/// assert_eq!(data_size, std::mem::size_of::() as u32); +/// ``` +pub fn sgx_qv_get_quote_supplemental_data_size() -> Result { + let mut data_size = 0u32; + unsafe { + match qvl_sys::sgx_qv_get_quote_supplemental_data_size(&mut data_size) { + quote3_error_t::SGX_QL_SUCCESS => Ok(data_size), + error_code => Err(error_code), + } + } +} + +/// Perform SGX ECDSA quote verification. +/// +/// # Param +/// - **quote**\ +/// SGX Quote, presented as u8 vector. +/// - **quote_collateral**\ +/// Quote Certification Collateral provided by the caller. +/// - **expiration_check_date**\ +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// - **qve_report_info**\ +/// This parameter can be used in 2 ways.\ +/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ +/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. +/// - **supplemental_data_size**\ +/// Size of the supplemental data (in bytes). +/// - **supplemental_data**\ +/// The parameter is optional. If it is None, supplemental_data_size must be 0. +/// +/// # Return +/// Result type of (collateral_expiration_status, verification_result). +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* +/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* +/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn sgx_qv_verify_quote( + quote: &[u8], + quote_collateral: Option<&Collateral>, + expiration_check_date: i64, + qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, + supplemental_data_size: u32, + supplemental_data: Option<&mut sgx_ql_qv_supplemental_t>, +) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { + let mut collateral_expiration_status = 1u32; + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + + let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); + let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); + + let p_qve_report_info = match qve_report_info { + Some(p) => p, + None => std::ptr::null_mut(), + }; + let p_supplemental_data = match supplemental_data { + Some(p) => p as *mut sgx_ql_qv_supplemental_t as *mut u8, + None => std::ptr::null_mut(), + }; + + unsafe { + match qvl_sys::sgx_qv_verify_quote( + quote.as_ptr(), + quote.len() as u32, + p_quote_collateral, + expiration_check_date, + &mut collateral_expiration_status, + &mut quote_verification_result, + p_qve_report_info, + supplemental_data_size, + p_supplemental_data, + ) { + quote3_error_t::SGX_QL_SUCCESS => { + Ok((collateral_expiration_status, quote_verification_result)) + } + error_code => Err(error_code), + } + } +} + +/// Get TDX supplemental data required size. +/// +/// # Return +/// Size of the supplemental data in bytes. +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_ERROR_QVL_QVE_MISMATCH* +/// - *SGX_QL_ENCLAVE_LOAD_ERROR* +/// +/// # Examples +/// ``` +/// use teepot_tee_quote_verification_rs::*; +/// +/// let data_size = tdx_qv_get_quote_supplemental_data_size().unwrap(); +/// +/// assert_eq!(data_size, std::mem::size_of::() as u32); +/// ``` +pub fn tdx_qv_get_quote_supplemental_data_size() -> Result { + let mut data_size = 0u32; + unsafe { + match qvl_sys::tdx_qv_get_quote_supplemental_data_size(&mut data_size) { + quote3_error_t::SGX_QL_SUCCESS => Ok(data_size), + error_code => Err(error_code), + } + } +} + +/// Perform TDX ECDSA quote verification. +/// +/// # Param +/// - **quote**\ +/// TDX Quote, presented as u8 vector. +/// - **quote_collateral**\ +/// Quote Certification Collateral provided by the caller. +/// - **expiration_check_date**\ +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// - **qve_report_info**\ +/// This parameter can be used in 2 ways.\ +/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ +/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. +/// - **supplemental_data_size**\ +/// Size of the supplemental data (in bytes). +/// - **supplemental_data**\ +/// The parameter is optional. If it is None, supplemental_data_size must be 0. +/// +/// # Return +/// Result type of (collateral_expiration_status, verification_result). +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* +/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* +/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn tdx_qv_verify_quote( + quote: &[u8], + quote_collateral: Option<&Collateral>, + expiration_check_date: i64, + qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, + supplemental_data_size: u32, + supplemental_data: Option<&mut sgx_ql_qv_supplemental_t>, +) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { + let mut collateral_expiration_status = 1u32; + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + + let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); + let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); + + let p_qve_report_info = match qve_report_info { + Some(p) => p, + None => std::ptr::null_mut(), + }; + let p_supplemental_data = match supplemental_data { + Some(p) => p as *mut sgx_ql_qv_supplemental_t as *mut u8, + None => std::ptr::null_mut(), + }; + + unsafe { + match qvl_sys::tdx_qv_verify_quote( + quote.as_ptr(), + quote.len() as u32, + p_quote_collateral, + expiration_check_date, + &mut collateral_expiration_status, + &mut quote_verification_result, + p_qve_report_info, + supplemental_data_size, + p_supplemental_data, + ) { + quote3_error_t::SGX_QL_SUCCESS => { + Ok((collateral_expiration_status, quote_verification_result)) + } + error_code => Err(error_code), + } + } +} + +/// Set the full path of QVE and QPL library.\ +/// The function takes the enum and the corresponding full path. +/// +/// # Param +/// - **path_type**\ +/// The type of binary being passed in. +/// - **path**\ +/// It should be a valid full path. +/// +/// # Return +/// - ***SGX_QL_SUCCESS***\ +/// Successfully set the full path. +/// - ***SGX_QL_ERROR_INVALID_PARAMETER***\ +/// Path is not a valid full path or the path is too long. +/// +#[cfg(target_os = "linux")] +pub fn sgx_qv_set_path(path_type: sgx_qv_path_type_t, path: &str) -> quote3_error_t { + match std::ffi::CString::new(path) { + Ok(path) => unsafe { qvl_sys::sgx_qv_set_path(path_type, path.as_ptr()) }, + _ => quote3_error_t::SGX_QL_ERROR_INVALID_PARAMETER, + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Collateral { + pub major_version: u16, + pub minor_version: u16, + pub tee_type: u32, + pub pck_crl_issuer_chain: Box<[u8]>, + pub root_ca_crl: Box<[u8]>, + pub pck_crl: Box<[u8]>, + pub tcb_info_issuer_chain: Box<[u8]>, + pub tcb_info: Box<[u8]>, + pub qe_identity_issuer_chain: Box<[u8]>, + pub qe_identity: Box<[u8]>, +} + +// referential struct +struct SgxQlQveCollateralT<'a> { + inner: sgx_ql_qve_collateral_t, + _phantom: PhantomData<&'a ()>, +} + +// create the referential struct +impl<'a> From<&'a Collateral> for SgxQlQveCollateralT<'a> { + fn from(data: &'a Collateral) -> Self { + let mut this = SgxQlQveCollateralT { + inner: sgx_ql_qve_collateral_t { + __bindgen_anon_1: Default::default(), + tee_type: data.tee_type, + pck_crl_issuer_chain: data.pck_crl_issuer_chain.as_ptr() as _, + pck_crl_issuer_chain_size: data.pck_crl_issuer_chain.len() as _, + root_ca_crl: data.root_ca_crl.as_ptr() as _, + root_ca_crl_size: data.root_ca_crl.len() as _, + pck_crl: data.pck_crl.as_ptr() as _, + pck_crl_size: data.pck_crl.len() as _, + tcb_info_issuer_chain: data.tcb_info_issuer_chain.as_ptr() as _, + tcb_info_issuer_chain_size: data.tcb_info_issuer_chain.len() as _, + tcb_info: data.tcb_info.as_ptr() as _, + tcb_info_size: data.tcb_info.len() as _, + qe_identity_issuer_chain: data.qe_identity_issuer_chain.as_ptr() as _, + qe_identity_issuer_chain_size: data.qe_identity_issuer_chain.len() as _, + qe_identity: data.qe_identity.as_ptr() as _, + qe_identity_size: data.qe_identity.len() as _, + }, + _phantom: PhantomData, + }; + this.inner.__bindgen_anon_1.__bindgen_anon_1.major_version = data.major_version; + this.inner.__bindgen_anon_1.__bindgen_anon_1.minor_version = data.minor_version; + this + } +} + +impl Deref for SgxQlQveCollateralT<'_> { + type Target = sgx_ql_qve_collateral_t; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +/// Get quote verification collateral. +/// +/// # Param +/// - **quote**\ +/// SGX/TDX Quote, presented as u8 vector. +/// +/// # Return +/// Result type of quote_collateral. +/// +/// - **quote_collateral**\ +/// This is the Quote Certification Collateral retrieved based on Quote. +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_PLATFORM_LIB_UNAVAILABLE* +/// - *SGX_QL_PCK_CERT_CHAIN_ERROR* +/// - *SGX_QL_PCK_CERT_UNSUPPORTED_FORMAT* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_OUT_OF_MEMORY* +/// - *SGX_QL_NO_QUOTE_COLLATERAL_DATA* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn tee_qv_get_collateral(quote: &[u8]) -> Result { + fn try_into_collateral( + buf: *const sgx_ql_qve_collateral_t, + buf_len: u32, + ) -> Result { + fn try_into_boxed_slice( + p: *mut ::std::os::raw::c_char, + size: u32, + ) -> Result, quote3_error_t> { + if p.is_null() || !p.is_aligned() { + return Err(quote3_error_t::SGX_QL_ERROR_MAX); + } + Ok(Box::from(unsafe { + slice::from_raw_parts(p as _, size as _) + })) + } + + if buf.is_null() + || (buf_len as usize) < size_of::() + || !buf.is_aligned() + { + return Err(quote3_error_t::SGX_QL_ERROR_MAX); + } + + // SAFETY: buf is not null, buf_len is not zero, and buf is aligned. + let collateral = unsafe { *buf }; + + Ok(Collateral { + major_version: unsafe { collateral.__bindgen_anon_1.__bindgen_anon_1.major_version }, + minor_version: unsafe { collateral.__bindgen_anon_1.__bindgen_anon_1.minor_version }, + tee_type: collateral.tee_type, + pck_crl_issuer_chain: try_into_boxed_slice( + collateral.pck_crl_issuer_chain, + collateral.pck_crl_issuer_chain_size, + )?, + root_ca_crl: try_into_boxed_slice(collateral.root_ca_crl, collateral.root_ca_crl_size)?, + pck_crl: try_into_boxed_slice(collateral.pck_crl, collateral.pck_crl_size)?, + tcb_info_issuer_chain: try_into_boxed_slice( + collateral.tcb_info_issuer_chain, + collateral.tcb_info_issuer_chain_size, + )?, + tcb_info: try_into_boxed_slice(collateral.tcb_info, collateral.tcb_info_size)?, + qe_identity_issuer_chain: try_into_boxed_slice( + collateral.qe_identity_issuer_chain, + collateral.qe_identity_issuer_chain_size, + )?, + qe_identity: try_into_boxed_slice(collateral.qe_identity, collateral.qe_identity_size)?, + }) + } + + let mut buf = std::ptr::null_mut(); + let mut buf_len = 0u32; + + match unsafe { + qvl_sys::tee_qv_get_collateral(quote.as_ptr(), quote.len() as u32, &mut buf, &mut buf_len) + } { + quote3_error_t::SGX_QL_SUCCESS => { + let collateral = try_into_collateral(buf as _, buf_len); + + match unsafe { tee_qv_free_collateral(buf) } { + quote3_error_t::SGX_QL_SUCCESS => collateral, + error_code => Err(error_code), + } + } + error_code => Err(error_code), + } +} + +/// Get supplemental data latest version and required size, support both SGX and TDX. +/// +/// # Param +/// - **quote**\ +/// SGX/TDX Quote, presented as u8 vector. +/// +/// # Return +/// Result type of (version, data_size) tuple. +/// +/// - **version**\ +/// Latest version of the supplemental data. +/// - **data_size**\ +/// The size of the buffer in bytes required to contain all of the supplemental data. +/// +pub fn tee_get_supplemental_data_version_and_size( + quote: &[u8], +) -> Result<(u32, u32), quote3_error_t> { + let mut version = 0u32; + let mut data_size = 0u32; + + unsafe { + match qvl_sys::tee_get_supplemental_data_version_and_size( + quote.as_ptr(), + quote.len() as u32, + &mut version, + &mut data_size, + ) { + quote3_error_t::SGX_QL_SUCCESS => Ok((version, data_size)), + error_code => Err(error_code), + } + } +} + +/// Perform quote verification for SGX and TDX.\ +/// This API works the same as the old one, but takes a new parameter to describe the supplemental data (supp_data_descriptor). +/// +/// # Param +/// - **quote**\ +/// SGX/TDX Quote, presented as u8 vector. +/// - **quote_collateral**\ +/// Quote Certification Collateral provided by the caller. +/// - **expiration_check_date**\ +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// - **qve_report_info**\ +/// This parameter can be used in 2 ways.\ +/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ +/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. +/// - **supp_datal_descriptor**\ +/// *tee_supp_data_descriptor_t* structure.\ +/// You can specify the major version of supplemental data by setting supp_datal_descriptor.major_version.\ +/// If supp_datal_descriptor is None, no supplemental data is returned.\ +/// If supp_datal_descriptor.major_version == 0, then return the latest version of the *sgx_ql_qv_supplemental_t* structure.\ +/// If supp_datal_descriptor.major_version <= latest supported version, return the latest minor version associated with that major version.\ +/// If supp_datal_descriptor.major_version > latest supported version, return an error *SGX_QL_SUPPLEMENTAL_DATA_VERSION_NOT_SUPPORTED*. +/// +/// # Return +/// Result type of (collateral_expiration_status, verification_result). +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* +/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* +/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn tee_verify_quote( + quote: &[u8], + quote_collateral: Option<&Collateral>, + expiration_check_date: i64, + qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, + supp_data_descriptor: Option<&mut tee_supp_data_descriptor_t>, +) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { + let mut collateral_expiration_status = 1u32; + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + + let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); + let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); + + let p_qve_report_info = qve_report_info.map_or(std::ptr::null_mut(), |p| p); + + let p_supp_data_descriptor = supp_data_descriptor.map_or(std::ptr::null_mut(), |p| p); + + unsafe { + match qvl_sys::tee_verify_quote( + quote.as_ptr(), + quote.len() as u32, + p_quote_collateral as _, + expiration_check_date, + &mut collateral_expiration_status, + &mut quote_verification_result, + p_qve_report_info, + p_supp_data_descriptor, + ) { + quote3_error_t::SGX_QL_SUCCESS => { + Ok((collateral_expiration_status, quote_verification_result)) + } + error_code => Err(error_code), + } + } +} diff --git a/crates/teepot-tee-quote-verification-rs/src/lib.rs b/crates/teepot-tee-quote-verification-rs/src/lib.rs index c19b292..75dd91f 100644 --- a/crates/teepot-tee-quote-verification-rs/src/lib.rs +++ b/crates/teepot-tee-quote-verification-rs/src/lib.rs @@ -1,557 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2024-2025 Matter Labs -// SPDX-License-Identifier: BSD-3-Clause -/* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -//! Intel(R) Software Guard Extensions Data Center Attestation Primitives (Intel(R) SGX DCAP) -//! Rust wrapper for Quote Verification Library -//! ================================================ -//! -//! This is a safe wrapper for **sgx-dcap-quoteverify-sys**. +#[cfg_attr(all(target_os = "linux", target_arch = "x86_64"), path = "intel.rs")] +#[cfg_attr( + not(all(target_os = "linux", target_arch = "x86_64")), + path = "empty.rs" +)] +mod os; -use serde::{Deserialize, Serialize}; -use std::{marker::PhantomData, ops::Deref, slice}; - -use intel_tee_quote_verification_sys as qvl_sys; -pub use qvl_sys::{ - quote3_error_t, sgx_ql_qe_report_info_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, - sgx_ql_qve_collateral_t, sgx_ql_request_policy_t, sgx_qv_path_type_t, tdx_ql_qve_collateral_t, - tee_qv_free_collateral, tee_supp_data_descriptor_t, -}; - -/// When the Quoting Verification Library is linked to a process, it needs to know the proper enclave loading policy. -/// The library may be linked with a long lived process, such as a service, where it can load the enclaves and leave -/// them loaded (persistent). This better ensures that the enclaves will be available upon quote requests and not subject -/// to EPC limitations if loaded on demand. However, if the Quoting library is linked with an application process, there -/// may be many applications with the Quoting library and a better utilization of EPC is to load and unloaded the quoting -/// enclaves on demand (ephemeral). The library will be shipped with a default policy of loading enclaves and leaving -/// them loaded until the library is unloaded (PERSISTENT). If the policy is set to EPHEMERAL, then the QE and PCE will -/// be loaded and unloaded on-demand. If either enclave is already loaded when the policy is change to EPHEMERAL, the -/// enclaves will be unloaded before returning. -/// -/// # Param -/// - **policy**\ -/// Set the requested enclave loading policy to either *SGX_QL_PERSISTENT*, *SGX_QL_EPHEMERAL* or *SGX_QL_DEFAULT*. -/// -/// # Return -/// - ***SGX_QL_SUCCESS***\ -/// Successfully set the enclave loading policy for the quoting library's enclaves.\ -/// - ***SGX_QL_UNSUPPORTED_LOADING_POLICY***\ -/// The selected policy is not support by the quoting library.\ -/// - ***SGX_QL_ERROR_UNEXPECTED***\ -/// Unexpected internal error. -/// -/// # Examples -/// ``` -/// use teepot_tee_quote_verification_rs::*; -/// -/// let policy = sgx_ql_request_policy_t::SGX_QL_DEFAULT; -/// let ret = sgx_qv_set_enclave_load_policy(policy); -/// -/// assert_eq!(ret, quote3_error_t::SGX_QL_SUCCESS); -/// ``` -pub fn sgx_qv_set_enclave_load_policy(policy: sgx_ql_request_policy_t) -> quote3_error_t { - unsafe { qvl_sys::sgx_qv_set_enclave_load_policy(policy) } -} - -/// Get SGX supplemental data required size. -/// -/// # Return -/// Size of the supplemental data in bytes. -/// -/// Status code of the operation, one of: -/// - *SGX_QL_ERROR_INVALID_PARAMETER* -/// - *SGX_QL_ERROR_QVL_QVE_MISMATCH* -/// - *SGX_QL_ENCLAVE_LOAD_ERROR* -/// -/// # Examples -/// ``` -/// use teepot_tee_quote_verification_rs::*; -/// -/// let data_size = sgx_qv_get_quote_supplemental_data_size().unwrap(); -/// -/// assert_eq!(data_size, std::mem::size_of::() as u32); -/// ``` -pub fn sgx_qv_get_quote_supplemental_data_size() -> Result { - let mut data_size = 0u32; - unsafe { - match qvl_sys::sgx_qv_get_quote_supplemental_data_size(&mut data_size) { - quote3_error_t::SGX_QL_SUCCESS => Ok(data_size), - error_code => Err(error_code), - } - } -} - -/// Perform SGX ECDSA quote verification. -/// -/// # Param -/// - **quote**\ -/// SGX Quote, presented as u8 vector. -/// - **quote_collateral**\ -/// Quote Certification Collateral provided by the caller. -/// - **expiration_check_date**\ -/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. -/// - **qve_report_info**\ -/// This parameter can be used in 2 ways.\ -/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ -/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. -/// - **supplemental_data_size**\ -/// Size of the supplemental data (in bytes). -/// - **supplemental_data**\ -/// The parameter is optional. If it is None, supplemental_data_size must be 0. -/// -/// # Return -/// Result type of (collateral_expiration_status, verification_result). -/// -/// Status code of the operation, one of: -/// - *SGX_QL_ERROR_INVALID_PARAMETER* -/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* -/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* -/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* -/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* -/// - *SGX_QL_ERROR_UNEXPECTED* -/// -pub fn sgx_qv_verify_quote( - quote: &[u8], - quote_collateral: Option<&Collateral>, - expiration_check_date: i64, - qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, - supplemental_data_size: u32, - supplemental_data: Option<&mut sgx_ql_qv_supplemental_t>, -) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { - let mut collateral_expiration_status = 1u32; - let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; - - let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); - let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); - - let p_qve_report_info = match qve_report_info { - Some(p) => p, - None => std::ptr::null_mut(), - }; - let p_supplemental_data = match supplemental_data { - Some(p) => p as *mut sgx_ql_qv_supplemental_t as *mut u8, - None => std::ptr::null_mut(), - }; - - unsafe { - match qvl_sys::sgx_qv_verify_quote( - quote.as_ptr(), - quote.len() as u32, - p_quote_collateral, - expiration_check_date, - &mut collateral_expiration_status, - &mut quote_verification_result, - p_qve_report_info, - supplemental_data_size, - p_supplemental_data, - ) { - quote3_error_t::SGX_QL_SUCCESS => { - Ok((collateral_expiration_status, quote_verification_result)) - } - error_code => Err(error_code), - } - } -} - -/// Get TDX supplemental data required size. -/// -/// # Return -/// Size of the supplemental data in bytes. -/// -/// Status code of the operation, one of: -/// - *SGX_QL_ERROR_INVALID_PARAMETER* -/// - *SGX_QL_ERROR_QVL_QVE_MISMATCH* -/// - *SGX_QL_ENCLAVE_LOAD_ERROR* -/// -/// # Examples -/// ``` -/// use teepot_tee_quote_verification_rs::*; -/// -/// let data_size = tdx_qv_get_quote_supplemental_data_size().unwrap(); -/// -/// assert_eq!(data_size, std::mem::size_of::() as u32); -/// ``` -pub fn tdx_qv_get_quote_supplemental_data_size() -> Result { - let mut data_size = 0u32; - unsafe { - match qvl_sys::tdx_qv_get_quote_supplemental_data_size(&mut data_size) { - quote3_error_t::SGX_QL_SUCCESS => Ok(data_size), - error_code => Err(error_code), - } - } -} - -/// Perform TDX ECDSA quote verification. -/// -/// # Param -/// - **quote**\ -/// TDX Quote, presented as u8 vector. -/// - **quote_collateral**\ -/// Quote Certification Collateral provided by the caller. -/// - **expiration_check_date**\ -/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. -/// - **qve_report_info**\ -/// This parameter can be used in 2 ways.\ -/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ -/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. -/// - **supplemental_data_size**\ -/// Size of the supplemental data (in bytes). -/// - **supplemental_data**\ -/// The parameter is optional. If it is None, supplemental_data_size must be 0. -/// -/// # Return -/// Result type of (collateral_expiration_status, verification_result). -/// -/// Status code of the operation, one of: -/// - *SGX_QL_ERROR_INVALID_PARAMETER* -/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* -/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* -/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* -/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* -/// - *SGX_QL_ERROR_UNEXPECTED* -/// -pub fn tdx_qv_verify_quote( - quote: &[u8], - quote_collateral: Option<&Collateral>, - expiration_check_date: i64, - qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, - supplemental_data_size: u32, - supplemental_data: Option<&mut sgx_ql_qv_supplemental_t>, -) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { - let mut collateral_expiration_status = 1u32; - let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; - - let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); - let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); - - let p_qve_report_info = match qve_report_info { - Some(p) => p, - None => std::ptr::null_mut(), - }; - let p_supplemental_data = match supplemental_data { - Some(p) => p as *mut sgx_ql_qv_supplemental_t as *mut u8, - None => std::ptr::null_mut(), - }; - - unsafe { - match qvl_sys::tdx_qv_verify_quote( - quote.as_ptr(), - quote.len() as u32, - p_quote_collateral, - expiration_check_date, - &mut collateral_expiration_status, - &mut quote_verification_result, - p_qve_report_info, - supplemental_data_size, - p_supplemental_data, - ) { - quote3_error_t::SGX_QL_SUCCESS => { - Ok((collateral_expiration_status, quote_verification_result)) - } - error_code => Err(error_code), - } - } -} - -/// Set the full path of QVE and QPL library.\ -/// The function takes the enum and the corresponding full path. -/// -/// # Param -/// - **path_type**\ -/// The type of binary being passed in. -/// - **path**\ -/// It should be a valid full path. -/// -/// # Return -/// - ***SGX_QL_SUCCESS***\ -/// Successfully set the full path. -/// - ***SGX_QL_ERROR_INVALID_PARAMETER***\ -/// Path is not a valid full path or the path is too long. -/// -#[cfg(target_os = "linux")] -pub fn sgx_qv_set_path(path_type: sgx_qv_path_type_t, path: &str) -> quote3_error_t { - match std::ffi::CString::new(path) { - Ok(path) => unsafe { qvl_sys::sgx_qv_set_path(path_type, path.as_ptr()) }, - _ => quote3_error_t::SGX_QL_ERROR_INVALID_PARAMETER, - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Collateral { - pub major_version: u16, - pub minor_version: u16, - pub tee_type: u32, - pub pck_crl_issuer_chain: Box<[u8]>, - pub root_ca_crl: Box<[u8]>, - pub pck_crl: Box<[u8]>, - pub tcb_info_issuer_chain: Box<[u8]>, - pub tcb_info: Box<[u8]>, - pub qe_identity_issuer_chain: Box<[u8]>, - pub qe_identity: Box<[u8]>, -} - -// referential struct -struct SgxQlQveCollateralT<'a> { - inner: sgx_ql_qve_collateral_t, - _phantom: PhantomData<&'a ()>, -} - -// create the referential struct -impl<'a> From<&'a Collateral> for SgxQlQveCollateralT<'a> { - fn from(data: &'a Collateral) -> Self { - let mut this = SgxQlQveCollateralT { - inner: sgx_ql_qve_collateral_t { - __bindgen_anon_1: Default::default(), - tee_type: data.tee_type, - pck_crl_issuer_chain: data.pck_crl_issuer_chain.as_ptr() as _, - pck_crl_issuer_chain_size: data.pck_crl_issuer_chain.len() as _, - root_ca_crl: data.root_ca_crl.as_ptr() as _, - root_ca_crl_size: data.root_ca_crl.len() as _, - pck_crl: data.pck_crl.as_ptr() as _, - pck_crl_size: data.pck_crl.len() as _, - tcb_info_issuer_chain: data.tcb_info_issuer_chain.as_ptr() as _, - tcb_info_issuer_chain_size: data.tcb_info_issuer_chain.len() as _, - tcb_info: data.tcb_info.as_ptr() as _, - tcb_info_size: data.tcb_info.len() as _, - qe_identity_issuer_chain: data.qe_identity_issuer_chain.as_ptr() as _, - qe_identity_issuer_chain_size: data.qe_identity_issuer_chain.len() as _, - qe_identity: data.qe_identity.as_ptr() as _, - qe_identity_size: data.qe_identity.len() as _, - }, - _phantom: PhantomData, - }; - this.inner.__bindgen_anon_1.__bindgen_anon_1.major_version = data.major_version; - this.inner.__bindgen_anon_1.__bindgen_anon_1.minor_version = data.minor_version; - this - } -} - -impl Deref for SgxQlQveCollateralT<'_> { - type Target = sgx_ql_qve_collateral_t; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -/// Get quote verification collateral. -/// -/// # Param -/// - **quote**\ -/// SGX/TDX Quote, presented as u8 vector. -/// -/// # Return -/// Result type of quote_collateral. -/// -/// - **quote_collateral**\ -/// This is the Quote Certification Collateral retrieved based on Quote. -/// -/// Status code of the operation, one of: -/// - *SGX_QL_ERROR_INVALID_PARAMETER* -/// - *SGX_QL_PLATFORM_LIB_UNAVAILABLE* -/// - *SGX_QL_PCK_CERT_CHAIN_ERROR* -/// - *SGX_QL_PCK_CERT_UNSUPPORTED_FORMAT* -/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* -/// - *SGX_QL_OUT_OF_MEMORY* -/// - *SGX_QL_NO_QUOTE_COLLATERAL_DATA* -/// - *SGX_QL_ERROR_UNEXPECTED* -/// -pub fn tee_qv_get_collateral(quote: &[u8]) -> Result { - fn try_into_collateral( - buf: *const sgx_ql_qve_collateral_t, - buf_len: u32, - ) -> Result { - fn try_into_boxed_slice( - p: *mut ::std::os::raw::c_char, - size: u32, - ) -> Result, quote3_error_t> { - if p.is_null() || !p.is_aligned() { - return Err(quote3_error_t::SGX_QL_ERROR_MAX); - } - Ok(Box::from(unsafe { - slice::from_raw_parts(p as _, size as _) - })) - } - - if buf.is_null() - || (buf_len as usize) < size_of::() - || !buf.is_aligned() - { - return Err(quote3_error_t::SGX_QL_ERROR_MAX); - } - - // SAFETY: buf is not null, buf_len is not zero, and buf is aligned. - let collateral = unsafe { *buf }; - - Ok(Collateral { - major_version: unsafe { collateral.__bindgen_anon_1.__bindgen_anon_1.major_version }, - minor_version: unsafe { collateral.__bindgen_anon_1.__bindgen_anon_1.minor_version }, - tee_type: collateral.tee_type, - pck_crl_issuer_chain: try_into_boxed_slice( - collateral.pck_crl_issuer_chain, - collateral.pck_crl_issuer_chain_size, - )?, - root_ca_crl: try_into_boxed_slice(collateral.root_ca_crl, collateral.root_ca_crl_size)?, - pck_crl: try_into_boxed_slice(collateral.pck_crl, collateral.pck_crl_size)?, - tcb_info_issuer_chain: try_into_boxed_slice( - collateral.tcb_info_issuer_chain, - collateral.tcb_info_issuer_chain_size, - )?, - tcb_info: try_into_boxed_slice(collateral.tcb_info, collateral.tcb_info_size)?, - qe_identity_issuer_chain: try_into_boxed_slice( - collateral.qe_identity_issuer_chain, - collateral.qe_identity_issuer_chain_size, - )?, - qe_identity: try_into_boxed_slice(collateral.qe_identity, collateral.qe_identity_size)?, - }) - } - - let mut buf = std::ptr::null_mut(); - let mut buf_len = 0u32; - - match unsafe { - qvl_sys::tee_qv_get_collateral(quote.as_ptr(), quote.len() as u32, &mut buf, &mut buf_len) - } { - quote3_error_t::SGX_QL_SUCCESS => { - let collateral = try_into_collateral(buf as _, buf_len); - - match unsafe { tee_qv_free_collateral(buf) } { - quote3_error_t::SGX_QL_SUCCESS => collateral, - error_code => Err(error_code), - } - } - error_code => Err(error_code), - } -} - -/// Get supplemental data latest version and required size, support both SGX and TDX. -/// -/// # Param -/// - **quote**\ -/// SGX/TDX Quote, presented as u8 vector. -/// -/// # Return -/// Result type of (version, data_size) tuple. -/// -/// - **version**\ -/// Latest version of the supplemental data. -/// - **data_size**\ -/// The size of the buffer in bytes required to contain all of the supplemental data. -/// -pub fn tee_get_supplemental_data_version_and_size( - quote: &[u8], -) -> Result<(u32, u32), quote3_error_t> { - let mut version = 0u32; - let mut data_size = 0u32; - - unsafe { - match qvl_sys::tee_get_supplemental_data_version_and_size( - quote.as_ptr(), - quote.len() as u32, - &mut version, - &mut data_size, - ) { - quote3_error_t::SGX_QL_SUCCESS => Ok((version, data_size)), - error_code => Err(error_code), - } - } -} - -/// Perform quote verification for SGX and TDX.\ -/// This API works the same as the old one, but takes a new parameter to describe the supplemental data (supp_data_descriptor). -/// -/// # Param -/// - **quote**\ -/// SGX/TDX Quote, presented as u8 vector. -/// - **quote_collateral**\ -/// Quote Certification Collateral provided by the caller. -/// - **expiration_check_date**\ -/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. -/// - **qve_report_info**\ -/// This parameter can be used in 2 ways.\ -/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ -/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. -/// - **supp_datal_descriptor**\ -/// *tee_supp_data_descriptor_t* structure.\ -/// You can specify the major version of supplemental data by setting supp_datal_descriptor.major_version.\ -/// If supp_datal_descriptor is None, no supplemental data is returned.\ -/// If supp_datal_descriptor.major_version == 0, then return the latest version of the *sgx_ql_qv_supplemental_t* structure.\ -/// If supp_datal_descriptor.major_version <= latest supported version, return the latest minor version associated with that major version.\ -/// If supp_datal_descriptor.major_version > latest supported version, return an error *SGX_QL_SUPPLEMENTAL_DATA_VERSION_NOT_SUPPORTED*. -/// -/// # Return -/// Result type of (collateral_expiration_status, verification_result). -/// -/// Status code of the operation, one of: -/// - *SGX_QL_ERROR_INVALID_PARAMETER* -/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* -/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* -/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* -/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* -/// - *SGX_QL_ERROR_UNEXPECTED* -/// -pub fn tee_verify_quote( - quote: &[u8], - quote_collateral: Option<&Collateral>, - expiration_check_date: i64, - qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, - supp_data_descriptor: Option<&mut tee_supp_data_descriptor_t>, -) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { - let mut collateral_expiration_status = 1u32; - let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; - - let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); - let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); - - let p_qve_report_info = qve_report_info.map_or(std::ptr::null_mut(), |p| p); - - let p_supp_data_descriptor = supp_data_descriptor.map_or(std::ptr::null_mut(), |p| p); - - unsafe { - match qvl_sys::tee_verify_quote( - quote.as_ptr(), - quote.len() as u32, - p_quote_collateral as _, - expiration_check_date, - &mut collateral_expiration_status, - &mut quote_verification_result, - p_qve_report_info, - p_supp_data_descriptor, - ) { - quote3_error_t::SGX_QL_SUCCESS => { - Ok((collateral_expiration_status, quote_verification_result)) - } - error_code => Err(error_code), - } - } -} +pub use os::*; diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index 357238c..57e2408 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -10,15 +10,15 @@ edition.workspace = true authors.workspace = true repository.workspace = true -[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] -tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } -teepot-tee-quote-verification-rs = { path = "../teepot-tee-quote-verification-rs" } - [target.'cfg(not(all(target_os = "linux", target_arch = "x86_64")))'.dependencies] dcap-qvl = "0.2.3" chrono = "0.4.40" bytes.workspace = true +[features] +default = ["quote_op"] +quote_op = ["dep:teepot-tee-quote-verification-rs"] + [dependencies] anyhow.workspace = true asn1_der.workspace = true @@ -49,6 +49,7 @@ serde_json.workspace = true sha2.workspace = true sha3.workspace = true signature.workspace = true +teepot-tee-quote-verification-rs = { path = "../teepot-tee-quote-verification-rs", optional = true } thiserror.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/crates/teepot/src/lib.rs b/crates/teepot/src/lib.rs index 1ce4079..9016d01 100644 --- a/crates/teepot/src/lib.rs +++ b/crates/teepot/src/lib.rs @@ -9,6 +9,7 @@ pub mod config; pub mod ethereum; pub mod log; +#[cfg(feature = "quote_op")] pub mod pki; pub mod prover; pub mod quote; diff --git a/crates/teepot/src/quote/error.rs b/crates/teepot/src/quote/error.rs index cf121d4..192cbda 100644 --- a/crates/teepot/src/quote/error.rs +++ b/crates/teepot/src/quote/error.rs @@ -4,8 +4,8 @@ //! Quote Error type use std::io; -#[cfg(all(target_os = "linux", target_arch = "x86_64"))] -use tdx_attest_rs::tdx_attest_error_t; +#[cfg(all(feature = "quote_op", target_os = "linux", target_arch = "x86_64"))] +use teepot_tee_quote_verification_rs::tdx_attest_rs::tdx_attest_error_t; use thiserror::Error; /// Quote parsing error @@ -22,7 +22,7 @@ pub enum QuoteError { InvalidTeeType, #[error("unsupported body type")] UnsupportedBodyType, - #[cfg(all(target_os = "linux", target_arch = "x86_64"))] + #[cfg(all(feature = "quote_op", target_os = "linux", target_arch = "x86_64"))] #[error("tdx_att_get_quote error {msg}: {inner:?}")] TdxAttGetQuote { inner: tdx_attest_error_t, @@ -58,7 +58,7 @@ pub enum QuoteError { CrlUnsupportedFormat(String), } -#[cfg(all(target_os = "linux", target_arch = "x86_64"))] +#[cfg(all(feature = "quote_op", target_os = "linux", target_arch = "x86_64"))] impl From for QuoteError { fn from(code: tdx_attest_error_t) -> Self { Self::TdxAttGetQuote { @@ -108,7 +108,7 @@ impl QuoteContextErr for Result { } } -#[cfg(all(target_os = "linux", target_arch = "x86_64"))] +#[cfg(all(feature = "quote_op", target_os = "linux", target_arch = "x86_64"))] impl QuoteContext for Result { type Ok = T; fn context>(self, msg: I) -> Result { diff --git a/crates/teepot/src/quote/intel.rs b/crates/teepot/src/quote/intel.rs index fbbaf0b..97ad1b6 100644 --- a/crates/teepot/src/quote/intel.rs +++ b/crates/teepot/src/quote/intel.rs @@ -11,9 +11,9 @@ use crate::{ }; use bytemuck::cast_slice; use std::{ffi::CStr, mem, mem::MaybeUninit, pin::Pin}; -use tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}; use teepot_tee_quote_verification_rs::{ quote3_error_t as _quote3_error_t, sgx_ql_qv_result_t, sgx_ql_qv_supplemental_t, + tdx_attest_rs::{tdx_att_get_quote, tdx_attest_error_t, tdx_report_data_t}, tee_get_supplemental_data_version_and_size, tee_qv_get_collateral, tee_supp_data_descriptor_t, tee_verify_quote, Collateral as IntelCollateral, }; diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index b2ba8ea..8a4c348 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -6,6 +6,7 @@ //! Get a quote from a TEE +#[cfg(feature = "quote_op")] pub mod attestation; pub mod error; pub mod tcblevel; @@ -15,6 +16,7 @@ pub mod tcblevel; not(all(target_os = "linux", target_arch = "x86_64")), path = "phala.rs" )] +#[cfg(feature = "quote_op")] mod os; mod utils; @@ -644,6 +646,7 @@ impl FromStr for TEEType { } /// Get the attestation quote from a TEE +#[cfg(feature = "quote_op")] pub fn get_quote(report_data: &[u8]) -> Result<(TEEType, Box<[u8]>), QuoteError> { os::get_quote(report_data) } @@ -690,11 +693,13 @@ pub struct Collateral { } /// Get the collateral data from an SGX or TDX quote +#[cfg(feature = "quote_op")] pub fn get_collateral(quote: &[u8]) -> Result { os::get_collateral(quote) } /// Verifies a quote with optional collateral material +#[cfg(feature = "quote_op")] pub fn verify_quote_with_collateral( quote: &[u8], collateral: Option<&Collateral>, diff --git a/crates/teepot/src/tdx/mod.rs b/crates/teepot/src/tdx/mod.rs index 878cd17..89fa9e8 100644 --- a/crates/teepot/src/tdx/mod.rs +++ b/crates/teepot/src/tdx/mod.rs @@ -3,7 +3,7 @@ //! Intel TDX helper functions. -#[cfg(all(target_os = "linux", target_arch = "x86_64"))] +#[cfg(all(feature = "quote_op", target_os = "linux", target_arch = "x86_64"))] pub mod rtmr; /// The sha384 digest of 0u32, which is used in the UEFI TPM protocol diff --git a/crates/teepot/src/tdx/rtmr.rs b/crates/teepot/src/tdx/rtmr.rs index 58725f3..bb26c6b 100644 --- a/crates/teepot/src/tdx/rtmr.rs +++ b/crates/teepot/src/tdx/rtmr.rs @@ -4,6 +4,7 @@ //! rtmr event data use crate::sgx::QuoteError; +use teepot_tee_quote_verification_rs::tdx_attest_rs::{tdx_att_extend, tdx_attest_error_t}; /// The actual rtmr event data handled in DCAP #[repr(C, packed)] @@ -59,8 +60,8 @@ impl TdxRtmrEvent { pub fn extend(self) -> Result<(), QuoteError> { let event: Vec = self.into(); - match tdx_attest_rs::tdx_att_extend(&event) { - tdx_attest_rs::tdx_attest_error_t::TDX_ATTEST_SUCCESS => Ok(()), + match tdx_att_extend(&event) { + tdx_attest_error_t::TDX_ATTEST_SUCCESS => Ok(()), error_code => Err(error_code.into()), } } diff --git a/crates/teepot/tests/sgx_quote_verification.rs b/crates/teepot/tests/sgx_quote_verification.rs index 28a33e9..7d8c6b5 100644 --- a/crates/teepot/tests/sgx_quote_verification.rs +++ b/crates/teepot/tests/sgx_quote_verification.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2024-2025 Matter Labs +#[cfg(feature = "quote_op")] mod sgx { use anyhow::{Context, Result}; use std::time::{Duration, UNIX_EPOCH}; From 6379e9aa9e1847ac19aa1ce0bb5a61d33e531af7 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 6 May 2025 10:02:38 +0200 Subject: [PATCH 090/114] feat(teepot): add `Quote::tee_type` method for TEE type determination - Introduced `tee_type` method to extract TEE type from the quote header. Signed-off-by: Harald Hoyer --- crates/teepot/src/quote/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/teepot/src/quote/mod.rs b/crates/teepot/src/quote/mod.rs index 8a4c348..19b1243 100644 --- a/crates/teepot/src/quote/mod.rs +++ b/crates/teepot/src/quote/mod.rs @@ -575,6 +575,22 @@ impl Quote { Ok(quote) } + /// Returns the TEE type of this quote. + /// + /// The TEE type is extracted from the quote header and can be either SGX or TDX for now. + /// Due to validation during quote parsing, this is guaranteed to return only + /// valid TEE types. + pub fn tee_type(&self) -> TEEType { + match self.header.tee_type { + TEE_TYPE_SGX => TEEType::SGX, + TEE_TYPE_TDX => TEEType::TDX, + // Creating `Self` via `parse()`, + // should guarantee that the TEE type + // is nothing else than SGX or TDX + _ => unreachable!(), + } + } + /// Get the raw certificate chain from the quote. pub fn raw_cert_chain(&self) -> Result<&[u8], QuoteError> { let cert_data = match &self.auth_data { From ad26c5e9aebe9fa01bd0844374b07835a6ecad1f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 21:21:53 +0000 Subject: [PATCH 091/114] chore(deps): update trufflesecurity/trufflehog action to v3.88.30 --- .github/workflows/secrets_scanner.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/secrets_scanner.yaml b/.github/workflows/secrets_scanner.yaml index 1e89f90..dfeadc8 100644 --- a/.github/workflows/secrets_scanner.yaml +++ b/.github/workflows/secrets_scanner.yaml @@ -9,7 +9,7 @@ jobs: with: fetch-depth: 0 - name: TruffleHog OSS - uses: trufflesecurity/trufflehog@943daae06ba9cc80437a748155c818e9e3177a30 # v3.88.6 + uses: trufflesecurity/trufflehog@c8921694a53d95ce424af6ae76dbebf3b6a83aef # v3.88.30 with: path: ./ base: ${{ github.event.repository.default_branch }} From bfd895e8f79403a8ce0d7402b990eb35a430cdfd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 14:52:46 +0100 Subject: [PATCH 092/114] chore(deps): update rust crate clap to v4.5.38 (#266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [clap](https://redirect.github.com/clap-rs/clap) | workspace.dependencies | patch | `4.5.30` -> `4.5.38` | --- ### Release Notes
clap-rs/clap (clap) ### [`v4.5.38`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4538---2025-05-11) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.37...v4.5.38) ##### Fixes - *(help)* When showing aliases, include leading `--` or `-` ### [`v4.5.37`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4537---2025-04-18) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.36...v4.5.37) ##### Features - Added `ArgMatches::try_clear_id()` ### [`v4.5.36`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4536---2025-04-11) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.35...v4.5.36) ##### Fixes - *(help)* Revert 4.5.35's "Don't leave space for shorts if there are none" for now ### [`v4.5.35`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4535---2025-04-01) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.34...v4.5.35) ##### Fixes - *(help)* Align positionals and flags when put in the same `help_heading` - *(help)* Don't leave space for shorts if there are none ### [`v4.5.34`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4534---2025-03-27) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.33...v4.5.34) ##### Fixes - *(help)* Don't add extra blank lines with `flatten_help(true)` and subcommands without arguments ### [`v4.5.33`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4533---2025-03-26) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.32...v4.5.33) ##### Fixes - *(error)* When showing the usage of a suggestion for an unknown argument, don't show the group ### [`v4.5.32`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4532---2025-03-10) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.31...v4.5.32) ##### Features - Add `Error::remove` ##### Documentation - *(cookbook)* Switch from `humantime` to `jiff` - *(tutorial)* Better cover required vs optional ##### Internal - Update `pulldown-cmark` ### [`v4.5.31`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4531---2025-02-24) [Compare Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.30...v4.5.31) ##### Features - Add `ValueParserFactory` for `Saturating`
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/matter-labs/teepot). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 56 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36007b4..b92e7b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -931,9 +931,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.30" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -941,9 +941,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.30" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstyle", "clap_lex", @@ -952,9 +952,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck", "proc-macro2", @@ -1652,7 +1652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3827,7 +3827,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4093,7 +4093,7 @@ name = "rtmr-calc" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.30", + "clap 4.5.38", "gpt", "hex", "pe-sign", @@ -4145,7 +4145,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4570,7 +4570,7 @@ name = "sha384-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.30", + "clap 4.5.38", "hex", "sha2", "teepot", @@ -4820,7 +4820,7 @@ name = "tdx-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.30", + "clap 4.5.38", "hex", "teepot", "tracing", @@ -4843,7 +4843,7 @@ name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.30", + "clap 4.5.38", "secp256k1 0.30.0", "teepot", "tracing", @@ -4856,7 +4856,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.30", + "clap 4.5.38", "rsa", "teepot", "tracing", @@ -4884,7 +4884,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.30", + "clap 4.5.38", "serde", "teepot", "teepot-vault", @@ -4901,7 +4901,7 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap 4.5.30", + "clap 4.5.38", "hex", "rustls", "serde_json", @@ -4921,7 +4921,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.30", + "clap 4.5.38", "rustls", "serde_json", "teepot", @@ -4942,7 +4942,7 @@ dependencies = [ "bytemuck", "bytes", "chrono", - "clap 4.5.30", + "clap 4.5.38", "config", "const-oid", "dcap-qvl", @@ -4988,7 +4988,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.30", + "clap 4.5.38", "serde_json", "teepot-vault", "tracing", @@ -5015,7 +5015,7 @@ dependencies = [ "awc", "base64", "bytes", - "clap 4.5.30", + "clap 4.5.38", "const-oid", "futures-core", "hex", @@ -5039,7 +5039,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.30", + "clap 4.5.38", "serde_json", "teepot-vault", "tracing", @@ -5058,7 +5058,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5660,7 +5660,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.30", + "clap 4.5.38", "hex", "pgp", "serde_json", @@ -5676,7 +5676,7 @@ dependencies = [ "actix-web", "anyhow", "base64", - "clap 4.5.30", + "clap 4.5.38", "serde_json", "teepot-vault", "tracing", @@ -5701,7 +5701,7 @@ name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.30", + "clap 4.5.38", "teepot", ] @@ -5710,7 +5710,7 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "bytes", - "clap 4.5.30", + "clap 4.5.38", "enumset", "hex", "jsonrpsee-types", @@ -5937,7 +5937,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] From bef406c456417296d63e04ac3e5c22f1142cabc2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 14:28:51 +0000 Subject: [PATCH 093/114] chore(deps): update rust crate anyhow to v1.0.98 (#273) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b92e7b3..c7fb5d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,9 +337,9 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.96" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "argon2" From f2718456efd831d8b2a7846bd40a202e18d866cd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 15:05:49 +0000 Subject: [PATCH 094/114] chore(deps): update rust crate serde_json to v1.0.140 (#274) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7fb5d4..96e2cec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4424,9 +4424,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.139" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap 2.7.1", "itoa", From e039adf158ed6f376abad17644f4547001952c36 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 15:40:23 +0000 Subject: [PATCH 095/114] chore(deps): update rust crate tracing-actix-web to v0.7.18 (#280) --- Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96e2cec..06a0269 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,7 +1652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -3827,7 +3827,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4145,7 +4145,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5058,7 +5058,7 @@ dependencies = [ "getrandom 0.3.1", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5430,9 +5430,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9f5c1aca50ebebf074ee665b9f99f2e84906dcf6b993a0d0090edb835166d" +checksum = "2340b7722695166c7fc9b3e3cd1166e7c74fedb9075b8f0c74d3822d2e41caf5" dependencies = [ "actix-web", "mutually_exclusive_features", From de010fd093f77fdfe0cd25432c448dd359a121f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 16:14:06 +0000 Subject: [PATCH 096/114] chore(deps): update rust crate thiserror to v2.0.12 (#287) --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06a0269..55fa9a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2612,7 +2612,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "url", "x509-cert", @@ -3259,7 +3259,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", ] @@ -3306,7 +3306,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tonic", "tracing", @@ -3345,7 +3345,7 @@ dependencies = [ "percent-encoding", "rand 0.8.5", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-stream", "tracing", @@ -3588,7 +3588,7 @@ dependencies = [ "sha3", "signature", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "twofish", "x25519-dalek", "zeroize", @@ -3790,7 +3790,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustls", "socket2", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "web-time", @@ -3810,7 +3810,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -4833,7 +4833,7 @@ dependencies = [ "anyhow", "serde", "teepot", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -4970,7 +4970,7 @@ dependencies = [ "signature", "teepot-tee-quote-verification-rs", "testaso", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "tracing-futures", @@ -5026,7 +5026,7 @@ dependencies = [ "serde_with 3.12.0", "sha2", "teepot", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "webpki-roots", "x509-cert", @@ -5106,11 +5106,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -5126,9 +5126,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -5721,7 +5721,7 @@ dependencies = [ "serde_with 3.12.0", "serde_yaml", "teepot", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-util", "tracing", From 5789fdd4339b0d2c6f21233952eaf50fd5c4a894 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 16:49:26 +0000 Subject: [PATCH 097/114] chore(deps): update rust crate getrandom to v0.3.3 (#314) --- Cargo.lock | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 55fa9a9..27252b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1916,16 +1916,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", "wasm-bindgen", - "windows-targets 0.52.6", ] [[package]] @@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3803,7 +3803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" dependencies = [ "bytes", - "getrandom 0.3.1", + "getrandom 0.3.3", "rand 0.9.0", "ring", "rustc-hash 2.1.1", @@ -3839,6 +3839,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -3902,7 +3908,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", ] [[package]] @@ -4948,7 +4954,7 @@ dependencies = [ "dcap-qvl", "enumset", "futures", - "getrandom 0.3.1", + "getrandom 0.3.3", "hex", "num-integer", "num-traits", @@ -5055,7 +5061,7 @@ checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5644,7 +5650,7 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", ] [[package]] @@ -5790,9 +5796,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -6170,9 +6176,9 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags 2.8.0", ] From 119c2abe095b311642b0b0ca7d201eee644583dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 11:32:13 +0100 Subject: [PATCH 098/114] chore(deps): update rust crate bytes to v1.10.1 (#312) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27252b5..f6f3242 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -799,9 +799,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytestring" From b16592ec34f3e1f46551372025e2c9e72b80618a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 11:06:13 +0000 Subject: [PATCH 099/114] chore(deps): update rust crate async-trait to v0.1.88 (#286) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6f3242..abd6c9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,9 +396,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", From 426e22138e964f9a016a724edb86f57c7fb0cf99 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 11:40:12 +0000 Subject: [PATCH 100/114] chore(deps): update rust crate sha2 to v0.10.9 (#318) --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index abd6c9f..0e96b20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4552,9 +4552,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", From 7c655d151c24a5f80abb760a93a65cb7121eca43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 12:13:46 +0000 Subject: [PATCH 101/114] chore(deps): update rust crate reqwest to v0.12.15 (#315) --- Cargo.lock | 93 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e96b20..e94a28d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -3972,9 +3972,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.12" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "base64", "bytes", @@ -5943,7 +5943,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -5979,32 +5979,31 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-registry" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] name = "windows-result" -version = "0.2.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-result", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -6058,13 +6057,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6077,6 +6092,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6089,6 +6110,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6101,12 +6128,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6119,6 +6158,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6131,6 +6176,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6143,6 +6194,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6155,6 +6212,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.3" From c8692df37a26986304f3169b3b9c8b2eedbb8bde Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 14:01:22 +0100 Subject: [PATCH 102/114] fix(deps): update rust crate chrono to v0.4.41 (#320) --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e94a28d..6d8cad1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -880,9 +880,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2911,7 +2911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] From aeff962224b86f44e5385a2385244dab0c0cf074 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 14:33:54 +0100 Subject: [PATCH 103/114] chore(deps): update rust crate enumset to v1.1.6 (#313) --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d8cad1..ce4e04e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1597,9 +1597,9 @@ dependencies = [ [[package]] name = "enumset" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" +checksum = "11a6b7c3d347de0a9f7bfd2f853be43fe32fa6fac30c70f6d6d67a1e936b87ee" dependencies = [ "enumset_derive", "serde", @@ -1607,9 +1607,9 @@ dependencies = [ [[package]] name = "enumset_derive" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" +checksum = "6da3ea9e1d1a3b1593e15781f930120e72aa7501610b2f82e5b6739c72e8eac5" dependencies = [ "darling 0.20.10", "proc-macro2", From 205113ecfaa8ae0a0a0e4a40f14e63e4b5e17611 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 28 May 2025 08:42:44 +0200 Subject: [PATCH 104/114] feat(intel-dcap-api): add comprehensive testing infrastructure and examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add mock tests using real Intel API response data (25 tests) - Create fetch_test_data tool to retrieve real API responses for testing - Add integration_test example covering 17 API endpoints - Add common_usage example demonstrating attestation verification patterns - Add issuer chain validation checks to ensure signature verification is possible - Add comprehensive documentation in CLAUDE.md The test suite now covers all major Intel DCAP API functionality including TCB info, enclave identities, PCK CRLs, FMSPCs, and evaluation data numbers for both SGX and TDX platforms across API v3 and v4. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude Signed-off-by: Harald Hoyer --- Cargo.lock | 51 + crates/intel-dcap-api/CLAUDE.md | 128 +++ crates/intel-dcap-api/Cargo.toml | 7 + .../intel-dcap-api/examples/common_usage.rs | 182 ++++ .../examples/fetch_test_data.rs | 515 ++++++++++ .../examples/integration_test.rs | 495 ++++++++++ crates/intel-dcap-api/specs/API spec V3.md | 694 ++++++++++++++ crates/intel-dcap-api/specs/API spec V4.md | 664 +++++++++++++ crates/intel-dcap-api/tests/mock_api_tests.rs | 312 ++++++ .../tests/real_data_mock_tests.rs | 901 ++++++++++++++++++ .../tests/test_data/fmspcs.json | 3 + .../tests/test_data/fmspcs_all_platforms.json | 3 + .../tests/test_data/fmspcs_no_filter.json | 3 + .../tests/test_data/pck_crl_platform.json | 4 + .../tests/test_data/pck_crl_processor.json | 4 + .../test_data/pck_crl_processor_der.json | 4 + .../tests/test_data/sgx_qae_identity.json | 4 + .../tests/test_data/sgx_qe_identity.json | 4 + .../tests/test_data/sgx_qe_identity_v3.json | 4 + .../tests/test_data/sgx_qve_identity.json | 4 + .../tests/test_data/sgx_tcb_eval_nums.json | 4 + .../test_data/sgx_tcb_info_00906ED50000.json | 4 + .../tests/test_data/sgx_tcb_info_alt.json | 4 + .../tests/test_data/sgx_tcb_info_early.json | 4 + .../tests/test_data/sgx_tcb_info_v3.json | 4 + .../tests/test_data/tdx_qe_identity.json | 4 + .../tests/test_data/tdx_tcb_eval_nums.json | 4 + .../tests/test_data/tdx_tcb_info.json | 4 + .../test_data/tdx_tcb_info_00806F050000.json | 4 + .../tests/test_data/tdx_tcb_info_eval17.json | 4 + packages/teepotCrate/default.nix | 1 + 31 files changed, 4027 insertions(+) create mode 100644 crates/intel-dcap-api/CLAUDE.md create mode 100644 crates/intel-dcap-api/examples/common_usage.rs create mode 100644 crates/intel-dcap-api/examples/fetch_test_data.rs create mode 100644 crates/intel-dcap-api/examples/integration_test.rs create mode 100644 crates/intel-dcap-api/specs/API spec V3.md create mode 100644 crates/intel-dcap-api/specs/API spec V4.md create mode 100644 crates/intel-dcap-api/tests/mock_api_tests.rs create mode 100644 crates/intel-dcap-api/tests/real_data_mock_tests.rs create mode 100644 crates/intel-dcap-api/tests/test_data/fmspcs.json create mode 100644 crates/intel-dcap-api/tests/test_data/fmspcs_all_platforms.json create mode 100644 crates/intel-dcap-api/tests/test_data/fmspcs_no_filter.json create mode 100644 crates/intel-dcap-api/tests/test_data/pck_crl_platform.json create mode 100644 crates/intel-dcap-api/tests/test_data/pck_crl_processor.json create mode 100644 crates/intel-dcap-api/tests/test_data/pck_crl_processor_der.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_qae_identity.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_qe_identity.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_qe_identity_v3.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_qve_identity.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_tcb_eval_nums.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_tcb_info_00906ED50000.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_tcb_info_alt.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_tcb_info_early.json create mode 100644 crates/intel-dcap-api/tests/test_data/sgx_tcb_info_v3.json create mode 100644 crates/intel-dcap-api/tests/test_data/tdx_qe_identity.json create mode 100644 crates/intel-dcap-api/tests/test_data/tdx_tcb_eval_nums.json create mode 100644 crates/intel-dcap-api/tests/test_data/tdx_tcb_info.json create mode 100644 crates/intel-dcap-api/tests/test_data/tdx_tcb_info_00806F050000.json create mode 100644 crates/intel-dcap-api/tests/test_data/tdx_tcb_info_eval17.json diff --git a/Cargo.lock b/Cargo.lock index ce4e04e..565b002 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,6 +372,16 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -1000,6 +1010,15 @@ dependencies = [ "x509-cert", ] +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "combine" version = "4.6.7" @@ -2607,7 +2626,9 @@ dependencies = [ name = "intel-dcap-api" version = "0.3.0" dependencies = [ + "base64", "hex", + "mockito", "percent-encoding", "reqwest", "serde", @@ -3044,6 +3065,30 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "mockito" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7760e0e418d9b7e5777c0374009ca4c93861b9066f18cb334a20ce50ab63aa48" +dependencies = [ + "assert-json-diff", + "bytes", + "colored", + "futures-util", + "http 1.2.0", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "log", + "rand 0.9.0", + "regex", + "serde_json", + "serde_urlencoded", + "similar", + "tokio", +] + [[package]] name = "mutually_exclusive_features" version = "0.1.0" @@ -4616,6 +4661,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "simple-bytes" version = "0.2.14" diff --git a/crates/intel-dcap-api/CLAUDE.md b/crates/intel-dcap-api/CLAUDE.md new file mode 100644 index 0000000..d2a01b3 --- /dev/null +++ b/crates/intel-dcap-api/CLAUDE.md @@ -0,0 +1,128 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This crate (`intel-dcap-api`) is a Rust client library for Intel's Data Center Attestation Primitives (DCAP) API. It +provides access to Intel's Trusted Services API for SGX and TDX attestation, including TCB info, PCK certificates, CRLs, +and enclave identity verification. + +## Features + +- Support for both API v3 and v4 +- Async/await API using tokio +- Comprehensive error handling with Intel-specific error codes +- Type-safe request/response structures +- Support for SGX and TDX platforms +- Real data integration tests + +## Development Commands + +```bash +# Build +cargo build +cargo build --no-default-features --features rustls # Use rustls instead of default TLS + +# Test +cargo test + +# Lint +cargo clippy + +# Examples +cargo run --example example # Basic usage example +cargo run --example get_pck_crl # Fetch certificate revocation lists +cargo run --example common_usage # Common attestation verification patterns +cargo run --example integration_test # Comprehensive test of most API endpoints +cargo run --example fetch_test_data # Fetch real data from Intel API for tests +``` + +## Architecture + +### Client Structure + +- **ApiClient** (`src/client/mod.rs`): Main entry point supporting API v3/v4 + - Base URL: https://api.trustedservices.intel.com + - Manages HTTP client and API version selection + +### Key Modules + +- **client/**: API endpoint implementations + - `tcb_info`: SGX/TDX TCB information retrieval + - `get_sgx_tcb_info()`, `get_tdx_tcb_info()` + - `pck_cert`: PCK certificate operations + - `get_pck_certificate_by_ppid()`, `get_pck_certificate_by_manifest()` + - `get_pck_certificates_by_ppid()`, `get_pck_certificates_by_manifest()` + - `get_pck_certificates_config_by_ppid()`, `get_pck_certificates_config_by_manifest()` + - `pck_crl`: Certificate revocation lists + - `get_pck_crl()` - supports PEM and DER encoding + - `enclave_identity`: SGX QE/QVE/QAE/TDQE identity + - `get_sgx_qe_identity()`, `get_sgx_qve_identity()`, `get_sgx_qae_identity()`, `get_tdx_qe_identity()` + - `fmspc`: FMSPC-related operations (V4 only) + - `get_fmspcs()` - with optional platform filter + - `get_sgx_tcb_evaluation_data_numbers()`, `get_tdx_tcb_evaluation_data_numbers()` + - `registration`: Platform registration + - `register_platform()`, `add_package()` + +### Core Types + +- **error.rs**: `IntelApiError` for comprehensive error handling + - Extracts error details from Error-Code and Error-Message headers +- **types.rs**: Enums (CaType, ApiVersion, UpdateType, etc.) +- **requests.rs**: Request structures +- **responses.rs**: Response structures with JSON and certificate data + +### API Pattern + +All client methods follow this pattern: + +1. Build request with query parameters +2. Send HTTP request with proper headers +3. Parse response (JSON + certificate chains) +4. Return typed response or error + +### Testing Strategy + +- **Mock Tests**: Two test suites using mockito for HTTP mocking + - `tests/mock_api_tests.rs`: Basic API functionality tests with simple data (11 tests) + - `tests/real_data_mock_tests.rs`: Tests using real Intel API responses (25 tests) +- **Test Data**: Real responses stored in `tests/test_data/` (JSON format) + - Fetched using `cargo run --example fetch_test_data` + - Includes TCB info, CRLs, enclave identities for both SGX and TDX + - Covers V3 and V4 API variations, different update types, and evaluation data numbers +- **Key Testing Considerations**: + - Headers with newlines must be URL-encoded for mockito (use `percent_encode` with `NON_ALPHANUMERIC`) + - V3 vs V4 API use different header names: + - V3: `SGX-TCB-Info-Issuer-Chain` + - V4: `TCB-Info-Issuer-Chain` + - Error responses include Error-Code and Error-Message headers + - Examples use real Intel API endpoints + - Test data (FMSPC, PPID) from Intel documentation + - Async tests require tokio runtime + +## API Version Differences + +### V4-Only Features + +- FMSPC listing (`get_fmspcs()`) +- TCB Evaluation Data Numbers endpoints +- PPID encryption key type parameter +- TDX QE identity endpoint + +## Common Pitfalls + +1. **Mockito Header Encoding**: Always URL-encode headers containing newlines/special characters +2. **API Version Selection**: Some endpoints are V4-only and will return errors on V3 +4. **Platform Filters**: Only certain values are valid (All, Client, E3, E5) +5. **Test Data**: PCK certificate endpoints require valid platform data and often need subscription keys +6. **Issuer Chain Validation**: Always check that `issuer_chain` is non-empty - it's critical for signature verification + +## Security Considerations + +- **Certificate Chain Verification**: The `issuer_chain` field contains the certificates needed to verify the signature + of the response data +- **Signature Validation**: All JSON responses (TCB info, enclave identities) should have their signatures verified + using the issuer chain +- **CRL Verification**: PCK CRLs must be signature-verified before being used for certificate revocation checking +- **Empty Issuer Chains**: Always validate that issuer chains are present and non-empty before trusting response data diff --git a/crates/intel-dcap-api/Cargo.toml b/crates/intel-dcap-api/Cargo.toml index d51993f..310daf7 100644 --- a/crates/intel-dcap-api/Cargo.toml +++ b/crates/intel-dcap-api/Cargo.toml @@ -11,6 +11,7 @@ keywords = ["sgx", "tdx", "intel", "attestation", "confidential"] categories = ["api-bindings", "cryptography", "authentication"] [dependencies] +base64.workspace = true percent-encoding = "2.3.1" reqwest = { workspace = true, features = ["json"] } serde.workspace = true @@ -20,9 +21,15 @@ tokio.workspace = true url.workspace = true [dev-dependencies] +base64.workspace = true hex.workspace = true +mockito = "1.4" x509-cert.workspace = true +[[example]] +name = "integration_test" +required-features = ["default"] + [features] default = ["reqwest/default-tls"] rustls = ["reqwest/rustls-tls"] diff --git a/crates/intel-dcap-api/examples/common_usage.rs b/crates/intel-dcap-api/examples/common_usage.rs new file mode 100644 index 0000000..e276787 --- /dev/null +++ b/crates/intel-dcap-api/examples/common_usage.rs @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use intel_dcap_api::{ApiClient, CaType, IntelApiError, UpdateType}; + +/// Common usage patterns for the Intel DCAP API client +/// +/// This example demonstrates typical use cases for attestation verification. +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create a client (defaults to V4 API) + let client = ApiClient::new()?; + + // Example 1: Get TCB info for quote verification + println!("Example 1: Getting TCB info for SGX quote verification"); + println!("======================================================"); + + let fmspc = "00906ED50000"; // From SGX quote + + match client.get_sgx_tcb_info(fmspc, None, None).await { + Ok(response) => { + // Critical: Check that issuer chain is present for signature verification + if response.issuer_chain.is_empty() { + println!("✗ Error: Empty issuer chain - cannot verify TCB info signature!"); + return Ok(()); + } + + println!("✓ Retrieved TCB info for FMSPC: {}", fmspc); + + // Parse the TCB info + let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?; + + // Extract useful information + if let Some(tcb_levels) = tcb_info["tcbInfo"]["tcbLevels"].as_array() { + println!(" Found {} TCB levels", tcb_levels.len()); + + // Show the latest TCB level + if let Some(latest) = tcb_levels.first() { + println!(" Latest TCB level:"); + if let Some(status) = latest["tcbStatus"].as_str() { + println!(" Status: {}", status); + } + if let Some(date) = latest["tcbDate"].as_str() { + println!(" Date: {}", date); + } + } + } + + // The issuer chain is needed to verify the signature + println!( + " Issuer chain length: {} bytes", + response.issuer_chain.len() + ); + // Verify we have certificate chain for signature verification + let cert_count = response.issuer_chain.matches("BEGIN CERTIFICATE").count(); + println!(" Certificate chain contains {} certificates", cert_count); + } + Err(IntelApiError::ApiError { + status, + error_message, + .. + }) => { + println!( + "✗ API Error {}: {}", + status, + error_message.unwrap_or_default() + ); + } + Err(e) => { + println!("✗ Error: {:?}", e); + } + } + + println!(); + + // Example 2: Get QE identity for enclave verification + println!("Example 2: Getting QE identity for enclave verification"); + println!("======================================================"); + + match client.get_sgx_qe_identity(None, None).await { + Ok(response) => { + // Critical: Check that issuer chain is present for signature verification + if response.issuer_chain.is_empty() { + println!("✗ Error: Empty issuer chain - cannot verify QE identity signature!"); + return Ok(()); + } + + println!("✓ Retrieved QE identity"); + println!( + " Issuer chain length: {} bytes", + response.issuer_chain.len() + ); + + let identity: serde_json::Value = + serde_json::from_str(&response.enclave_identity_json)?; + + if let Some(enclave_id) = identity["enclaveIdentity"]["id"].as_str() { + println!(" Enclave ID: {}", enclave_id); + } + + if let Some(version) = identity["enclaveIdentity"]["version"].as_u64() { + println!(" Version: {}", version); + } + + if let Some(mrsigner) = identity["enclaveIdentity"]["mrsigner"].as_str() { + println!(" MRSIGNER: {}...", &mrsigner[..16]); + } + } + Err(e) => { + println!("✗ Failed to get QE identity: {:?}", e); + } + } + + println!(); + + // Example 3: Check certificate revocation + println!("Example 3: Checking certificate revocation status"); + println!("================================================"); + + match client.get_pck_crl(CaType::Processor, None).await { + Ok(response) => { + // Critical: Check that issuer chain is present for CRL verification + if response.issuer_chain.is_empty() { + println!("✗ Error: Empty issuer chain - cannot verify CRL signature!"); + return Ok(()); + } + + println!("✓ Retrieved PCK CRL"); + println!( + " Issuer chain length: {} bytes", + response.issuer_chain.len() + ); + + let crl_pem = String::from_utf8_lossy(&response.crl_data); + + // In real usage, you would parse this CRL and check if a certificate is revoked + if crl_pem.contains("BEGIN X509 CRL") { + println!(" CRL format: PEM"); + println!(" CRL size: {} bytes", crl_pem.len()); + + // Count the revoked certificates (naive approach) + let revoked_count = crl_pem.matches("Serial Number:").count(); + println!(" Approximate revoked certificates: {}", revoked_count); + } + } + Err(e) => { + println!("✗ Failed to get CRL: {:?}", e); + } + } + + println!(); + + // Example 4: Early update for testing + println!("Example 4: Getting early TCB update (for testing)"); + println!("================================================"); + + match client + .get_sgx_tcb_info(fmspc, Some(UpdateType::Early), None) + .await + { + Ok(response) => { + println!("✓ Retrieved early TCB update"); + + let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?; + + if let Some(next_update) = tcb_info["tcbInfo"]["nextUpdate"].as_str() { + println!(" Next update: {}", next_update); + } + } + Err(IntelApiError::ApiError { status, .. }) if status.as_u16() == 404 => { + println!(" No early update available (this is normal)"); + } + Err(e) => { + println!("✗ Error: {:?}", e); + } + } + + println!(); + println!("Done! These examples show common patterns for attestation verification."); + + Ok(()) +} diff --git a/crates/intel-dcap-api/examples/fetch_test_data.rs b/crates/intel-dcap-api/examples/fetch_test_data.rs new file mode 100644 index 0000000..be32fdf --- /dev/null +++ b/crates/intel-dcap-api/examples/fetch_test_data.rs @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use base64::{engine::general_purpose, Engine as _}; +use intel_dcap_api::{ApiClient, ApiVersion, CaType, CrlEncoding, PlatformFilter, UpdateType}; +use std::{fs, path::Path}; + +/// Fetch real data from Intel API and save it as JSON files +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create test data directory + let test_data_dir = Path::new("tests/test_data"); + fs::create_dir_all(test_data_dir)?; + + let client = ApiClient::new()?; + + println!("Fetching real test data from Intel API..."); + + // Keep track of successful fetches + let mut successes: Vec = Vec::new(); + let mut failures: Vec = Vec::new(); + + // 1. Fetch SGX TCB info + println!("\n1. Fetching SGX TCB info..."); + match client + .get_sgx_tcb_info("00606A6A0000", Some(UpdateType::Standard), None) + .await + { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_tcb_info.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX TCB info".to_string()); + } + Err(e) => { + failures.push(format!("SGX TCB info: {}", e)); + } + } + + // 2. Fetch TDX TCB info + println!("\n2. Fetching TDX TCB info..."); + match client + .get_tdx_tcb_info("00806F050000", Some(UpdateType::Standard), None) + .await + { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("tdx_tcb_info.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("TDX TCB info".to_string()); + } + Err(e) => { + failures.push(format!("TDX TCB info: {}", e)); + } + } + + // 3. Fetch PCK CRL for processor + println!("\n3. Fetching PCK CRL (processor)..."); + match client.get_pck_crl(CaType::Processor, None).await { + Ok(response) => { + let crl_string = String::from_utf8_lossy(&response.crl_data); + let data = serde_json::json!({ + "crl_data": crl_string, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("pck_crl_processor.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("PCK CRL (processor)".to_string()); + } + Err(e) => { + failures.push(format!("PCK CRL (processor): {}", e)); + } + } + + // 4. Fetch PCK CRL for platform + println!("\n4. Fetching PCK CRL (platform)..."); + match client.get_pck_crl(CaType::Platform, None).await { + Ok(response) => { + let crl_string = String::from_utf8_lossy(&response.crl_data); + let data = serde_json::json!({ + "crl_data": crl_string, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("pck_crl_platform.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("PCK CRL (platform)".to_string()); + } + Err(e) => { + failures.push(format!("PCK CRL (platform): {}", e)); + } + } + + // 5. Fetch SGX QE identity + println!("\n5. Fetching SGX QE identity..."); + match client.get_sgx_qe_identity(None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "enclave_identity_json": response.enclave_identity_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_qe_identity.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX QE identity".to_string()); + } + Err(e) => { + failures.push(format!("SGX QE identity: {}", e)); + } + } + + // 6. Fetch SGX QVE identity + println!("\n6. Fetching SGX QVE identity..."); + match client.get_sgx_qve_identity(None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "enclave_identity_json": response.enclave_identity_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_qve_identity.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX QVE identity".to_string()); + } + Err(e) => { + failures.push(format!("SGX QVE identity: {}", e)); + } + } + + // 7. Fetch TDX QE identity + println!("\n7. Fetching TDX QE identity..."); + match client.get_tdx_qe_identity(None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "enclave_identity_json": response.enclave_identity_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("tdx_qe_identity.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("TDX QE identity".to_string()); + } + Err(e) => { + failures.push(format!("TDX QE identity: {}", e)); + } + } + + // 8. Try an alternative FMSPC + println!("\n8. Fetching alternative SGX TCB info..."); + match client.get_sgx_tcb_info("00906ED50000", None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_tcb_info_alt.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("Alternative SGX TCB info".to_string()); + } + Err(e) => { + failures.push(format!("Alternative SGX TCB info: {}", e)); + } + } + + // 9. Fetch PCK certificate + println!("\n9. Attempting to fetch PCK certificate..."); + let ppid = "3d6dd97e96f84536a2267e727dd860e4fdd3ffa3e319db41e8f69c9a43399e7b7ce97d7eb3bd05b0a58bdb5b90a0e218"; + let cpusvn = "0606060606060606060606060606060606060606060606060606060606060606"; + let pcesvn = "0a00"; + let pceid = "0000"; + + match client + .get_pck_certificate_by_ppid(ppid, cpusvn, pcesvn, pceid, None, None) + .await + { + Ok(response) => { + let data = serde_json::json!({ + "pck_cert_pem": response.pck_cert_pem, + "issuer_chain": response.issuer_chain, + "tcbm": response.tcbm, + "fmspc": response.fmspc, + }); + fs::write( + test_data_dir.join("pck_cert.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("PCK certificate".to_string()); + } + Err(e) => { + failures.push(format!("PCK certificate: {}", e)); + } + } + + // 10. Fetch SGX QAE identity + println!("\n10. Fetching SGX QAE identity..."); + match client.get_sgx_qae_identity(None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "enclave_identity_json": response.enclave_identity_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_qae_identity.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX QAE identity".to_string()); + } + Err(e) => { + failures.push(format!("SGX QAE identity: {}", e)); + } + } + + // 11. Fetch FMSPCs + println!("\n11. Fetching FMSPCs..."); + match client.get_fmspcs(Some(PlatformFilter::All)).await { + Ok(fmspcs_json) => { + let data = serde_json::json!({ + "fmspcs_json": fmspcs_json, + }); + fs::write( + test_data_dir.join("fmspcs.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("FMSPCs".to_string()); + } + Err(e) => { + failures.push(format!("FMSPCs: {}", e)); + } + } + + // 12. Fetch SGX TCB evaluation data numbers + println!("\n12. Fetching SGX TCB evaluation data numbers..."); + match client.get_sgx_tcb_evaluation_data_numbers().await { + Ok(response) => { + let data = serde_json::json!({ + "tcb_evaluation_data_numbers_json": response.tcb_evaluation_data_numbers_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_tcb_eval_nums.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX TCB evaluation data numbers".to_string()); + } + Err(e) => { + failures.push(format!("SGX TCB evaluation data numbers: {}", e)); + } + } + + // 13. Fetch TDX TCB evaluation data numbers + println!("\n13. Fetching TDX TCB evaluation data numbers..."); + match client.get_tdx_tcb_evaluation_data_numbers().await { + Ok(response) => { + let data = serde_json::json!({ + "tcb_evaluation_data_numbers_json": response.tcb_evaluation_data_numbers_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("tdx_tcb_eval_nums.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("TDX TCB evaluation data numbers".to_string()); + } + Err(e) => { + failures.push(format!("TDX TCB evaluation data numbers: {}", e)); + } + } + + // 14. Fetch PCK CRL with DER encoding + println!("\n14. Fetching PCK CRL (processor, DER encoding)..."); + match client + .get_pck_crl(CaType::Processor, Some(CrlEncoding::Der)) + .await + { + Ok(response) => { + // For DER, save as base64 + let crl_base64 = general_purpose::STANDARD.encode(&response.crl_data); + let data = serde_json::json!({ + "crl_data_base64": crl_base64, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("pck_crl_processor_der.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("PCK CRL (processor, DER)".to_string()); + } + Err(e) => { + failures.push(format!("PCK CRL (processor, DER): {}", e)); + } + } + + // 15. Try different update types + println!("\n15. Fetching SGX TCB info with Early update..."); + match client + .get_sgx_tcb_info("00906ED50000", Some(UpdateType::Early), None) + .await + { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_tcb_info_early.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX TCB info (Early update)".to_string()); + } + Err(e) => { + failures.push(format!("SGX TCB info (Early update): {}", e)); + } + } + + // 16. Try with specific TCB evaluation data number + println!("\n16. Fetching TDX TCB info with specific evaluation number..."); + match client + .get_tdx_tcb_info("00806F050000", None, Some(17)) + .await + { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("tdx_tcb_info_eval17.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("TDX TCB info (eval number 17)".to_string()); + } + Err(e) => { + failures.push(format!("TDX TCB info (eval number 17): {}", e)); + } + } + + // 17. Try different FMSPCs + println!("\n17. Fetching more SGX TCB info variations..."); + let test_fmspcs = vec!["00906ED50000", "00906C0F0000", "00A06F050000"]; + for fmspc in test_fmspcs { + match client.get_sgx_tcb_info(fmspc, None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join(format!("sgx_tcb_info_{}.json", fmspc)), + serde_json::to_string_pretty(&data)?, + )?; + successes.push(format!("SGX TCB info (FMSPC: {})", fmspc)); + } + Err(e) => { + failures.push(format!("SGX TCB info (FMSPC: {}): {}", fmspc, e)); + } + } + } + + // 18. Try FMSPCs with different platform filters + println!("\n18. Fetching FMSPCs with different platform filters..."); + match client.get_fmspcs(None).await { + Ok(fmspcs_json) => { + let data = serde_json::json!({ + "fmspcs_json": fmspcs_json, + }); + fs::write( + test_data_dir.join("fmspcs_no_filter.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("FMSPCs (no filter)".to_string()); + } + Err(e) => { + failures.push(format!("FMSPCs (no filter): {}", e)); + } + } + + match client.get_fmspcs(Some(PlatformFilter::All)).await { + Ok(fmspcs_json) => { + let data = serde_json::json!({ + "fmspcs_json": fmspcs_json, + }); + fs::write( + test_data_dir.join("fmspcs_all_platforms.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("FMSPCs (all platforms)".to_string()); + } + Err(e) => { + failures.push(format!("FMSPCs (all platforms): {}", e)); + } + } + + // 19. Try PCK certificates with different parameters (encrypted PPID) + println!("\n19. Attempting to fetch PCK certificates with different params..."); + // Try with a different encrypted PPID format + let encrypted_ppid = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + let pceid = "0000"; + + match client + .get_pck_certificates_by_ppid(encrypted_ppid, pceid, None, None) + .await + { + Ok(response) => { + let data = serde_json::json!({ + "pck_certificates_json": response.pck_certs_json, + "issuer_chain": response.issuer_chain, + "fmspc": response.fmspc, + }); + fs::write( + test_data_dir.join("pck_certificates.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("PCK certificates (by PPID)".to_string()); + } + Err(e) => { + failures.push(format!("PCK certificates (by PPID): {}", e)); + } + } + + // 20. Try TDX TCB info with different FMSPCs + println!("\n20. Fetching TDX TCB info variations..."); + let tdx_fmspcs = vec!["00806F050000", "00A06F050000", "00606A0000000"]; + for fmspc in tdx_fmspcs { + match client.get_tdx_tcb_info(fmspc, None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join(format!("tdx_tcb_info_{}.json", fmspc)), + serde_json::to_string_pretty(&data)?, + )?; + successes.push(format!("TDX TCB info (FMSPC: {})", fmspc)); + } + Err(e) => { + failures.push(format!("TDX TCB info (FMSPC: {}): {}", fmspc, e)); + } + } + } + + // 21. Try with V3 API for some endpoints + println!("\n21. Testing V3 API endpoints..."); + let v3_client = + ApiClient::new_with_options("https://api.trustedservices.intel.com", ApiVersion::V3)?; + + match v3_client.get_sgx_tcb_info("00906ED50000", None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "tcb_info_json": response.tcb_info_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_tcb_info_v3.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX TCB info (V3 API)".to_string()); + } + Err(e) => { + failures.push(format!("SGX TCB info (V3 API): {}", e)); + } + } + + match v3_client.get_sgx_qe_identity(None, None).await { + Ok(response) => { + let data = serde_json::json!({ + "enclave_identity_json": response.enclave_identity_json, + "issuer_chain": response.issuer_chain, + }); + fs::write( + test_data_dir.join("sgx_qe_identity_v3.json"), + serde_json::to_string_pretty(&data)?, + )?; + successes.push("SGX QE identity (V3 API)".to_string()); + } + Err(e) => { + failures.push(format!("SGX QE identity (V3 API): {}", e)); + } + } + + println!("\n\nTest data fetching complete!"); + println!("\nSuccessful fetches:"); + for s in &successes { + println!(" ✓ {}", s); + } + + if !failures.is_empty() { + println!("\nFailed fetches:"); + for f in &failures { + println!(" ✗ {}", f); + } + } + + println!("\nData saved in: {}", test_data_dir.display()); + + Ok(()) +} diff --git a/crates/intel-dcap-api/examples/integration_test.rs b/crates/intel-dcap-api/examples/integration_test.rs new file mode 100644 index 0000000..b88088f --- /dev/null +++ b/crates/intel-dcap-api/examples/integration_test.rs @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use intel_dcap_api::{ + ApiClient, ApiVersion, CaType, CrlEncoding, IntelApiError, PlatformFilter, UpdateType, +}; +use std::time::Duration; +use tokio::time::sleep; + +/// Comprehensive integration test example demonstrating most Intel DCAP API client functions +/// +/// This example shows how to use various endpoints of the Intel Trusted Services API. +/// Note: Some operations may fail with 404 or 400 errors if the data doesn't exist on Intel's servers. +#[tokio::main] +async fn main() -> Result<(), Box> { + println!("=== Intel DCAP API Integration Test Example ===\n"); + + // Create clients for both V3 and V4 APIs + let v4_client = ApiClient::new()?; + let v3_client = + ApiClient::new_with_options("https://api.trustedservices.intel.com", ApiVersion::V3)?; + + // Track successes and failures + let mut results = Vec::new(); + + // Test FMSPC - commonly used for TCB lookups + let test_fmspc = "00906ED50000"; + let test_fmspc_tdx = "00806F050000"; + + println!("1. Testing TCB Info Endpoints..."); + println!("================================"); + + // 1.1 SGX TCB Info (V4) + print!(" - SGX TCB Info (V4): "); + match v4_client.get_sgx_tcb_info(test_fmspc, None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX TCB Info (V4)", false)); + } else { + println!("✓ Success"); + println!(" FMSPC: {}", test_fmspc); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?; + if let Some(version) = tcb_info["tcbInfo"]["version"].as_u64() { + println!(" TCB Info Version: {}", version); + } + results.push(("SGX TCB Info (V4)", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX TCB Info (V4)", false)); + } + } + + // Add small delay between requests to be nice to the API + sleep(Duration::from_millis(100)).await; + + // 1.2 SGX TCB Info (V3) + print!(" - SGX TCB Info (V3): "); + match v3_client.get_sgx_tcb_info(test_fmspc, None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX TCB Info (V3)", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + results.push(("SGX TCB Info (V3)", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX TCB Info (V3)", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 1.3 TDX TCB Info + print!(" - TDX TCB Info: "); + match v4_client.get_tdx_tcb_info(test_fmspc_tdx, None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("TDX TCB Info", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?; + if let Some(id) = tcb_info["tcbInfo"]["id"].as_str() { + println!(" Platform: {}", id); + } + results.push(("TDX TCB Info", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("TDX TCB Info", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 1.4 SGX TCB Info with Early Update + print!(" - SGX TCB Info (Early Update): "); + match v4_client + .get_sgx_tcb_info(test_fmspc, Some(UpdateType::Early), None) + .await + { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX TCB Info (Early)", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + results.push(("SGX TCB Info (Early)", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX TCB Info (Early)", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + println!("\n2. Testing Enclave Identity Endpoints..."); + println!("========================================"); + + // 2.1 SGX QE Identity + print!(" - SGX QE Identity: "); + match v4_client.get_sgx_qe_identity(None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX QE Identity", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + let identity: serde_json::Value = + serde_json::from_str(&response.enclave_identity_json)?; + if let Some(id) = identity["enclaveIdentity"]["id"].as_str() { + println!(" Enclave ID: {}", id); + } + results.push(("SGX QE Identity", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX QE Identity", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 2.2 SGX QVE Identity + print!(" - SGX QVE Identity: "); + match v4_client.get_sgx_qve_identity(None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX QVE Identity", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + results.push(("SGX QVE Identity", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX QVE Identity", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 2.3 SGX QAE Identity + print!(" - SGX QAE Identity: "); + match v4_client.get_sgx_qae_identity(None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX QAE Identity", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + results.push(("SGX QAE Identity", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX QAE Identity", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 2.4 TDX QE Identity (V4 only) + print!(" - TDX QE Identity: "); + match v4_client.get_tdx_qe_identity(None, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("TDX QE Identity", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + results.push(("TDX QE Identity", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("TDX QE Identity", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + println!("\n3. Testing PCK CRL Endpoints..."); + println!("================================"); + + // 3.1 PCK CRL - Processor (PEM) + print!(" - PCK CRL (Processor, PEM): "); + match v4_client.get_pck_crl(CaType::Processor, None).await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("PCK CRL (Processor)", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + let crl_str = String::from_utf8_lossy(&response.crl_data); + if crl_str.contains("BEGIN X509 CRL") { + println!(" Format: PEM"); + } + results.push(("PCK CRL (Processor)", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("PCK CRL (Processor)", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 3.2 PCK CRL - Platform (DER) + print!(" - PCK CRL (Platform, DER): "); + match v4_client + .get_pck_crl(CaType::Platform, Some(CrlEncoding::Der)) + .await + { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("PCK CRL (Platform, DER)", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + println!(" CRL size: {} bytes", response.crl_data.len()); + results.push(("PCK CRL (Platform, DER)", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("PCK CRL (Platform, DER)", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + println!("\n4. Testing FMSPC Endpoints (V4 only)..."); + println!("======================================="); + + // 4.1 Get FMSPCs (no filter) + print!(" - Get FMSPCs (no filter): "); + match v4_client.get_fmspcs(None).await { + Ok(fmspcs_json) => { + println!("✓ Success"); + let fmspcs: serde_json::Value = serde_json::from_str(&fmspcs_json)?; + if let Some(arr) = fmspcs.as_array() { + println!(" Total FMSPCs: {}", arr.len()); + // Show first few FMSPCs + for (i, fmspc) in arr.iter().take(3).enumerate() { + if let (Some(fmspc_val), Some(platform)) = + (fmspc["fmspc"].as_str(), fmspc["platform"].as_str()) + { + println!(" [{}] {} - {}", i + 1, fmspc_val, platform); + } + } + if arr.len() > 3 { + println!(" ... and {} more", arr.len() - 3); + } + } + results.push(("Get FMSPCs", true)); + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("Get FMSPCs", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 4.2 Get FMSPCs with platform filter + print!(" - Get FMSPCs (All platforms): "); + match v4_client.get_fmspcs(Some(PlatformFilter::All)).await { + Ok(_) => { + println!("✓ Success"); + results.push(("Get FMSPCs (filtered)", true)); + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("Get FMSPCs (filtered)", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + println!("\n5. Testing TCB Evaluation Data Numbers (V4 only)..."); + println!("==================================================="); + + // 5.1 SGX TCB Evaluation Data Numbers + print!(" - SGX TCB Evaluation Data Numbers: "); + match v4_client.get_sgx_tcb_evaluation_data_numbers().await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("SGX TCB Eval Numbers", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + let data: serde_json::Value = + serde_json::from_str(&response.tcb_evaluation_data_numbers_json)?; + if let Some(sgx_data) = data.get("sgx") { + println!( + " SGX entries: {}", + sgx_data.as_array().map(|a| a.len()).unwrap_or(0) + ); + } + results.push(("SGX TCB Eval Numbers", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("SGX TCB Eval Numbers", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + // 5.2 TDX TCB Evaluation Data Numbers + print!(" - TDX TCB Evaluation Data Numbers: "); + match v4_client.get_tdx_tcb_evaluation_data_numbers().await { + Ok(response) => { + if response.issuer_chain.is_empty() { + println!("✗ Failed: Empty issuer chain"); + results.push(("TDX TCB Eval Numbers", false)); + } else { + println!("✓ Success"); + println!(" Issuer chain: {} bytes", response.issuer_chain.len()); + let data: serde_json::Value = + serde_json::from_str(&response.tcb_evaluation_data_numbers_json)?; + if let Some(tdx_data) = data.get("tdx") { + println!( + " TDX entries: {}", + tdx_data.as_array().map(|a| a.len()).unwrap_or(0) + ); + } + results.push(("TDX TCB Eval Numbers", true)); + } + } + Err(e) => { + println!("✗ Failed: {:?}", e); + results.push(("TDX TCB Eval Numbers", false)); + } + } + + sleep(Duration::from_millis(100)).await; + + println!("\n6. Testing PCK Certificate Endpoints..."); + println!("======================================="); + + /* // 6.1 PCK Certificate by PPID (usually requires valid data) + print!(" - PCK Certificate by PPID: "); + let test_ppid = "0000000000000000000000000000000000000000000000000000000000000000"; + let test_cpusvn = "00000000000000000000000000000000"; + let test_pcesvn = "0000"; + let test_pceid = "0000"; + + match v4_client + .get_pck_certificate_by_ppid(test_ppid, test_cpusvn, test_pcesvn, test_pceid, None, None) + .await + { + Ok(_) => { + println!("✓ Success"); + results.push(("PCK Certificate", true)); + } + Err(e) => { + // Expected to fail with test data + match &e { + IntelApiError::ApiError { status, .. } => { + println!("✗ Failed (Expected): HTTP {}", status); + } + _ => println!("✗ Failed: {:?}", e), + } + results.push(("PCK Certificate", false)); + } + } + + sleep(Duration::from_millis(100)).await; + */ + println!("\n7. Testing API Version Compatibility..."); + println!("======================================="); + + // 7.1 Try V4-only endpoint on V3 + print!(" - V4-only endpoint on V3 (should fail): "); + match v3_client.get_fmspcs(None).await { + Ok(_) => { + println!("✗ Unexpected success!"); + results.push(("V3/V4 compatibility check", false)); + } + Err(IntelApiError::UnsupportedApiVersion(_)) => { + println!("✓ Correctly rejected"); + results.push(("V3/V4 compatibility check", true)); + } + Err(e) => { + println!("✗ Wrong error: {:?}", e); + results.push(("V3/V4 compatibility check", false)); + } + } + + println!("\n8. Testing Error Handling..."); + println!("============================"); + + // 8.1 Invalid FMSPC + print!(" - Invalid FMSPC format: "); + match v4_client.get_sgx_tcb_info("invalid", None, None).await { + Ok(_) => { + println!("✗ Unexpected success!"); + results.push(("Error handling", false)); + } + Err(IntelApiError::ApiError { + status, + error_code, + error_message, + .. + }) => { + println!("✓ Correctly handled"); + println!(" Status: {}", status); + if let Some(code) = error_code { + println!(" Error Code: {}", code); + } + if let Some(msg) = error_message { + println!(" Error Message: {}", msg); + } + results.push(("Error handling", true)); + } + Err(e) => { + println!("✗ Unexpected error: {:?}", e); + results.push(("Error handling", false)); + } + } + + // Summary + println!("\n\n=== Summary ==="); + println!("==============="); + + let total = results.len(); + let successful = results.iter().filter(|(_, success)| *success).count(); + let failed = total - successful; + + println!("Total tests: {}", total); + println!( + "Successful: {} ({}%)", + successful, + (successful * 100) / total + ); + println!("Failed: {} ({}%)", failed, (failed * 100) / total); + + println!("\nDetailed Results:"); + for (test, success) in &results { + println!(" {} {}", if *success { "✓" } else { "✗" }, test); + } + + println!("\nNote: Some failures are expected due to:"); + println!("- Test data not existing on Intel servers"); + println!("- PCK operations requiring valid platform data"); + println!("- Subscription key requirements for certain endpoints"); + + Ok(()) +} diff --git a/crates/intel-dcap-api/specs/API spec V3.md b/crates/intel-dcap-api/specs/API spec V3.md new file mode 100644 index 0000000..59667cd --- /dev/null +++ b/crates/intel-dcap-api/specs/API spec V3.md @@ -0,0 +1,694 @@ +# Intel® SGX and Intel® TDX services - V3 API Documentation + +## Intel® SGX and Intel® TDX Registration Service for Scalable Platforms + +The API exposed by the Intel SGX registration service allows registering an Intel® SGX platform with multiple processor +packages as a single platform instance, which can be remotely attested as a single entity later on[cite: 1]. The minimum +version of the TLS protocol supported by the service is 1.2; any connection attempts with previous versions of TLS/SSL +will be dropped by the server[cite: 2]. + +### Register Platform + +This API allows registering a multi-package SGX platform, covering initial registration and TCB Recovery[cite: 2]. +During registration, the platform manifest is authenticated by the Registration Service to verify it originates from a +genuine, non-revoked SGX platform[cite: 2]. If the platform configuration is successfully verified, platform +provisioning root keys are stored in the backend[cite: 2]. + +Stored platform provisioning root keys are later used to derive the public parts of Provisioning Certification Keys ( +PCKs)[cite: 2]. These PCKs are distributed as x.509 certificates by the Provisioning Certification Service for Intel SGX +and are used during the remote attestation of the platform[cite: 3]. + +#### POST `https://api.trustedservices.intel.com/sgx/registration/v1/platform` + +**Request** + +**Headers** + +Besides the headers explicitly mentioned below, the HTTP request may contain standard HTTP headers (e.g., +Content-Length)[cite: 3]. + +| Name | Required | Value | Description | +|:-------------|:---------|:---------------------------|:----------------------------------------| +| Content-Type | True | `application/octet-stream` | MIME type of the request body[cite: 4]. | + +**Body** + +The body is a binary representation of the Platform Manifest structure – an opaque blob representing a registration +manifest for a multi-package platform[cite: 5]. It contains platform provisioning root keys established by the platform +instance and data required to authenticate the platform as genuine and non-revoked[cite: 5]. + +**Example Request** + +```bash +curl -H "Content-Type: application/octet-stream" --data-binary @platform_manifest POST "[https://api.trustedservices.intel.com/sgx/registration/v1/platform](https://api.trustedservices.intel.com/sgx/registration/v1/platform)" +```` + +**Response** + +**Model** + +The response is a Hex-encoded representation of the PPID for the registered platform instance (only if the HTTP Status +Code is 201; otherwise, the body is empty). + +**Example Response** + +``` +001122334455667788AABBCCDDEEFF +``` + +**Status Codes** + +| Code | Headers | Body | Description | +|:-----|:--------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 201 | Request-ID: Randomly generated identifier for each request (for troubleshooting purposes). | Hex-encoded representation of PPID. | Operation successful (new platform instance registered). A new platform instance has been registered[cite: 5]. | +| 400 | Request-ID: Randomly generated identifier[cite: 6]. \ Error-Code and Error-Message: Additional details about the error[cite: 9]. | | Invalid Platform Manifest[cite: 8]. The request might be malformed[cite: 6], intended for a different server[cite: 7], contain an invalid/revoked package[cite: 7], an unrecognized package[cite: 7], an incompatible package[cite: 7], an invalid manifest[cite: 7], or violate a key caching policy[cite: 8]. The client should not repeat the request without modifications[cite: 9]. | +| 415 | Request-ID: Randomly generated identifier[cite: 10]. | | MIME type specified in the request is not supported[cite: 10]. | +| 500 | Request-ID: Randomly generated identifier[cite: 10]. | | Internal server error occurred[cite: 10]. | +| 503 | Request-ID: Randomly generated identifier[cite: 10]. | | Server is currently unable to process the request. The client should try again later[cite: 11]. | + +----- + +### Add Package + +This API adds new package(s) to an already registered platform instance[cite: 11]. A subscription is required[cite: 11]. +If successful, a Platform Membership Certificate is generated for each processor package in the Add Request[cite: 12]. + +#### POST `https://api.trustedservices.intel.com/sgx/registration/v1/package` + +**Request** + +**Headers** + +| Name | Required | Value | Description | +|:--------------------------|:---------|:---------------------------|:--------------------------------------------------------------------------------| +| Ocp-Apim-Subscription-Key | True | | Subscription key providing access to this API, found in your Profile[cite: 14]. | +| Content-Type | True | `application/octet-stream` | MIME type of the request body[cite: 14]. | + +**Body** + +Binary representation of the Add Request structure – an opaque blob for adding new processor packages to an existing +platform instance. + +**Example Request** + +```bash +curl -H "Content-Type: application/octet-stream" --data-binary @add_package POST "[https://api.trustedservices.intel.com/sgx/registration/v1/package](https://api.trustedservices.intel.com/sgx/registration/v1/package)" -H "Ocp-Apim-Subscription-Key: {subscription_key}" +``` + +**Response** + +**Model** + +For a 200 HTTP Status Code, the response is a fixed-size array (8 elements) containing binary representations of +Platform Membership Certificate structures[cite: 15]. Certificates are populated sequentially, starting at index 0, with +the rest of the elements zeroed[cite: 15]. + +**Example Response (hex-encoded)** + +``` +E4B0E8B80F8B49184488F77273550840984816854488B7CFRP... +``` + +**Status Codes** + +| Code | Headers | Body | Description | +|:-----|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 200 | Content-Type: `application/octet-stream`[cite: 17]. \ Request-ID: Random identifier[cite: 17]. \ CertificateCount: Number of certificates returned[cite: 17]. | Fixed-size array of Platform Membership Certificates[cite: 17]. | Operation successful. Packages added[cite: 17]. | +| 400 | Request-ID: Random identifier[cite: 17]. \ Error-Code and Error-Message: Details on the error[cite: 17]. | | Invalid Add Request Payload[cite: 17]. Can be due to malformed syntax, platform not found, invalid/revoked/unrecognized package, or invalid AddRequest[cite: 17]. | +| 401 | Request-ID: Random identifier[cite: 17]. | | Failed to authenticate or authorize the request[cite: 17]. | +| 415 | Request-ID: Random identifier[cite: 17]. | | MIME type specified is not supported[cite: 17]. | +| 500 | Request-ID: Random identifier[cite: 17]. | | Internal server error occurred[cite: 17]. | +| 503 | Request-ID: Random identifier[cite: 17]. | | Server is currently unable to process the request[cite: 17]. | + +----- + +## Intel® SGX Provisioning Certification Service for ECDSA Attestation + +Download the Provisioning Certification Root CA Certificate (API v3) here: + +* [DER](https://www.google.com/search?q=https://certificates.trustedservices.intel.com/Intel_SGX_Provisioning_Certification_RootCA.cer) [cite: 18] +* [PEM](https://www.google.com/search?q=https://certificates.trustedservices.intel.com/intel_SGX_Provisioning_Certification_RootCA.perm) [cite: 18] + +### Get PCK Certificate V3 + +This API allows requesting a single PCK certificate by specifying PPID and SVNs or Platform Manifest and SVNs[cite: 18]. +A subscription is required[cite: 18]. + +* **Using PPID and SVNs**: + * Single-socket platforms: No prerequisites[cite: 18]. + * Multi-socket platforms: Requires previous registration via `Register Platform` API[cite: 18]. Platform root keys + must be persistently stored[cite: 19], and the `Keys Caching Policy` must be set to `true`[cite: 21]. The service + uses a PCK public key derived from stored keys[cite: 20]. +* **Using Platform Manifest and SVNs**: + * Multi-socket platforms: Does not require previous registration[cite: 21]. It doesn't require keys to be + persistently stored[cite: 22]. The service uses a PCK public key derived from the provided manifest[cite: 23]. + Depending on the `Keys Caching Policy`, keys might be stored[cite: 24]. + * **Direct Registration** (`Register Platform` first): Sets policy to always store keys[cite: 25]. Keys are + stored when the manifest is sent[cite: 26]. `CachedKeys` flag in PCK Certificates is set to `true`[cite: 27]. + * **Indirect Registration** (`Get PCK Certificate(s)` first): Sets policy to never store keys[cite: 27]. Keys + are discarded after use[cite: 28]. Standard metadata is stored, but `Register Platform` cannot be used + anymore[cite: 29]. `CachedKeys` flag is set to `false`[cite: 30]. + +The PCS returns the PCK Certificate representing the TCB level with the highest security posture based on CPUSVN and PCE +ISVSVN[cite: 30]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcert` + +**Request** + +| Name | Type | Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------|:---------|:--------------------|:-----------------------------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 32]. | +| PPID-Encryption-Key | String | Header | False | | Type of key for PPID encryption (Default: `RSA-3072`)[cite: 32]. | +| encrypted\_ppid | String | Query | True | `[0-9a-fA-F]{768}$` | Base16-encoded PPID (encrypted with PPIDEK)[cite: 32]. | +| cpusvn | String | Query | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN (16 bytes)[cite: 32]. | +| pcesvn | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCESVN (2 bytes, little endian)[cite: 32]. | +| pceid | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID (2 bytes, little endian)[cite: 32]. | + +**Example Request** + +```bash +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcert?encrypted_ppid=...&cpusvn=...&pcesvn=...&pceid=](https://api.trustedservices.intel.com/sgx/certification/v3/pckcert?encrypted_ppid=...&cpusvn=...&pcesvn=...&pceid=)..." -H "Ocp-Apim-Subscription-Key: {subscription_key}" +``` + +**Response**: Response description can be +found [here](https://www.google.com/search?q=%23response-get-and-post-1)[cite: 34]. + +#### POST `https://api.trustedservices.intel.com/sgx/certification/v3/pckcert` + +**Request** + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:-----------------------------|:---------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 35]. | +| Content-Type | String | Header | True | | Content Type (`application/json`)[cite: 35]. | +| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16882,112884}$` | Base16-encoded Platform Manifest[cite: 35]. | +| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN[cite: 35]. | +| pcesvn | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCESVN[cite: 35]. | +| pceid | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 35]. | + +**Body** + +```json +{ + "platformManifest": "...", + "cpusvn": "...", + "pcesvn": "...", + "pceid": "..." +} +``` + +**Example Request** + +```bash +curl -X POST -d '{"platformManifest": "...", "cpusvn": "...", "pcesvn": "...", "pceid": "..."}' -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription_key}" "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcert](https://api.trustedservices.intel.com/sgx/certification/v3/pckcert)" +``` + +**Response (GET and POST)** + +**Model**: PckCert (X-PEM-FILE) - PEM-encoded SGX PCK Certificate[cite: 36]. + +**Example Response** + +```pem +-----BEGIN CERTIFICATE----- +... +-----END CERTIFICATE----- +``` + +**Status Codes** + +| Code | Model | Headers | Description | +|:-----|:--------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------| +| 200 | PckCert | Content-Type: `application/x-pem-file`[cite: 36]. \ Request-ID[cite: 36]. \ SGX-PCK-Certificate-Issuer-Chain: URL-encoded issuer chain[cite: 36]. \ SGX-TCBm: Hex-encoded CPUSVN and PCESVN[cite: 37]. \ SGX-FMSPC: Hex-encoded FMSPC[cite: 37]. \ SGX-PCK-Certificate-CA-Type: 'processor' or 'platform'[cite: 39]. \ Warning: Optional message[cite: 39]. | Operation successful[cite: 36]. | +| 400 | | Request-ID[cite: 39]. \ Warning[cite: 39]. | Invalid request parameters[cite: 39]. | +| 401 | | Request-ID[cite: 40]. \ Warning[cite: 40]. | Failed to authenticate or authorize the request[cite: 40]. | +| 404 | | Request-ID[cite: 40]. \ Warning[cite: 40]. | PCK Certificate not found[cite: 40]. Reasons: unsupported PPID/PCE-ID, TCB level too low, or Platform Manifest not registered/updated[cite: 41]. | +| 500 | | Request-ID[cite: 41]. \ Warning[cite: 41]. | Internal server error occurred[cite: 41]. | +| 503 | | Request-ID[cite: 42]. \ Warning[cite: 42]. | Server is currently unable to process the request[cite: 42]. | + +----- + +### Get PCK Certificates V3 + +This API retrieves PCK certificates for all configured TCB levels using PPID or Platform Manifest[cite: 42]. +Subscription required[cite: 42]. + +* **Using PPID**: + * Single-socket platforms: No prerequisites[cite: 43]. + * Multi-socket platforms: Requires prior registration via `Register Platform` API[cite: 44]. Keys must be + persistently stored[cite: 45], and `Keys Caching Policy` must be `true`[cite: 47]. PCS uses stored keys[cite: 46]. +* **Using Platform Manifest**: + * Multi-socket platforms: Does not require prior registration[cite: 47]. Does not require persistent + storage[cite: 48]. PCS uses manifest keys[cite: 49]. Caching policy determines storage[cite: 50]. + * **Direct Registration**: Always stores keys; `CachedKeys` is `true`[cite: 51, 52]. + * **Indirect Registration**: Never stores keys; `CachedKeys` is `false`[cite: 53]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts` + +Retrieves certificates based on encrypted PPID and PCE-ID[cite: 53]. + +**Request** + +| Name | Type | Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------|:---------|:--------------------|:--------------------------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 54]. | +| PPID-Encryption-Key | String | Header | False | | Key type for PPID encryption (Default: `RSA-3072`)[cite: 54]. | +| encrypted\_ppid | String | Query | True | `[0-9a-fA-F]{768}$` | Base16-encoded PPID[cite: 54]. | +| pceid | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 54]. | + +**Example Request** + +```bash +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts?encrypted_ppid=...&pceid=](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts?encrypted_ppid=...&pceid=)..." -H "Ocp-Apim-Subscription-Key: {subscription_key}" +``` + +**Response**: Response description can be +found [here](https://www.google.com/search?q=%23response-get-and-post-2)[cite: 55]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config` + +Retrieves certificates for a specific CPUSVN (multi-package only)[cite: 55]. + +**Request** + +| Name | Type | Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------|:---------|:--------------------|:----------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 56]. | +| PPID-Encryption-Key | String | Header | False | | Key type for PPID encryption[cite: 56]. | +| encrypted\_ppid | String | Query | True | `[0-9a-fA-F]{768}$` | Base16-encoded PPID[cite: 56]. | +| pceid | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 56]. | +| cpusvn | String | Query | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN[cite: 56]. | + +**Example Request** + +```bash +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config?encrypted_ppid=...&pceid=...&cpusvn=](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config?encrypted_ppid=...&pceid=...&cpusvn=)..." -H "Ocp-Apim-Subscription-Key: {subscription_key}" +``` + +**Response**: Response description can be +found [here](https://www.google.com/search?q=%23response-get-and-post-2)[cite: 57]. + +#### POST `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts` + +Retrieves certificates based on Platform Manifest and PCE-ID (multi-package only)[cite: 57]. + +**Request** + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:-----------------------------|:--------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 58]. | +| Content-Type | String | Header | True | `application/json` | Content Type[cite: 58]. | +| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16882,112884}$` | Base16-encoded Platform Manifest[cite: 58]. | +| pceid | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 58]. | + +**Body** + +```json +{ + "platformManifest": "...", + "pceid": "..." +} +``` + +**Example Request** + +```bash +curl -X POST -d '{"platformManifest": "...", "pceid": "..."}' -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription_key}" "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts)" +``` + +**Response**: Response description can be +found [here](https://www.google.com/search?q=%23response-get-and-post-2)[cite: 59]. + +#### POST `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config` + +Retrieves certificates for a specific CPUSVN using Platform Manifest (multi-package only)[cite: 59]. + +**Request** + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:-----------------------------|:--------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 61]. | +| Content-Type | String | Header | True | `application/json` | Content Type[cite: 61]. | +| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16882,112884}$` | Base16-encoded Platform Manifest[cite: 61]. | +| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN[cite: 61]. | +| pceid | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 61]. | + +**Body** + +```json +{ + "platformManifest": "...", + "cpusvn": "...", + "pceid": "..." +} +``` + +**Example Request** + +```bash +curl -X POST -d '{"platformManifest": "...", "cpusvn": "...", "pceid": "..."}' -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription_key}" "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config)" +``` + +**Response (GET and POST)** + +**Model**: PckCerts (JSON) - Array of data structures with `tcb`, `tcm`, and `certificate`[cite: 62]. + +**PckCerts Structure** + +```json +[ + { + "tcb": { + "sgxtcbcomp01svn": 0, + // Integer + "sgxtcbcomp02svn": 0, + // Integer + // ... (03 to 16) + "pcesvn": 0 + // Integer + }, + "tcm": "...", + // String, Hex-encoded TCBm [cite: 63, 64] + "cert": "..." + // String, PEM-encoded certificate or "Not available" [cite: 64] + } +] +``` + +**Example Response** + +```json +[ + { + "tcb": { + "sgxtcbcomp01svn": 0, + "sgxtcbcomp02svn": 0, + "sgxtcbcomp03svn": 0, + "sgxtcbcomp04svn": 0, + "sgxtcbcomp05svn": 0, + "sgxtcbcomp06svn": 0, + "sgxtcbcomp07svn": 0, + "sgxtcbcomp08svn": 0, + "sgxtcbcomp09svn": 0, + "sgxtcbcomp10svn": 0, + "sgxtcbcomp11svn": 0, + "sgxtcbcomp12svn": 0, + "sgxtcbcomp13svn": 0, + "sgxtcbcomp14svn": 0, + "sgxtcbcomp15svn": 0, + "sgxtcbcomp16svn": 0, + "pcesvn": 0 + }, + "tcm": "...", + "cert": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" + } +] +``` + +**Status Codes** + +| Code | Model | Headers | Description | +|:-----|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------| +| 200 | PckCerts | Content-Type: `application/json`[cite: 65]. \ Request-ID[cite: 65]. \ SGX-PCK-Certificate-Issuer-Chain: Issuer chain[cite: 66]. \ SGX-FMSPC[cite: 66]. \ SGX-PCK-Certificate-CA-Type[cite: 66]. \ Warning[cite: 66]. | Operation successful[cite: 65]. | +| 400 | | Request-ID[cite: 67]. \ Warning[cite: 67]. | Invalid request parameters[cite: 67]. | +| 401 | | Request-ID[cite: 68]. \ Warning[cite: 68]. | Failed to authenticate or authorize the request[cite: 68]. | +| 404 | | Request-ID[cite: 69]. \ Warning[cite: 69]. | PCK Certificate not found[cite: 69]. Reasons: PPID/PCE-ID not supported or Platform Manifest not registered[cite: 70]. | +| 500 | | Request-ID[cite: 70]. \ Warning[cite: 70]. | Internal server error occurred[cite: 70]. | +| 503 | | Request-ID[cite: 70]. \ Warning[cite: 70]. | Server is currently unable to process the request[cite: 70]. | + +----- + +### Get Revocation List V3 + +Retrieves the X.509 Certificate Revocation List (CRL) for revoked SGX PCK Certificates[cite: 71]. CRLs are issued by +Intel SGX Processor CA or Platform CA[cite: 71]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcrl` + +**Request** + +| Name | Type | Request Type | Required | Pattern | Description | +|:---------|:-------|:-------------|:---------|:------------|:------------| +| ca | String | Query | True | `(processor | platform)` | CA that issued the CRL[cite: 71]. | +| encoding | String | Query | False | `(pem | der)` | Encoding (Default: PEM)[cite: 71]. | + +**Example Request** + +```bash +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcrl?ca=platform&encoding=der](https://api.trustedservices.intel.com/sgx/certification/v3/pckcrl?ca=platform&encoding=der)" +``` + +**Response** + +**Model**: PckCrl (X-PEM-FILE or PKIX-CRL) - PEM or DER-encoded CRL[cite: 71]. + +**Example Response** + +``` +-----BEGIN X509 CRL----- +... +-----END X509 CRL----- +``` + +**Status Codes** + +| Code | Model | Headers | Description | +|:-----|:-------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------| +| 200 | PckCrl | Content-Type: `application/x-pem-file` (PEM) or `application/pkix-crl` (DER)[cite: 72]. \ Request-ID[cite: 72]. \ SGX-PCK-CRL-Issuer-Chain: Issuer chain[cite: 72]. \ Warning[cite: 72]. | Operation successful[cite: 72]. | +| 400 | | Request-ID[cite: 72]. \ Warning[cite: 73]. | Invalid request parameters[cite: 72]. | +| 401 | | Request-ID[cite: 73]. \ Warning[cite: 73]. | Failed to authenticate or authorize[cite: 73]. | +| 500 | | Request-ID[cite: 73]. \ Warning[cite: 73]. | Internal server error occurred[cite: 73]. | +| 503 | | Request-ID[cite: 73]. \ Warning[cite: 73]. | Server is currently unable to process[cite: 73]. | + +----- + +### Get TCB Info V3 + +Retrieves SGX TCB information for a given FMSPC[cite: 74]. + +**Algorithm for TCB Status:** + +1. Retrieve FMSPC from the SGX PCK Certificate[cite: 74]. +2. Retrieve TCB Info matching the FMSPC[cite: 75]. +3. Iterate through the sorted TCB Levels[cite: 75]: + * Compare all SGX TCB Comp SVNs (01-16) from the certificate with TCB Level values[cite: 76]. If all are \>=, + proceed[cite: 76]. Otherwise, move to the next item[cite: 76]. + * Compare PCESVN from the certificate with the TCB Level value[cite: 77]. If \>=, read the status[cite: 77]. + Otherwise, move to the next item[cite: 78]. +4. If no match is found, the TCB Level is not supported[cite: 78]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/tcb` + +**Request** + +| Name | Type | Request Type | Required | Pattern | Description | +|:------------------------|:-------|:-------------|:---------|:-------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| fmspc | String | Query | True | `[0-9a-fA-F]{12}$` | Base16-encoded FMSPC (6 bytes)[cite: 81]. | +| update | String | Query | False | `(early | standard)` | Update type (Default: standard). 'early' provides early access, 'standard' provides standard access[cite: 81]. Cannot be used with `tcbEvaluationDataNumber`[cite: 81]. | +| tcbEvaluationDataNumber | Number | Query | False | `\d+$` | Specifies a TCB Evaluation Data Number. Allows fetching specific versions; returns 410 if \< M, 404 if \> N[cite: 81]. Cannot be used with `update`[cite: 81]. | + +**Example Requests** + +```bash +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&update=early](https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&update=early)" +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&tcbEvaluationDataNumber=](https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&tcbEvaluationDataNumber=)..." +``` + +**Response** + +**Model**: TcbInfoV2 (JSON) - SGX TCB Info[cite: 82]. + +**TcbInfoV2 Structure** + +* `version`: Integer[cite: 83]. +* `issueDate`: String (date-time, ISO 8601 UTC)[cite: 84]. +* `nextUpdate`: String (date-time, ISO 8601 UTC)[cite: 85]. +* `fmspc`: String (Base16-encoded FMSPC)[cite: 85]. +* `pceId`: String (Base16-encoded PCE-ID)[cite: 85]. +* `tcbType`: Integer[cite: 85]. +* `tcbEvaluationDataNumber`: Integer, monotonically increasing sequence number for TCB evaluation data set + updates[cite: 86]. Synchronized across TCB Info and Identities[cite: 86]. Helps determine which data supersedes + another[cite: 87]. +* `tcbLevels`: Array of TCB level objects[cite: 87]. + * `tcb`: Object with `sgxtcbcompXXsvn` (Integer) and `pcesvn` (Integer)[cite: 87]. + * `tcbDate`: String (date-time, ISO 8601 UTC)[cite: 89]. If advisories exist after this date with enforced + mitigations, status won't be `UpToDate`[cite: 88]. + * `tcbStatus`: String (`UpToDate`, `HardeningNeeded`, `ConfigurationNeeded`, `ConfigurationAndHardeningNeeded`, + `OutOfDate`, `OutOfDateConfigurationNeeded`, `Revoked`)[cite: 90, 91, 92]. + * `advisoryIDs`: Array of strings (e.g., `INTEL-SA-XXXXX`, `INTEL-DOC-XXXXX`)[cite: 93, 94]. +* `signature`: String (Base16 encoded)[cite: 94]. + +**Example Response** + +```json +{ + "tcbInfo": { + "version": 2, + "issueDate": "2018-07-30T12:00:00Z", + "nextUpdate": "2018-08-30T12:00:00Z", + "fmspc": "...", + "pceId": "0000", + "tcbType": 1, + "tcbEvaluationDataNumber": 7, + "tcbLevels": [ + { + "tcb": { + "sgxtcbcomp01svn": 0, + /* ... */ + "pcesvn": 0 + }, + "tcbDate": "2018-07-11T12:00:00Z", + "tcbStatus": "UpToDate", + "advisoryIDs": [ + "INTEL-SA-00070", + "INTEL-SA-00076" + ] + } + ] + }, + "signature": "..." +} +``` + +**Status Codes** + +| Code | Model | Headers | Description | +|:-----|:----------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------| +| 200 | TcbInfoV2 | Content-Type: `application/json`[cite: 96]. \ Request-ID[cite: 96]. \ SGX-TCB-Info-Issuer-Chain: Issuer chain[cite: 96]. \ Warning[cite: 96]. | Operation successful[cite: 96]. | +| 400 | | Request-ID[cite: 96]. \ Warning[cite: 96]. | Invalid request (bad FMSPC or conflicting `update`/`tcbEvaluationDataNumber`)[cite: 96]. | +| 401 | | Request-ID[cite: 96]. \ Warning[cite: 96]. | Failed to authenticate or authorize[cite: 96]. | +| 404 | | Request-ID[cite: 96]. \ Warning[cite: 96]. | TCB info not found for FMSPC or `tcbEvaluationDataNumber`[cite: 96]. | +| 410 | | Request-ID[cite: 98]. \ Warning[cite: 98]. | TCB Information for `tcbEvaluationDataNumber` no longer available[cite: 98]. | +| 500 | | Request-ID[cite: 98]. \ Warning[cite: 98]. | Internal server error[cite: 98]. | +| 503 | | Request-ID[cite: 98]. \ Warning[cite: 98]. | Server unable to process[cite: 98]. | + +----- + +### Get Quoting Enclave Identity V3 + +Verifies if an SGX Enclave Report matches a valid Quoting Enclave (QE) identity[cite: 99]. + +**Algorithm:** + +1. Retrieve and validate QE Identity[cite: 99]. +2. Compare SGX Enclave Report against QE Identity: + * Verify `MRSIGNER` equals `mrsigner`[cite: 100]. + * Verify `ISVPRODID` equals `isvprodid`[cite: 101]. + * Verify `(miscselectMask & MISCSELECT)` equals `miscselect`[cite: 102]. + * Verify `(attributesMask & ATTRIBUTES)` equals `attributes`[cite: 103, 104]. +3. If any check fails, identity doesn't match[cite: 105]. +4. Determine TCB status: + * Retrieve TCB Levels[cite: 106]. + * Find TCB Level with ISVSVN \<= Enclave Report ISVSVN (descending)[cite: 107]. + * Read `tcbStatus`; if not found, it's unsupported[cite: 108]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity` + +**Request** + +| Name | Type | Type | Required | Pattern | Description | +|:------------------------|:-------|:------|:---------|:--------|:------------------------------------------------------------------------------------------| +| update | String | Query | False | `(early | standard)` | Update type (Default: standard)[cite: 110]. Cannot be used with `tcbEvaluationDataNumber`[cite: 110]. | +| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Specifies TCB Evaluation Data Number[cite: 110]. Cannot be used with `update`[cite: 110]. | + +**Example Requests** + +```bash +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?update=early](https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?update=early)" +curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?tcbEvaluationDataNumber=](https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?tcbEvaluationDataNumber=)..." +``` + +**Response** + +**Model**: QEIdentityV2 (JSON) - QE Identity data[cite: 111]. + +**QEIdentityV2 Structure** + +* `enclaveIdentity`: + * `id`: String (`QE`, `QVE`, or `QAE`)[cite: 113]. + * `version`: Integer[cite: 113]. + * `issueDate`, `nextUpdate`: String (date-time, ISO 8601 UTC)[cite: 114]. + * `tcbEvaluationDataNumber`: Integer[cite: 115]. + * `miscselect`, `miscselectMask`: String (Base16-encoded)[cite: 115, 116]. + * `attributes`, `attributesMask`: String (Base16-encoded)[cite: 116]. + * `mrsigner`: String (Base16-encoded)[cite: 116]. + * `isvprodid`: Integer[cite: 116]. + * `tcbLevels`: Array of TCB level objects[cite: 116]. + * `tcb`: Object with `isvsvn` (Integer)[cite: 117]. + * `tcbDate`: String (date-time, ISO 8601 UTC)[cite: 117]. + * `tcbStatus`: String (`UpToDate`, `OutOfDate`, `Revoked`)[cite: 119]. + * `advisoryIDs`: Array of strings[cite: 119]. +* `signature`: String (Hex-encoded)[cite: 119]. + +**Status Codes** + +| Code | Model | Headers | Description | +|:-----|:-------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------| +| 200 | QEIdentityV2 | Content-Type: `application/json`[cite: 122]. \ Request-ID[cite: 122]. \ SGX-Enclave-Identity-Issuer-Chain: Issuer chain[cite: 122]. \ Warning[cite: 122]. | Operation successful[cite: 122]. | +| 400 | | Request-ID[cite: 122]. \ Warning[cite: 123]. | Invalid request (bad params or conflicting `update`/`tcbEvaluationDataNumber`)[cite: 122, 124]. | +| 401 | | Request-ID[cite: 123]. \ Warning[cite: 123]. | Failed to authenticate or authorize[cite: 123]. | +| 404 | | Request-ID[cite: 123]. \ Warning[cite: 123]. | QE identity not found for `tcbEvaluationDataNumber`[cite: 124]. | +| 410 | | Request-ID[cite: 124]. \ Warning[cite: 124]. | QEIdentity for `tcbEvaluationDataNumber` no longer available[cite: 124]. | +| 500 | | Request-ID[cite: 125]. \ Warning[cite: 125]. | Internal server error[cite: 125]. | +| 503 | | Request-ID[cite: 125]. \ Warning[cite: 125]. | Server unable to process[cite: 125]. | + +----- + +### Get Quote Verification Enclave Identity V3 + +Verifies if an SGX Enclave Report matches a valid QVE identity[cite: 126]. + +**Algorithm:** + +1. Retrieve and validate QVE Identity[cite: 126]. +2. Compare Enclave Report: `MRSIGNER`[cite: 127], `ISVPRODID`[cite: 128], `MISCSELECT` (with mask)[cite: 128], + `ATTRIBUTES` (with mask)[cite: 128]. +3. If any fails, no match[cite: 129]. +4. Determine TCB status via ISVSVN comparison[cite: 129, 130]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/qve/identity` + +**Request**: Same parameters as `Get Quoting Enclave Identity V3` (`update` and `tcbEvaluationDataNumber`)[cite: 132]. + +**Response**: QVEIdentityV2 (JSON) - QVE Identity data[cite: 133]. Structure similar to QE +Identity[cite: 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144]. + +**Status Codes**: Similar to `Get Quoting Enclave Identity V3`[cite: 145]. + +----- + +### Get Quote Appraisal Enclave Identity V3 + +Verifies if an SGX Enclave Report matches a valid QAE identity[cite: 149]. + +**Algorithm:** + +1. Retrieve and validate QAE Identity[cite: 149]. +2. Compare Enclave Report: `MRSIGNER`[cite: 151], `ISVPRODID`[cite: 151], `MISCSELECT` (with mask)[cite: 152, 153], + `ATTRIBUTES` (with mask)[cite: 154, 155]. +3. If any fails, no match[cite: 155]. +4. Determine TCB status via ISVSVN comparison[cite: 157, 158]. + +#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/qae/identity` + +**Request**: Same parameters as `Get Quoting Enclave Identity V3` (`update` and `tcbEvaluationDataNumber`)[cite: 160]. + +**Response**: QAEIdentityV2 (JSON) - QAE Identity data[cite: 161]. Structure similar to QE +Identity[cite: 162, 163, 164, 165, 166, 167, 168, 169, 170]. + +**Status Codes**: Similar to `Get Quoting Enclave Identity V3`[cite: 171, 174]. + +----- + +### PCK Certificate and CRL Specification + +This document specifies the hierarchy and format of X.509 v3 certificates and v2 CRLs for Provisioning Certification +Keys[cite: 175]. + +Enforcement of a mitigation means the attestation process can detect its presence and the result will differ[cite: 175]. +Intel offers `standard` (default) and `early` update parameters, affecting when enforcement occurs[cite: 176]. The +attestation result is an objective assessment[cite: 177]. Relying parties can use additional factors [cite: 178] and may +choose to trust an 'OutOfDate' platform, accepting risks[cite: 180]. Intel will strive to communicate schedule +deviations[cite: 181]. + diff --git a/crates/intel-dcap-api/specs/API spec V4.md b/crates/intel-dcap-api/specs/API spec V4.md new file mode 100644 index 0000000..0112b31 --- /dev/null +++ b/crates/intel-dcap-api/specs/API spec V4.md @@ -0,0 +1,664 @@ +This document outlines the API for Intel® SGX and Intel® TDX services, focusing on platform registration and +provisioning certification using ECDSA attestation. + +## Intel® SGX and Intel® TDX Registration Service for Scalable Platforms [cite: 1] + +The Intel® SGX and Intel® TDX Registration Service API enables the registration of Intel® SGX platforms with multiple +processor packages as a unified platform instance[cite: 2]. This allows these platforms to be remotely attested as a +single entity[cite: 2]. It is important to note that the service enforces a minimum TLS protocol version of 1.2; any +attempts to connect with older TLS/SSL versions will be rejected[cite: 3]. + +### Register Platform + +This API facilitates the registration of multi-package SGX platforms, encompassing both initial registration and TCB ( +Trusted Computing Base) recovery[cite: 4]. During this process, the Registration Service authenticates the platform +manifest to confirm it originates from a genuine, non-revoked SGX platform[cite: 4]. If the platform configuration +passes verification, its provisioning root keys are securely stored[cite: 4]. These stored keys are subsequently used to +derive the public components of Provisioning Certification Keys (PCKs), which are then distributed as X.509 certificates +by the Provisioning Certification Service[cite: 5]. These PCK certificates are integral to the remote attestation +process for the platform[cite: 5]. + +**POST** `https://api.trustedservices.intel.com/sgx/registration/v1/platform` + +**Request** + +* **Headers**: In addition to standard HTTP headers (like `Content-Length`), the following is required[cite: 1]: + +| Name | Required | Value | Description | +|:-------------|:---------|:-------------------------|:----------------------------------------| +| Content-Type | True | application/octet-stream | MIME type of the request body[cite: 1]. | + +* **Body**: The request body must be a binary representation of the Platform Manifest structure[cite: 6]. This is an + opaque blob containing the registration manifest for a multi-package platform[cite: 6]. It includes the platform + provisioning root keys established by the platform instance and the necessary data to authenticate it as a genuine, + non-revoked SGX platform[cite: 6]. + +* **Example Request**: + ```bash + curl -v -X POST "Content-Type: application/octet-stream" --data-binary @platform_manifest.bin "https://api.trustedservices.intel.com/sgx/registration/v1/platform" [cite: 1] + ``` + +**Response** + +* **Model**: The response body will contain the hex-encoded representation of the PPID (Platform Provisioning ID) for + the registered platform instance, but only if the HTTP Status Code is 201[cite: 1]. Otherwise, the body will be + empty[cite: 1]. + +* **Example Response**: + ``` + 00112233445566778899AABBCCDDEEFF [cite: 1] + ``` + +* **Status Codes**: + +| Code | Headers | Body | Description | +|:-----|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------|:--------------------------------------------------------------------------------------------------| +| 201 | `Request-ID`: Randomly generated identifier for troubleshooting[cite: 7]. | Hex-encoded PPID | Operation successful; a new platform instance has been registered[cite: 7]. | +| 400 | `Request-ID`: Randomly generated identifier[cite: 8]. `Error-Code` & `Error-Message`: Details on the error (e.g., `InvalidRequestSyntax`, `InvalidRegistrationServer`, `InvalidOrRevokedPackage`, `PackageNotFound`, `IncompatiblePackage`, `InvalidPlatformManifest`, `CachedKeysPolicyViolation`)[cite: 8]. | | Invalid Platform Manifest[cite: 10]. The client should not retry without modifications[cite: 10]. | +| 415 | `Request-ID`: Randomly generated identifier[cite: 8]. | | The MIME type specified in the request is not supported[cite: 8]. | +| 500 | `Request-ID`: Randomly generated identifier[cite: 8]. | | An internal server error occurred[cite: 8]. | +| 503 | `Request-ID`: Randomly generated identifier[cite: 8]. | | The server is currently unable to process the request; try again later[cite: 8]. | + +### Add Package + +This API allows for adding new processor packages to an already registered platform instance[cite: 11]. Upon successful +execution, a Platform Membership Certificate is generated for each processor package included in the Add +Request[cite: 11]. This requires a subscription for registration[cite: 11]. + +**POST** `https://api.trustedservices.intel.com/sgx/registration/v1/package` + +**Request** + +* **Headers**: Besides standard headers like `Content-Length`[cite: 12], the following are needed: + +| Name | Required | Value | Description | +|:--------------------------|:---------|:-------------------------|:------------------------------------------------------------------| +| Ocp-Apim-Subscription-Key | True | *Your Subscription Key* | Subscription key for API access, found in your profile[cite: 12]. | +| Content-Type | True | application/octet-stream | MIME type of the request body[cite: 12]. | + +* **Body**: A binary representation of the Add Request structure, an opaque blob for adding new packages to an existing + platform[cite: 13]. + +* **Example Request**: + ```bash + curl -v -X POST "Content-Type: application/octet-stream" --data-binary @add_package_request.bin "https://api.trustedservices.intel.com/sgx/registration/v1/package" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 14] + ``` + +**Response** + +* **Model**: For a 200 HTTP Status Code, the response is a fixed-size array (8 elements) containing binary Platform + Membership Certificate structures appended together[cite: 14]. Certificates fill the array sequentially, starting from + index 0, with remaining elements zeroed out[cite: 14]. + +* **Example Response (hex-encoded)**: + ``` + E8BDBECFEF9040184488777267355084...00000000 [cite: 15] + ``` + +* **Status Codes**: + +| Code | Headers | Body | Description | +|:-----|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------| +| 200 | `Content-Type`: application/octet-stream[cite: 18]. `Request-ID`: Randomly generated identifier[cite: 18]. `Certificate-Count`: Number of certificates returned[cite: 18]. | Fixed-size array (8 elements) with binary Platform Membership Certificates[cite: 18, 19]. | Operation successful; packages added to the platform[cite: 18]. | +| 400 | `Request-ID`: Randomly generated identifier[cite: 18]. `Error-Code` & `Error-Message`: Details on the error (e.g., `InvalidRequestSyntax`, `PlatformNotFound`, `InvalidOrRevokedPackage`, `PackageNotFound`[cite: 17], `InvalidAddRequest`)[cite: 18]. | | Invalid Add Request Payload[cite: 20]. Do not retry without modifications[cite: 20]. | +| 401 | `Request-ID`: Randomly generated identifier[cite: 18]. | | Failed to authenticate or authorize the request[cite: 18]. | +| 415 | `Request-ID`: Randomly generated identifier[cite: 18]. | | The MIME type specified is not supported[cite: 18]. | +| 500 | `Request-ID`: Randomly generated identifier[cite: 18]. | | Internal server error occurred[cite: 18]. | +| 503 | `Request-ID`: Randomly generated identifier[cite: 18]. | | Server is currently unable to process the request[cite: 18]. | + +## Intel® SGX and Intel® TDX Provisioning Certification Service for ECDSA Attestation [cite: 21] + +This service provides PCK certificates. You can download the Provisioning Certification Root CA Certificate (v4) in both +DER and PEM formats[cite: 21]. + +### Get/Post PCK Certificate V4 + +This API allows requesting a single PCK certificate. It offers two primary methods: + +1. **Using PPID and SVNs**: + * **Single-socket platforms**: No prerequisites[cite: 22]. + * **Multi-socket platforms**: Requires prior platform registration via the Register Platform API[cite: 22]. This + flow necessitates that platform root keys are persistently stored in the backend[cite: 23], and the Keys Caching + Policy must be `true`[cite: 23]. +2. **Using Platform Manifest and SVNs**: + * **Multi-socket platforms**: Does *not* require prior registration[cite: 24]. Platform root keys are *not* required + to be persistently stored[cite: 24]. The Keys Caching Policy determines whether keys are stored or not[cite: 25]. + * **Direct Registration (via Register Platform API)**: Keys are always stored; `CachedKeys` flag in PCK + certificates is `true`[cite: 26, 27]. + * **Indirect Registration (via Get PCK Certificate(s) API)**: Keys are never stored; `CachedKeys` flag is + `false`[cite: 28, 30]. Register Platform API cannot be used afterward[cite: 29]. + +**Note**: The PCS returns the PCK Certificate representing the highest TCB security level based on the CPUSVN and PCE +ISVSVN inputs[cite: 31]. + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcert` + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:-------------------|:--------------------------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 32]. | +| PPID-Encryption-Key | String | Header | False | | Key type for PPID encryption (default: "RSA-3072")[cite: 32]. | +| encrypted_ppid | String | Query | True | `[0-9a-fA-F]{768}` | Base16-encoded encrypted PPID[cite: 32]. | +| cpusvn | String | Query | True | `[0-9a-fA-F]{32}` | Base16-encoded CPUSVN[cite: 32]. | +| pcesvn | String | Query | True | `[0-9a-fA-F]{4}` | Base16-encoded PCESVN (little endian)[cite: 32]. | +| pceid | String | Query | True | `[0-9a-fA-F]{4}` | Base16-encoded PCE-ID (little endian)[cite: 32]. | + +* **Example Request**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcert?encrypted_ppid={encrypted_ppid}&cpusvn={cpusvn}&pcesvn={pcesvn}&pceid={pceid}" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 33] + ``` + +**POST** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcert` + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:----------------------------|:-------------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 33]. | +| Content-Type | String | Header | True | `application/json` | Content type[cite: 35]. | +| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16862,112884}` | Base16-encoded Platform Manifest[cite: 35]. | +| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}` | Base16-encoded CPUSVN[cite: 35]. | +| pcesvn | String | Body Field | True | `[0-9a-fA-F]{4}` | Base16-encoded PCESVN (little endian)[cite: 35]. | +| pceid | String | Body Field | True | `[0-9a-fA-F]{4}` | Base16-encoded PCE-ID (little endian)[cite: 35]. | + +* **Body**: + ```json + { + "platformManifest": "...", [cite: 36] + "cpusvn": "...", [cite: 36] + "pcesvn": "...", [cite: 36] + "pceid": "..." [cite: 36] + } + ``` + +* **Example Request**: + ```bash + curl -v -X POST --data '{"platformManifest":"...","cpusvn":"...","pcesvn":"...","pceid":"..."}' "https://api.trustedservices.intel.com/sgx/certification/v4/pckcert" -H "Ocp-Apim-Subscription-Key: {subscription_key}" -H "Content-Type: application/json" [cite: 36] + ``` + +**Response (Both GET & POST)** + +* **Model**: `PckCert (X-PEM-FILE)` - PEM-encoded SGX PCK Certificate[cite: 36]. +* **Example Response**: + ```pem + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- [cite: 36] + ``` +* **Status Codes**: + +| Code | Model | Headers | Description | +|:-----|:--------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------| +| 200 | PckCert | `Content-Type`: application/x-pem-file[cite: 37]. `Request-ID`: Identifier[cite: 37]. `SGX-PCK-Certificate-Issuer-Chain`: PEM-encoded Issuer Chain[cite: 37]. `SGX-TCBm`: Hex-encoded CPUSVN & PCESVN[cite: 37]. `SGX-FMSPC`: Hex-encoded FMSPC[cite: 37]. `SGX-PCK-Certificate-CA-Type`: "processor" or "platform"[cite: 37]. `Warning` (Optional)[cite: 37]. | Operation successful[cite: 37]. | +| 400 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. `Error-Code` & `Error-Message` (e.g., `InvalidRequestSyntax`, `InvalidRegistrationServer`, `InvalidOrRevokedPackage`, `PackageNotFound`, `IncompatiblePackage`, `InvalidPlatformManifest`)[cite: 37]. | Invalid request parameters[cite: 37]. | +| 401 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. | Failed to authenticate or authorize[cite: 37]. | +| 404 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. | PCK Certificate not found (e.g., unsupported PPID/PCE-ID, TCB below minimum, Platform Manifest not registered/updated)[cite: 37]. | +| 429 | | `Retry-After`: Wait time in seconds[cite: 37]. `Warning` (Optional)[cite: 37]. | Too many requests[cite: 37]. | +| 500 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. | Internal server error[cite: 37]. | +| 503 | | `Request-ID`: Identifier[cite: 39]. `Warning` (Optional)[cite: 39]. | Server is currently unable to process[cite: 39]. | + +### Get PCK Certificates V4 + +This API retrieves PCK certificates for *all* configured TCB levels for a platform. The usage conditions (single-socket +vs. multi-socket, PPID vs. Platform Manifest, key caching) are similar to the single PCK certificate +API[cite: 40, 41, 42, 43, 44, 45, 46, 47, 48]. + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts` (Using PPID & PCE-ID) + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:-------------------|:------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 49]. | +| PPID-Encryption-Key | String | Header | False | | Key type (default: "RSA-3072")[cite: 49]. | +| encrypted_ppid | String | Query | True | `[0-9a-fA-F]{768}` | Encrypted PPID[cite: 49]. | +| pceid | String | Query | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 49]. | + +* **Example Request**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts?encrypted_ppid={...}&pceid={...}" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 50] + ``` + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config` (Using PPID, PCE-ID & +CPUSVN) [cite: 51] + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:-------------------|:------------------------------------------| +| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 52]. | +| PPID-Encryption-Key | String | Header | False | | Key type (default: "RSA-3072")[cite: 52]. | +| encrypted_ppid | String | Query | True | `[0-9a-fA-F]{768}` | Encrypted PPID[cite: 52]. | +| pceid | String | Query | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 52]. | +| cpusvn | String | Query | True | `[0-9a-fA-F]{32}` | CPUSVN[cite: 52]. | + +* **Example Request**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config?encrypted_ppid={...}&pceid={...}&cpusvn={...}" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 53] + ``` + +**POST** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts` (Using Platform Manifest & PCE-ID) + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:----------------------------|:-----------------------------| +| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 54]. | +| Content-Type | String | Header | True | `application/json` | Content type[cite: 54]. | +| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16862,112884}` | Platform Manifest[cite: 54]. | +| pceid | String | Body Field | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 54]. | + +* **Body**: + ```json + { + "platformManifest": "...", [cite: 55] + "pceid": "..." [cite: 55] + } + ``` +* **Example Request**: + ```bash + curl -v -X POST --data '{"platformManifest":"...","pceid":"..."}' "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts" -H "Ocp-Apim-Subscription-Key: {subscription_key}" -H "Content-Type: application/json" [cite: 55] + ``` + +**POST** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config` (Using Platform Manifest, PCE-ID & +CPUSVN) + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:--------------------------|:-------|:-------------|:---------|:----------------------------|:-----------------------------| +| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 56]. | +| Content-Type | String | Header | True | `application/json` | Content type[cite: 57]. | +| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16862,112884}` | Platform Manifest[cite: 56]. | +| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}` | CPUSVN[cite: 56]. | +| pceid | String | Body Field | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 56]. | + +* **Body**: + ```json + { + "platformManifest": "...", [cite: 57] + "cpusvn": "...", [cite: 57] + "pceid": "..." [cite: 57] + } + ``` +* **Example Request**: + ```bash + curl -v -X POST --data '{"platformManifest":"...","cpusvn":"...","pceid":"..."}' "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config" -H "Ocp-Apim-Subscription-Key: {subscription_key}" -H "Content-Type: application/json" [cite: 57] + ``` + +**Response (All GET & POST for multiple certs)** + +* **Model**: `PckCerts` (JSONArray of objects, each containing `tcb`, `tcbm`, and `cert`)[cite: 56]. + * `tcb`: Object with 16 `sgxtcbcompXXsvn` fields (integer 0-255) and `pcesvn` (integer 0-65535)[cite: 59]. + * `tcbm`: Hex-encoded string of CPUSVN (16 bytes) and PCESVN (2 bytes)[cite: 7]. + * `cert`: URL-encoded PEM PCK Certificate, or "Not available" string[cite: 60]. +* **Example Response**: + ```json + [ + { + "tcb": { + "sgxtcbcomp01svn": 3, + "sgxtcbcomp02svn": 1, + ... + "pcesvn": 11 + }, + "tcbm": "...", + "cert": "-----BEGIN%20CERTIFICATE-----%0A...%0A-----END%20CERTIFICATE-----" [cite: 61] + }, + ... + ] + ``` +* **Status Codes**: + +| Code | Model | Headers | Description | +|:-----|:---------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------| +| 200 | PckCerts | `Content-Type`: application/json[cite: 8]. `Request-ID`: Identifier[cite: 8]. `SGX-PCK-Certificate-Issuer-Chain`: Issuer Chain[cite: 62]. `SGX-FMSPC`: FMSPC[cite: 8]. `SGX-PCK-Certificate-CA-Type`: "processor" or "platform"[cite: 63]. `Warning` (Optional)[cite: 8]. | Operation successful[cite: 8]. | +| 400 | | `Request-ID`: Identifier[cite: 8]. `Warning` (Optional)[cite: 8]. `Error-Code` & `Error-Message` (e.g., `InvalidRequestSyntax`[cite: 65], `InvalidRegistrationServer`[cite: 65], `InvalidOrRevokedPackage`[cite: 65], `PackageNotFound`[cite: 65], `IncompatiblePackage`[cite: 65], `InvalidPlatformManifest` [cite: 66]) | Invalid request parameters[cite: 8]. | +| 401 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | Failed to authenticate or authorize[cite: 68]. | +| 404 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | PCK Certificate not found (e.g., unsupported PPID/PCE-ID, Platform Manifest not registered)[cite: 68]. | +| 429 | | `Retry-After`: Wait time[cite: 68]. `Warning` (Optional)[cite: 68]. | Too many requests[cite: 68]. | +| 500 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | Internal server error[cite: 68]. | +| 503 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | Server is currently unable to process[cite: 68]. | + +### Get Revocation List V4 + +This API retrieves the X.509 Certificate Revocation List (CRL) for revoked SGX PCK Certificates, issued by either the +Intel SGX Processor CA or Platform CA[cite: 69, 70]. + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl` [cite: 71] + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:---------|:-------|:-------------|:---------|:------------|:------------| +| ca | String | Query | True | `(processor | platform)` | CA identifier ("processor" or "platform")[cite: 71, 72]. | +| encoding | String | Query | False | `(pem | der)` | CRL encoding (default: PEM)[cite: 71]. | + +* **Example Request**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform&encoding=pem" [cite: 71] + ``` + +**Response** + +* **Model**: `PckCrl` (X-PEM-FILE or PKIX-CRL) - PEM or DER encoded CRL[cite: 71]. +* **Example Response**: + ```pem + -----BEGIN X509 CRL----- + ... + -----END X509 CRL----- [cite: 71] + ``` +* **Status Codes**: + +| Code | Model | Headers | Description | +|:-----|:-------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------| +| 200 | PckCrl | `Content-Type`: "application/x-pem-file" or "application/pkix-crl"[cite: 71]. `Request-ID`: Identifier[cite: 71]. `SGX-PCK-CRL-Issuer-Chain`: Issuer Chain[cite: 73]. `Warning` (Optional)[cite: 71]. | Operation successful[cite: 71]. | +| 400 | | `Request-ID`: Identifier[cite: 71]. `Warning` (Optional)[cite: 71]. | Invalid request parameters[cite: 71]. | +| 401 | | `Request-ID`: Identifier[cite: 74]. `Warning` (Optional)[cite: 74]. | Failed to authenticate or authorize[cite: 74]. | +| 500 | | `Request-ID`: Identifier[cite: 74]. `Warning` (Optional)[cite: 74]. | Internal server error[cite: 74]. | +| 503 | | `Request-ID`: Identifier[cite: 74]. `Warning` (Optional)[cite: 74]. | Server is currently unable to process[cite: 74]. | + +### Get SGX TCB Info V4 + +This API retrieves SGX TCB information for a specific FMSPC, which is crucial for determining the TCB status of a +platform[cite: 75]. The process involves: + +1. Retrieving the FMSPC from the SGX PCK Certificate[cite: 75]. +2. Fetching the corresponding SGX TCB info[cite: 76]. +3. Iterating through the TCB Levels: + * Comparing all 16 SGX TCB Comp SVNs from the certificate against the TCB Level; they must be >=[cite: 77, 78]. + * Comparing the PCESVN from the certificate against the TCB Level; it must be >=[cite: 79, 80]. If both match, the + TCB level's status is found[cite: 80]. +4. If no match is found, the TCB level is unsupported[cite: 82]. + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/tcb` [cite: 82] + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:------------------------|:-------|:-------------|:---------|:------------------|:-------------------------------------------------------------------------------------------------------| +| fmspc | String | Query | True | `[0-9a-fA-F]{12}` | Base16-encoded FMSPC[cite: 83]. | +| update | String | Query | False | `(early | standard)` | TCB Info update type (default: standard). `early` provides access sooner than `standard`[cite: 83]. Cannot be used with `tcbEvaluationDataNumber`[cite: 83]. | +| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Retrieves TCB info for a specific evaluation number[cite: 83]. Cannot be used with `update`[cite: 83]. | + +* **Example Requests**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc={fmspc_value}&update=early" [cite: 84] + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc={fmspc_value}&tcbEvaluationDataNumber={number}" [cite: 84] + ``` + +**Response** + +* **Model**: `Appendix A: TCB info V3`[cite: 86]. (See Appendix A below). +* **Example Response**: (JSON structure as shown in the document)[cite: 85]. +* **Status Codes**: + +| Code | Model | Headers | Description | +|:-----|:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------| +| 200 | TcbInfoV3 | `Content-Type`: application/json[cite: 86]. `Request-ID`: Identifier[cite: 86]. `TCB-Info-Issuer-Chain`: Issuer Chain[cite: 86]. `Warning` (Optional)[cite: 86]. | Operation successful[cite: 86]. | +| 400 | | `Request-ID`: Identifier[cite: 86]. `Warning` (Optional)[cite: 86]. | Invalid request (bad `fmspc`, invalid params, or `update` & `tcbEvaluationDataNumber` used together)[cite: 86]. | +| 401 | | `Request-ID`: Identifier[cite: 86]. `Warning` (Optional)[cite: 87]. | Failed to authenticate or authorize[cite: 86]. | +| 404 | | `Request-ID`: Identifier[cite: 86]. `Warning` (Optional)[cite: 87]. | TCB info not found for the given `fmspc` or `tcbEvaluationDataNumber`[cite: 86]. | +| 410 | | `Request-ID`: Identifier[cite: 88]. `Warning` (Optional)[cite: 88]. | TCB info for the provided `tcbEvaluationDataNumber` is no longer available[cite: 88]. | +| 500 | | `Request-ID`: Identifier[cite: 88]. `Warning` (Optional)[cite: 88]. | Internal server error[cite: 88]. | +| 503 | | `Request-ID`: Identifier[cite: 88]. `Warning` (Optional)[cite: 88]. | Server currently unable to process[cite: 88]. | + +### Get TDX TCB Info V4 + +This API retrieves TDX TCB information[cite: 89]. The TCB status determination follows a similar process to SGX but +includes additional steps for TDX TEE TCB SVNs and TDX Module +Identity[cite: 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102]. + +**GET** `https://api.trustedservices.intel.com/tdx/certification/v4/tcb` [cite: 102] + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:------------------------|:-------|:-------------|:---------|:------------------|:---------------------------------------------------------------------------------------------------------| +| fmspc | String | Query | True | `[0-9a-fA-F]{12}` | Base16-encoded FMSPC[cite: 103]. | +| update | String | Query | False | `(early | standard)` | TCB Info update type (default: standard)[cite: 103]. Cannot be used with `tcbEvaluationDataNumber`[cite: 103]. | +| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Retrieves TCB info for a specific evaluation number[cite: 103]. Cannot be used with `update`[cite: 103]. | + +* **Example Requests**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc={fmspc_value}&update=early" [cite: 104] + curl -v -X GET "https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc={fmspc_value}&tcbEvaluationDataNumber={number}" [cite: 104] + ``` + +**Response** + +* **Model**: `Appendix A: TCB info V3`[cite: 107]. (See Appendix A below). +* **Example Response**: (JSON structure including `tdxModule` and `tdxtcbcomponents` as shown in the + document)[cite: 105, 106]. +* **Status Codes**: Similar to Get SGX TCB Info V4[cite: 108]. + +### Enclave Identity V4 + +This set of APIs allows for determining if an SGX Enclave's identity matches Intel's published identity[cite: 109]. The +process involves: + +1. Retrieving the Enclave Identity (SGX QE, TDX QE, QVE, or QAE)[cite: 109]. +2. Comparing `MRSIGNER` and `ISVPRODID` fields[cite: 109]. +3. Applying `miscselectMask` and `attributesMask` and comparing the results[cite: 111, 112, 113, 114]. +4. If checks pass, determining the TCB status by finding the highest TCB Level (sorted by ISVSVN) whose ISVSVN is <= the + Enclave Report's ISVSVN[cite: 116, 117]. + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/qe/identity` [cite: 118] +**GET** `https://api.trustedservices.intel.com/tdx/certification/v4/qe/identity` [cite: 128] +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/qve/identity` [cite: 133] +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/qae/identity` [cite: 138] + +* **Request**: + +| Name | Type | Request Type | Required | Pattern | Description | +|:------------------------|:-------|:-------------|:---------|:--------|:--------------------------------------------------------------------------------------------------------------------------------------------| +| update | String | Query | False | `(early | standard)` | Identity update type (default: standard)[cite: 118, 127, 132, 137]. Cannot be used with `tcbEvaluationDataNumber`[cite: 118, 121, 127, 132, 137]. | +| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Retrieves Identity for a specific evaluation number[cite: 119, 120, 127, 132, 137]. Cannot be used with `update`[cite: 121, 127, 132, 137]. | + +* **Example Requests** (SGX QE shown): + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/qe/identity?update=early" [cite: 122] + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/qe/identity?tcbEvaluationDataNumber={number}" [cite: 122] + ``` + +**Response** + +* **Model**: `Appendix B: Enclave Identity V2`[cite: 122, 128, 134, 139]. (See Appendix B below). +* **Example Response**: (JSON structure as shown in the document for QE[cite: 125], TDX QE[cite: 131], QVE[cite: 136], + and QAE [cite: 141]). +* **Status Codes** (SGX QE shown, others are similar): + +| Code | Model | Headers | Description | +|:-----|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------| +| 200 | EIdentityV2 | `Content-Type`: application/json[cite: 122]. `Request-ID`: Identifier[cite: 122]. `SGX-Enclave-Identity-Issuer-Chain`: Issuer Chain[cite: 122]. `Warning` (Optional)[cite: 122]. | Operation successful[cite: 122]. | +| 400 | | `Request-ID`: Identifier[cite: 122]. `Warning` (Optional)[cite: 122]. | Invalid request (params or `update` & `tcbEvaluationDataNumber` conflict)[cite: 122]. | +| 401 | | `Request-ID`: Identifier[cite: 123]. `Warning` (Optional)[cite: 123]. | Failed to authenticate or authorize[cite: 122]. | +| 404 | | `Request-ID`: Identifier[cite: 123]. `Warning` (Optional)[cite: 123]. | Identity info not found[cite: 122]. | +| 410 | | `Request-ID`: Identifier[cite: 124]. `Warning` (Optional)[cite: 124]. | Identity info no longer available[cite: 124]. | +| 500 | | `Request-ID`: Identifier[cite: 124]. `Warning` (Optional)[cite: 124]. | Internal server error[cite: 124]. | +| 503 | | `Request-ID`: Identifier[cite: 124]. `Warning` (Optional)[cite: 124]. | Server currently unable to process[cite: 124]. | + +### Retrieve FMSPCs V4 + +Retrieves a list of FMSPC values for SGX and TDX platforms that support DCAP attestation[cite: 141]. + +**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/fmspcs` [cite: 141] + +* **Request**: + +| Name | Type | Request Type | Required | Description | +|:---------|:-------|:-------------|:---------|:----------------------------------------------------------------------------| +| platform | String | Query | False | Optional platform filter: `all` (default), `client`, `E3`, `E5`[cite: 141]. | + +* **Example Request**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/fmspcs?platform=E5" [cite: 141] + ``` + +**Response** + +* **Example Response**: + ```json + [ + {"platform": "E3", "fmspc": "123456789000"}, [cite: 142] + {"platform": "E5", "fmspc": "987654321000"}, [cite: 142] + {"platform": "client", "fmspc": "ABCDEF123456"} [cite: 142] + ] + ``` +* **Status Codes**: + +| Code | Headers | Description | +|:-----|:-------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------| +| 200 | `Content-Type`: application/json[cite: 142]. `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 142]. | Operation successful[cite: 142]. | +| 400 | `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 143]. | Invalid request parameters[cite: 142]. | +| 500 | `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 142]. | Internal server error[cite: 142]. | +| 503 | `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 142]. | Server currently unable to process[cite: 142]. | + +### Retrieve TCB Evaluation Data Numbers V4 + +Retrieves the list of currently supported TCB Evaluation Data Numbers and their associated TCB-R event +states[cite: 142]. + +**GET** `https://api.trustedservices.intel.com/{sgx|tdx}/certification/v4/tcbevaluationdatanumbers` [cite: 142] + +* **Example Requests**: + ```bash + curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/tcbevaluationdatanumbers" [cite: 142] + curl -v -X GET "https://api.trustedservices.intel.com/tdx/certification/v4/tcbevaluationdatanumbers" [cite: 142] + ``` + +**Response** + +* **Model**: `Appendix C: TCB Evaluation Data Numbers V1`[cite: 144]. (See Appendix C below). +* **Example Response**: + ```json + { + "tcbEvaluationDataNumbers": { + "version": 1, + "issueDate": "2023-04-13T09:38:17Z", + "nextUpdate": "2023-05-13T09:38:17Z", + "tcbNumbers": [ + {"tcbEvaluationDataNumber": 12, "tcbRecoveryEventDate": "2023-04-13T00:00:00Z", "tcbDate": "2023-04-13T00:00:00Z"}, + {"tcbEvaluationDataNumber": 11, "tcbRecoveryEventDate": "2023-01-14T00:00:00Z", "tcbDate": "2023-01-14T00:00:00Z"} + ], + "signature": "..." [cite: 142] + } + } + ``` +* **Status Codes**: + +| Code | Headers | Description | +|:-----|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------| +| 200 | `Content-Type`: application/json[cite: 144]. `Request-ID`: Identifier[cite: 144]. `TCB-Evaluation-Data-Numbers-Issuer-Chain`: Issuer Chain[cite: 145]. `Warning` (Optional)[cite: 144]. | Operation successful[cite: 144]. | +| 500 | `Request-ID`: Identifier[cite: 144]. `Warning` (Optional)[cite: 144]. | Internal server error[cite: 144]. | +| 503 | `Request-ID`: Identifier[cite: 144]. `Warning` (Optional)[cite: 144]. | Server currently unable to process[cite: 146]. | + +--- + +## Appendix A: TCB Info V3 [cite: 147] + +This defines the structure of the TCB Info V3 JSON response[cite: 147]. + +* `tcbInfo`: (Object) + * `id`: (String) Identifier (e.g., "SGX", "TDX")[cite: 148]. + * `version`: (Integer) Structure version[cite: 148]. + * `issueDate`: (String - datetime) Creation timestamp (ISO 8601 UTC)[cite: 148]. + * `nextUpdate`: (String - datetime) Next update timestamp (ISO 8601 UTC)[cite: 149]. + * `fmspc`: (String) Base16-encoded FMSPC[cite: 149]. + * `pceId`: (String) Base16-encoded PCE ID[cite: 149]. + * `tcbType`: (Integer) TCB level composition type[cite: 149]. + * `tcbEvaluationDataNumber`: (Integer) Monotonically increasing sequence number, synchronized across TCB Info and + Enclave Identities, indicating updates[cite: 150, 151, 152]. + * `tdxModule`: (Object - Optional, only for TDX TCB Info)[cite: 153]. + * `mrsigner`: (String) Base16-encoded TDX SEAM module's signer measurement[cite: 154]. + * `attributes`: (String) Base16-encoded "golden" attributes[cite: 154]. + * `attributesMask`: (String) Base16-encoded attributes mask[cite: 154]. + * `tdxModuleIdentities`: (Array - Optional, for multiple TDX SEAM Modules)[cite: 154]. + * `id`: (String) Module identifier[cite: 154]. + * `mrsigner`: (String) Base16-encoded signer measurement[cite: 155]. + * `attributes`: (String) Base16-encoded "golden" attributes[cite: 155]. + * `attributesMask`: (String) Base16-encoded attributes mask[cite: 156]. + * `tcbLevels`: (Array) Sorted list of TCB levels for this module[cite: 157]. + * `tcb`: (Object) + * `isvsvn`: (Integer) ISV SVN[cite: 157]. + * `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 158]. + * `tcbStatus`: (String) "UpToDate", "OutOfDate", or "Revoked"[cite: 158]. + * `advisoryIDs`: (Array - Optional) List of relevant `INTEL-SA-XXXXX` or `INTEL-DOC-XXXXX` + identifiers[cite: 159, 160]. + * `tcbLevels`: (Array) Sorted list of TCB levels for the FMSPC[cite: 160]. + * `tcb`: (Object) + * `sgxtcbcomponents`: (Array - Optional) 16 SGX TCB Components (SVN, Category, Type)[cite: 161]. + * `tdxtcbcomponents`: (Array - Optional, only for TDX TCB Info) 16 TDX TCB Components (SVN, Category, + Type)[cite: 161, 162, 164]. + * `pcesvn`: (Integer) PCE SVN[cite: 161]. + * `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 165]. + * `tcbStatus`: (String) "UpToDate", "HardeningNeeded", "ConfigurationNeeded", " + ConfigurationAndHardeningNeeded", "OutOfDate", "OutOfDateConfigurationNeeded", "Revoked"[cite: 165, 166]. + * `advisoryIDs`: (Array - Optional) List of relevant `INTEL-SA-XXXXX` or `INTEL-DOC-XXXXX` + identifiers[cite: 167, 168]. + * `signature`: (String) Base16-encoded signature over the `tcbInfo` body[cite: 163]. + +--- + +## Appendix B: Enclave Identity V2 [cite: 168] + +This defines the structure of the Enclave Identity V2 JSON response[cite: 168]. + +* `enclaveIdentity`: (Object) + * `id`: (String) Identifier ("QE", "QVE", "QAE", "TD_QE")[cite: 169]. + * `version`: (Integer) Structure version[cite: 169]. + * `issueDate`: (String - datetime) Creation timestamp (ISO 8601 UTC)[cite: 170]. + * `nextUpdate`: (String - datetime) Next update timestamp (ISO 8601 UTC)[cite: 170]. + * `tcbEvaluationDataNumber`: (Integer) Monotonically increasing sequence number, synchronized across TCB Info and + Enclave Identities[cite: 171, 172]. + * `miscselect`: (String) Base16-encoded "golden" miscselect value[cite: 172]. + * `miscselectMask`: (String) Base16-encoded miscselect mask[cite: 172]. + * `attributes`: (String) Base16-encoded "golden" attributes value[cite: 172]. + * `attributesMask`: (String) Base16-encoded attributes mask[cite: 173]. + * `mrsigner`: (String) Base16-encoded mrsigner hash[cite: 173]. + * `isvprodid`: (Integer) Enclave Product ID[cite: 173]. + * `tcbLevels`: (Array) Sorted list of Enclave TCB levels[cite: 173]. + * `tcb`: (Object) + * `isvsvn`: (Integer) Enclave's ISV SVN[cite: 173]. + * `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 174]. + * `tcbStatus`: (String) "UpToDate", "OutOfDate", or "Revoked"[cite: 174, 176]. + * `advisoryIDs`: (Array - Optional) List of relevant `INTEL-SA-XXXXX` or `INTEL-DOC-XXXXX` + identifiers[cite: 177]. + * `signature`: (String) Base16-encoded signature over the `enclaveIdentity` body[cite: 175]. + +--- + +## Appendix C: TCB Evaluation Data Numbers V1 [cite: 177] + +This defines the structure of the TCB Evaluation Data Numbers V1 JSON response[cite: 177]. + +* `tcbEvaluationDataNumbers`: (Object) + * `id`: (String) Identifier ("SGX" or "TDX")[cite: 178]. + * `version`: (Integer) Structure version[cite: 178]. + * `issueDate`: (String - datetime) Creation timestamp (ISO 8601 UTC)[cite: 178]. + * `nextUpdate`: (String - datetime) Suggested next call timestamp (ISO 8601 UTC)[cite: 179]. + * `tcbNumbers`: (Array) List of TCB Evaluation Data Number objects[cite: 179]. + * `tcbEvaluationDataNumber`: (Integer) The number itself[cite: 179]. + * `tcbRecoveryEventDate`: (String - datetime) The date Intel first publishes related collateral (ISO 8601 + UTC)[cite: 179]. + * `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 180, 181]. + * `signature`: (String) Base16-encoded signature over the structure's body[cite: 181]. + +--- + +## Appendix D: PCK Certificate and CRL Specification + +This section refers to an external document that specifies the hierarchy and format of X.509 v3 certificates and X.509 +v2 CRLs issued by Intel for Provisioning Certification Keys[cite: 181]. + +--- + +**Notes on TCB Status and Enforcement:** + +* **Enforcement Grace Periods**: Intel provides "early" and "standard" update parameters, offering different enforcement + grace periods[cite: 182]. The attestation result depends on which parameter is used[cite: 182]. +* **Relying Party Trust Decisions**: Relying parties can use additional factors beyond the attestation result to make + trust decisions[cite: 183]. They might accept risks even if a platform is technically "OutOfDate" due to low-severity + issues[cite: 184]. +* **Communication**: Intel aims to communicate planned deviations via email to registered API subscribers[cite: 185]. diff --git a/crates/intel-dcap-api/tests/mock_api_tests.rs b/crates/intel-dcap-api/tests/mock_api_tests.rs new file mode 100644 index 0000000..34a1f39 --- /dev/null +++ b/crates/intel-dcap-api/tests/mock_api_tests.rs @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use intel_dcap_api::{ApiClient, ApiVersion, CaType, IntelApiError, UpdateType}; +use mockito::Server; +use reqwest::Client; + +// Create a test client without TLS requirements +async fn create_test_client(base_url: &str) -> ApiClient { + // Create a custom client without TLS requirements for testing + ApiClient::new_with_base_url(base_url).expect("Failed to create client") +} + +#[tokio::test] +async fn test_simple_request() { + let mut server = Server::new_async().await; + + // First, test with plain reqwest to ensure mock works + let _m = server + .mock("GET", "/test") + .with_status(200) + .with_body("test") + .create_async() + .await; + + let client = Client::new(); + let resp = client + .get(format!("{}/test", server.url())) + .send() + .await + .unwrap(); + assert_eq!(resp.status(), 200); + assert_eq!(resp.text().await.unwrap(), "test"); +} + +#[tokio::test] +async fn test_tdx_tcb_minimal() { + let mut server = Server::new_async().await; + + // Use minimal response + let _m = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "test123".into(), + )) + .with_status(200) + .with_header("TCB-Info-Issuer-Chain", "test-cert") + .with_body("{}") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_tdx_tcb_info("test123", None, None).await; + + match &result { + Ok(resp) => { + assert_eq!(resp.tcb_info_json, "{}"); + assert_eq!(resp.issuer_chain, "test-cert"); + } + Err(e) => { + eprintln!("Error: {:?}", e); + panic!("Request failed"); + } + } +} + +#[tokio::test] +async fn test_sgx_qe_identity_minimal() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/sgx/certification/v4/qe/identity") + .with_status(200) + .with_header("SGX-Enclave-Identity-Issuer-Chain", "test-cert") + .with_body("{}") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_sgx_qe_identity(None, None).await; + + assert!(result.is_ok()); + let resp = result.unwrap(); + assert_eq!(resp.enclave_identity_json, "{}"); + assert_eq!(resp.issuer_chain, "test-cert"); +} + +#[tokio::test] +async fn test_pck_crl_minimal() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/sgx/certification/v4/pckcrl") + .match_query(mockito::Matcher::UrlEncoded( + "ca".into(), + "processor".into(), + )) + .with_status(200) + .with_header("SGX-PCK-CRL-Issuer-Chain", "test-cert") + .with_body("test-crl") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_pck_crl(CaType::Processor, None).await; + + assert!(result.is_ok()); + let resp = result.unwrap(); + assert_eq!(String::from_utf8_lossy(&resp.crl_data), "test-crl"); + assert_eq!(resp.issuer_chain, "test-cert"); +} + +#[tokio::test] +async fn test_error_handling() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/sgx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded("fmspc".into(), "bad".into())) + .with_status(404) + .with_header("Request-ID", "test-123") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_sgx_tcb_info("bad", None, None).await; + + assert!(result.is_err()); + match result.unwrap_err() { + IntelApiError::ApiError { + status, request_id, .. + } => { + assert_eq!(status.as_u16(), 404); + assert_eq!(request_id, "test-123"); + } + _ => panic!("Wrong error type"), + } +} + +#[tokio::test] +async fn test_update_types() { + let mut server = Server::new_async().await; + + // Test Early update type + let _m1 = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::AllOf(vec![ + mockito::Matcher::UrlEncoded("fmspc".into(), "test".into()), + mockito::Matcher::UrlEncoded("update".into(), "early".into()), + ])) + .with_status(200) + .with_header("TCB-Info-Issuer-Chain", "cert") + .with_body("{\"early\":true}") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client + .get_tdx_tcb_info("test", Some(UpdateType::Early), None) + .await; + assert!(result.is_ok()); + assert_eq!(result.unwrap().tcb_info_json, "{\"early\":true}"); + + // Test Standard update type + let _m2 = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::AllOf(vec![ + mockito::Matcher::UrlEncoded("fmspc".into(), "test".into()), + mockito::Matcher::UrlEncoded("update".into(), "standard".into()), + ])) + .with_status(200) + .with_header("TCB-Info-Issuer-Chain", "cert") + .with_body("{\"standard\":true}") + .create_async() + .await; + + let result2 = client + .get_tdx_tcb_info("test", Some(UpdateType::Standard), None) + .await; + assert!(result2.is_ok()); + assert_eq!(result2.unwrap().tcb_info_json, "{\"standard\":true}"); +} + +#[tokio::test] +async fn test_v3_api_headers() { + let mut server = Server::new_async().await; + + // V3 uses different header names for CRL + let _m = server + .mock("GET", "/sgx/certification/v3/pckcrl") + .match_query(mockito::Matcher::UrlEncoded("ca".into(), "platform".into())) + .with_status(200) + .with_header("SGX-PCK-CRL-Issuer-Chain", "v3-cert") + .with_body("v3-crl-data") + .create_async() + .await; + + let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap(); + let result = client.get_pck_crl(CaType::Platform, None).await; + + assert!(result.is_ok()); + let resp = result.unwrap(); + assert_eq!(String::from_utf8_lossy(&resp.crl_data), "v3-crl-data"); + assert_eq!(resp.issuer_chain, "v3-cert"); +} + +#[tokio::test] +async fn test_sgx_qve_identity() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/sgx/certification/v4/qve/identity") + .with_status(200) + .with_header("SGX-Enclave-Identity-Issuer-Chain", "qve-cert") + .with_body("{\"id\":\"QVE\"}") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_sgx_qve_identity(None, None).await; + + assert!(result.is_ok()); + let resp = result.unwrap(); + assert_eq!(resp.enclave_identity_json, "{\"id\":\"QVE\"}"); + assert_eq!(resp.issuer_chain, "qve-cert"); +} + +#[tokio::test] +async fn test_tdx_qe_identity() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/tdx/certification/v4/qe/identity") + .with_status(200) + .with_header("SGX-Enclave-Identity-Issuer-Chain", "tdx-qe-cert") + .with_body("{\"id\":\"TDX-QE\"}") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_tdx_qe_identity(None, None).await; + + assert!(result.is_ok()); + let resp = result.unwrap(); + assert_eq!(resp.enclave_identity_json, "{\"id\":\"TDX-QE\"}"); + assert_eq!(resp.issuer_chain, "tdx-qe-cert"); +} + +#[tokio::test] +async fn test_error_with_details() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/sgx/certification/v4/pckcert") + .match_query(mockito::Matcher::Any) + .with_status(400) + .with_header("Request-ID", "error-req-123") + .with_header("Error-Code", "InvalidParameter") + .with_header("Error-Message", "PPID format is invalid") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client + .get_pck_certificate_by_ppid("bad", "bad", "bad", "bad", None, None) + .await; + + assert!(result.is_err()); + match result.unwrap_err() { + IntelApiError::ApiError { + status, + request_id, + error_code, + error_message, + } => { + assert_eq!(status.as_u16(), 400); + assert_eq!(request_id, "error-req-123"); + assert_eq!(error_code.as_deref(), Some("InvalidParameter")); + assert_eq!(error_message.as_deref(), Some("PPID format is invalid")); + } + _ => panic!("Wrong error type"), + } +} + +#[tokio::test] +async fn test_sgx_tcb_info() { + let mut server = Server::new_async().await; + + let _m = server + .mock("GET", "/sgx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "00606A6A0000".into(), + )) + .with_status(200) + .with_header("TCB-Info-Issuer-Chain", "sgx-tcb-cert") + .with_body("{\"tcbInfo\":{\"fmspc\":\"00606A6A0000\"}}") + .create_async() + .await; + + let client = create_test_client(&server.url()).await; + let result = client.get_sgx_tcb_info("00606A6A0000", None, None).await; + + assert!(result.is_ok()); + let resp = result.unwrap(); + assert_eq!( + resp.tcb_info_json, + "{\"tcbInfo\":{\"fmspc\":\"00606A6A0000\"}}" + ); + assert_eq!(resp.issuer_chain, "sgx-tcb-cert"); +} diff --git a/crates/intel-dcap-api/tests/real_data_mock_tests.rs b/crates/intel-dcap-api/tests/real_data_mock_tests.rs new file mode 100644 index 0000000..026335d --- /dev/null +++ b/crates/intel-dcap-api/tests/real_data_mock_tests.rs @@ -0,0 +1,901 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use intel_dcap_api::{ + ApiClient, ApiVersion, CaType, CrlEncoding, IntelApiError, PlatformFilter, UpdateType, +}; +use mockito::Server; +use percent_encoding::{percent_encode, NON_ALPHANUMERIC}; +use serde_json::Value; + +// Include real test data +const TDX_TCB_INFO_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_info.json"); +const PCK_CRL_PROCESSOR_DATA: &[u8] = include_bytes!("test_data/pck_crl_processor.json"); +const PCK_CRL_PLATFORM_DATA: &[u8] = include_bytes!("test_data/pck_crl_platform.json"); +const SGX_QE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/sgx_qe_identity.json"); +const SGX_QVE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/sgx_qve_identity.json"); +const TDX_QE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/tdx_qe_identity.json"); +const SGX_TCB_INFO_ALT_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_info_alt.json"); +const SGX_QAE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/sgx_qae_identity.json"); +const FMSPCS_DATA: &[u8] = include_bytes!("test_data/fmspcs.json"); +const SGX_TCB_EVAL_NUMS_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_eval_nums.json"); +const TDX_TCB_EVAL_NUMS_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_eval_nums.json"); +const PCK_CRL_PROCESSOR_DER_DATA: &[u8] = include_bytes!("test_data/pck_crl_processor_der.json"); +const SGX_TCB_INFO_EARLY_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_info_early.json"); +const TDX_TCB_INFO_EVAL17_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_info_eval17.json"); +const FMSPCS_NO_FILTER_DATA: &[u8] = include_bytes!("test_data/fmspcs_no_filter.json"); +// const FMSPCS_ALL_PLATFORMS_DATA: &[u8] = include_bytes!("test_data/fmspcs_all_platforms.json"); // Reserved for future use +const SGX_QE_IDENTITY_V3_DATA: &[u8] = include_bytes!("test_data/sgx_qe_identity_v3.json"); +const SGX_TCB_INFO_V3_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_info_v3.json"); +const TDX_TCB_INFO_ALT_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_info_00806F050000.json"); + +fn parse_test_data(data: &[u8]) -> Value { + serde_json::from_slice(data).expect("Failed to parse test data") +} + +#[tokio::test] +async fn test_tdx_tcb_info_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(TDX_TCB_INFO_DATA); + + // URL encode the issuer chain header value + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "00806F050000".into(), + )) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_tdx_tcb_info("00806F050000", None, None).await; + + if let Err(e) = &result { + eprintln!("Error: {:?}", e); + eprintln!("Server URL: {}", server.url()); + } + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.tcb_info_json, + test_data["tcb_info_json"].as_str().unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); + + // Verify the JSON can be parsed + let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap(); + assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00806F050000"); + assert_eq!(tcb_info["tcbInfo"]["id"], "TDX"); +} + +#[tokio::test] +async fn test_sgx_qe_identity_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_QE_IDENTITY_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/qe/identity") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["enclave_identity_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_qe_identity(None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.enclave_identity_json, + test_data["enclave_identity_json"].as_str().unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); + + // Verify the JSON structure + let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap(); + assert_eq!(identity["enclaveIdentity"]["id"], "QE"); +} + +#[tokio::test] +async fn test_sgx_qve_identity_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_QVE_IDENTITY_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/qve/identity") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["enclave_identity_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_qve_identity(None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify the JSON structure + let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap(); + assert_eq!(identity["enclaveIdentity"]["id"], "QVE"); +} + +#[tokio::test] +async fn test_tdx_qe_identity_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(TDX_QE_IDENTITY_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/tdx/certification/v4/qe/identity") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["enclave_identity_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_tdx_qe_identity(None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify the JSON structure + let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap(); + assert_eq!(identity["enclaveIdentity"]["id"], "TD_QE"); +} + +#[tokio::test] +async fn test_pck_crl_processor_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(PCK_CRL_PROCESSOR_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/pckcrl") + .match_query(mockito::Matcher::UrlEncoded( + "ca".into(), + "processor".into(), + )) + .with_status(200) + .with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["crl_data"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_pck_crl(CaType::Processor, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + String::from_utf8_lossy(&response.crl_data), + test_data["crl_data"].as_str().unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); + + // Verify it's a valid CRL format + let crl_str = String::from_utf8_lossy(&response.crl_data); + assert!(crl_str.contains("BEGIN X509 CRL")); + assert!(crl_str.contains("END X509 CRL")); +} + +#[tokio::test] +async fn test_pck_crl_platform_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(PCK_CRL_PLATFORM_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/pckcrl") + .match_query(mockito::Matcher::UrlEncoded("ca".into(), "platform".into())) + .with_status(200) + .with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["crl_data"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_pck_crl(CaType::Platform, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify issuer chain contains multiple certificates + assert!(response.issuer_chain.contains("BEGIN CERTIFICATE")); + assert!(response.issuer_chain.contains("END CERTIFICATE")); +} + +#[tokio::test] +async fn test_sgx_tcb_info_alt_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_TCB_INFO_ALT_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "00906ED50000".into(), + )) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_tcb_info("00906ED50000", None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify the JSON structure + let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap(); + assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00906ED50000"); + assert_eq!(tcb_info["tcbInfo"]["id"], "SGX"); +} + +#[tokio::test] +async fn test_tdx_tcb_with_update_type() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(TDX_TCB_INFO_DATA); + + // Test with Early update type + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m1 = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::AllOf(vec![ + mockito::Matcher::UrlEncoded("fmspc".into(), "00806F050000".into()), + mockito::Matcher::UrlEncoded("update".into(), "early".into()), + ])) + .with_status(200) + .with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client + .get_tdx_tcb_info("00806F050000", Some(UpdateType::Early), None) + .await; + assert!(result.is_ok()); +} + +#[tokio::test] +async fn test_error_handling_with_intel_headers() { + let mut server = Server::new_async().await; + + // Real error response from Intel API + let _m = server + .mock("GET", "/sgx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "invalid".into(), + )) + .with_status(404) + .with_header("Request-ID", "abc123def456") + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_tcb_info("invalid", None, None).await; + + assert!(result.is_err()); + match result.unwrap_err() { + IntelApiError::ApiError { + status, request_id, .. + } => { + assert_eq!(status.as_u16(), 404); + assert_eq!(request_id, "abc123def456"); + } + _ => panic!("Expected ApiError"), + } +} + +#[tokio::test] +async fn test_v3_api_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(PCK_CRL_PROCESSOR_DATA); + + // V3 uses different header names + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v3/pckcrl") + .match_query(mockito::Matcher::UrlEncoded( + "ca".into(), + "processor".into(), + )) + .with_status(200) + .with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["crl_data"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap(); + let result = client.get_pck_crl(CaType::Processor, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + String::from_utf8_lossy(&response.crl_data), + test_data["crl_data"].as_str().unwrap() + ); +} + +#[tokio::test] +async fn test_sgx_qae_identity_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_QAE_IDENTITY_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/qae/identity") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["enclave_identity_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_qae_identity(None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.enclave_identity_json, + test_data["enclave_identity_json"].as_str().unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); + + // Verify the JSON structure + let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap(); + assert_eq!(identity["enclaveIdentity"]["id"], "QAE"); +} + +#[tokio::test] +async fn test_get_fmspcs_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(FMSPCS_DATA); + + let _m = server + .mock("GET", "/sgx/certification/v4/fmspcs") + .match_query(mockito::Matcher::UrlEncoded( + "platform".into(), + "all".into(), + )) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_body(test_data["fmspcs_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_fmspcs(Some(PlatformFilter::All)).await; + + assert!(result.is_ok()); + let fmspcs_json = result.unwrap(); + assert_eq!(fmspcs_json, test_data["fmspcs_json"].as_str().unwrap()); + + // Verify the JSON structure + let fmspcs: Value = serde_json::from_str(&fmspcs_json).unwrap(); + assert!(fmspcs.is_array()); + assert!(!fmspcs.as_array().unwrap().is_empty()); +} + +#[tokio::test] +async fn test_sgx_tcb_evaluation_data_numbers_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_TCB_EVAL_NUMS_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/tcbevaluationdatanumbers") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header( + "TCB-Evaluation-Data-Numbers-Issuer-Chain", + &encoded_issuer_chain, + ) + .with_body( + test_data["tcb_evaluation_data_numbers_json"] + .as_str() + .unwrap(), + ) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_tcb_evaluation_data_numbers().await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.tcb_evaluation_data_numbers_json, + test_data["tcb_evaluation_data_numbers_json"] + .as_str() + .unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); + + // Verify the JSON structure + let eval_nums: Value = + serde_json::from_str(&response.tcb_evaluation_data_numbers_json).unwrap(); + assert!(eval_nums.is_object()); +} + +#[tokio::test] +async fn test_tdx_tcb_evaluation_data_numbers_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(TDX_TCB_EVAL_NUMS_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/tdx/certification/v4/tcbevaluationdatanumbers") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header( + "TCB-Evaluation-Data-Numbers-Issuer-Chain", + &encoded_issuer_chain, + ) + .with_body( + test_data["tcb_evaluation_data_numbers_json"] + .as_str() + .unwrap(), + ) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_tdx_tcb_evaluation_data_numbers().await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.tcb_evaluation_data_numbers_json, + test_data["tcb_evaluation_data_numbers_json"] + .as_str() + .unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); +} + +#[tokio::test] +async fn test_pck_crl_der_encoding_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(PCK_CRL_PROCESSOR_DER_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + // The DER data is stored as base64 in our test data + let crl_base64 = test_data["crl_data_base64"].as_str().unwrap(); + use base64::{engine::general_purpose, Engine as _}; + let crl_der = general_purpose::STANDARD.decode(crl_base64).unwrap(); + + let _m = server + .mock("GET", "/sgx/certification/v4/pckcrl") + .match_query(mockito::Matcher::AllOf(vec![ + mockito::Matcher::UrlEncoded("ca".into(), "processor".into()), + mockito::Matcher::UrlEncoded("encoding".into(), "der".into()), + ])) + .with_status(200) + .with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain) + .with_body(crl_der) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client + .get_pck_crl(CaType::Processor, Some(CrlEncoding::Der)) + .await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify the response data matches + let response_base64 = general_purpose::STANDARD.encode(&response.crl_data); + assert_eq!(response_base64, crl_base64); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); +} + +#[tokio::test] +async fn test_sgx_tcb_info_early_update_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_TCB_INFO_EARLY_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/sgx/certification/v4/tcb") + .match_query(mockito::Matcher::AllOf(vec![ + mockito::Matcher::UrlEncoded("fmspc".into(), "00906ED50000".into()), + mockito::Matcher::UrlEncoded("update".into(), "early".into()), + ])) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client + .get_sgx_tcb_info("00906ED50000", Some(UpdateType::Early), None) + .await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.tcb_info_json, + test_data["tcb_info_json"].as_str().unwrap() + ); + + // Verify the JSON structure + let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap(); + assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00906ED50000"); +} + +#[tokio::test] +async fn test_tdx_tcb_info_with_eval_number_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(TDX_TCB_INFO_EVAL17_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::AllOf(vec![ + mockito::Matcher::UrlEncoded("fmspc".into(), "00806F050000".into()), + mockito::Matcher::UrlEncoded("tcbEvaluationDataNumber".into(), "17".into()), + ])) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client + .get_tdx_tcb_info("00806F050000", None, Some(17)) + .await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify the response + let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap(); + assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00806F050000"); + assert_eq!(tcb_info["tcbInfo"]["id"], "TDX"); +} + +#[tokio::test] +async fn test_get_fmspcs_v3_should_fail() { + let server = Server::new_async().await; + + // FMSPCs is V4 only + let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap(); + let result = client.get_fmspcs(None).await; + + assert!(result.is_err()); + match result.unwrap_err() { + IntelApiError::UnsupportedApiVersion(msg) => { + assert!(msg.contains("API v4 only")); + } + _ => panic!("Expected UnsupportedApiVersion error"), + } +} + +#[tokio::test] +async fn test_tcb_evaluation_data_numbers_v3_should_fail() { + let server = Server::new_async().await; + + // TCB evaluation data numbers is V4 only + let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap(); + + let sgx_result = client.get_sgx_tcb_evaluation_data_numbers().await; + assert!(sgx_result.is_err()); + match sgx_result.unwrap_err() { + IntelApiError::UnsupportedApiVersion(msg) => { + assert!(msg.contains("requires API v4")); + } + _ => panic!("Expected UnsupportedApiVersion error"), + } + + let tdx_result = client.get_tdx_tcb_evaluation_data_numbers().await; + assert!(tdx_result.is_err()); + match tdx_result.unwrap_err() { + IntelApiError::UnsupportedApiVersion(msg) => { + assert!(msg.contains("requires API v4")); + } + _ => panic!("Expected UnsupportedApiVersion error"), + } +} + +#[tokio::test] +async fn test_get_fmspcs_no_filter_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(FMSPCS_NO_FILTER_DATA); + + let _m = server + .mock("GET", "/sgx/certification/v4/fmspcs") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_body(test_data["fmspcs_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_fmspcs(None).await; + + assert!(result.is_ok()); + let fmspcs_json = result.unwrap(); + assert_eq!(fmspcs_json, test_data["fmspcs_json"].as_str().unwrap()); +} + +#[tokio::test] +async fn test_sgx_qe_identity_v3_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_QE_IDENTITY_V3_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + // V3 uses different header names + let _m = server + .mock("GET", "/sgx/certification/v3/qe/identity") + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["enclave_identity_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap(); + let result = client.get_sgx_qe_identity(None, None).await; + + if let Err(e) = &result { + eprintln!("Error in V3 test: {:?}", e); + } + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.enclave_identity_json, + test_data["enclave_identity_json"].as_str().unwrap() + ); + assert_eq!( + response.issuer_chain, + test_data["issuer_chain"].as_str().unwrap() + ); +} + +#[tokio::test] +async fn test_sgx_tcb_info_v3_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(SGX_TCB_INFO_V3_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + // V3 uses different header names + let _m = server + .mock("GET", "/sgx/certification/v3/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "00906ED50000".into(), + )) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("SGX-TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap(); + let result = client.get_sgx_tcb_info("00906ED50000", None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert_eq!( + response.tcb_info_json, + test_data["tcb_info_json"].as_str().unwrap() + ); + + // Verify the JSON structure + let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap(); + assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00906ED50000"); +} + +#[tokio::test] +async fn test_tdx_tcb_info_alternate_fmspc_with_real_data() { + let mut server = Server::new_async().await; + let test_data = parse_test_data(TDX_TCB_INFO_ALT_DATA); + + let issuer_chain = test_data["issuer_chain"].as_str().unwrap(); + let encoded_issuer_chain = + percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string(); + + let _m = server + .mock("GET", "/tdx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "00806F050000".into(), + )) + .with_status(200) + .with_header("Content-Type", "application/json") + .with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain) + .with_body(test_data["tcb_info_json"].as_str().unwrap()) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_tdx_tcb_info("00806F050000", None, None).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + + // Verify we got the same data as the first TDX TCB info test + let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap(); + assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00806F050000"); + assert_eq!(tcb_info["tcbInfo"]["id"], "TDX"); +} + +#[tokio::test] +async fn test_platform_filter_combinations() { + let mut server = Server::new_async().await; + + // Test with different platform filters + let filters = vec![ + (Some(PlatformFilter::All), "all"), + (Some(PlatformFilter::Client), "client"), + (Some(PlatformFilter::E3), "E3"), + (Some(PlatformFilter::E5), "E5"), + (None, ""), + ]; + + for (filter, query_value) in filters { + let mock_response = r#"[{"fmspc": "00906ED50000", "platform": "SGX"}]"#; + + let mut mock = server.mock("GET", "/sgx/certification/v4/fmspcs"); + + if !query_value.is_empty() { + mock = mock.match_query(mockito::Matcher::UrlEncoded( + "platform".into(), + query_value.into(), + )); + } + + let _m = mock + .with_status(200) + .with_header("Content-Type", "application/json") + .with_body(mock_response) + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_fmspcs(filter).await; + + assert!(result.is_ok()); + let response = result.unwrap(); + assert!(response.contains("00906ED50000")); + } +} + +#[tokio::test] +async fn test_error_scenarios() { + let mut server = Server::new_async().await; + + // Test 404 with Error headers + let _m = server + .mock("GET", "/sgx/certification/v4/tcb") + .match_query(mockito::Matcher::UrlEncoded( + "fmspc".into(), + "invalid".into(), + )) + .with_status(404) + .with_header("Request-ID", "test123") + .with_header("Error-Code", "InvalidParameter") + .with_header("Error-Message", "Invalid FMSPC format") + .create_async() + .await; + + let client = ApiClient::new_with_base_url(server.url()).unwrap(); + let result = client.get_sgx_tcb_info("invalid", None, None).await; + + assert!(result.is_err()); + match result.unwrap_err() { + IntelApiError::ApiError { + status, + request_id, + error_code, + error_message, + } => { + assert_eq!(status.as_u16(), 404); + assert_eq!(request_id, "test123"); + assert_eq!(error_code.as_deref(), Some("InvalidParameter")); + assert_eq!(error_message.as_deref(), Some("Invalid FMSPC format")); + } + _ => panic!("Expected ApiError"), + } +} diff --git a/crates/intel-dcap-api/tests/test_data/fmspcs.json b/crates/intel-dcap-api/tests/test_data/fmspcs.json new file mode 100644 index 0000000..93e4cc8 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/fmspcs.json @@ -0,0 +1,3 @@ +{ + "fmspcs_json": "[{\"fmspc\":\"00A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"70A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"00A06E050000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EA50000\",\"platform\":\"client\"},{\"fmspc\":\"20606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"50806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A067110000\",\"platform\":\"E3\"},{\"fmspc\":\"00606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"00706E470000\",\"platform\":\"client\"},{\"fmspc\":\"00806EA60000\",\"platform\":\"client\"},{\"fmspc\":\"00706A800000\",\"platform\":\"client\"},{\"fmspc\":\"00706A100000\",\"platform\":\"client\"},{\"fmspc\":\"F0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EC50000\",\"platform\":\"client\"},{\"fmspc\":\"90806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06F010000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"B0C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906ED50000\",\"platform\":\"E3\"},{\"fmspc\":\"40A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"D0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A065510000\",\"platform\":\"client\"},{\"fmspc\":\"10A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"30606A000000\",\"platform\":\"E5\"},{\"fmspc\":\"20806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EA10000\",\"platform\":\"E3\"},{\"fmspc\":\"30806F040000\",\"platform\":\"E5\"},{\"fmspc\":\"C0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"30A06D050000\",\"platform\":\"E5\"},{\"fmspc\":\"60C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F050000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"20906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"90C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"80C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EB10000\",\"platform\":\"client\"},{\"fmspc\":\"00606A000000\",\"platform\":\"E5\"}]" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/fmspcs_all_platforms.json b/crates/intel-dcap-api/tests/test_data/fmspcs_all_platforms.json new file mode 100644 index 0000000..93e4cc8 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/fmspcs_all_platforms.json @@ -0,0 +1,3 @@ +{ + "fmspcs_json": "[{\"fmspc\":\"00A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"70A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"00A06E050000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EA50000\",\"platform\":\"client\"},{\"fmspc\":\"20606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"50806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A067110000\",\"platform\":\"E3\"},{\"fmspc\":\"00606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"00706E470000\",\"platform\":\"client\"},{\"fmspc\":\"00806EA60000\",\"platform\":\"client\"},{\"fmspc\":\"00706A800000\",\"platform\":\"client\"},{\"fmspc\":\"00706A100000\",\"platform\":\"client\"},{\"fmspc\":\"F0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EC50000\",\"platform\":\"client\"},{\"fmspc\":\"90806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06F010000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"B0C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906ED50000\",\"platform\":\"E3\"},{\"fmspc\":\"40A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"D0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A065510000\",\"platform\":\"client\"},{\"fmspc\":\"10A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"30606A000000\",\"platform\":\"E5\"},{\"fmspc\":\"20806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EA10000\",\"platform\":\"E3\"},{\"fmspc\":\"30806F040000\",\"platform\":\"E5\"},{\"fmspc\":\"C0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"30A06D050000\",\"platform\":\"E5\"},{\"fmspc\":\"60C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F050000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"20906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"90C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"80C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EB10000\",\"platform\":\"client\"},{\"fmspc\":\"00606A000000\",\"platform\":\"E5\"}]" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/fmspcs_no_filter.json b/crates/intel-dcap-api/tests/test_data/fmspcs_no_filter.json new file mode 100644 index 0000000..93e4cc8 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/fmspcs_no_filter.json @@ -0,0 +1,3 @@ +{ + "fmspcs_json": "[{\"fmspc\":\"00A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"70A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"00A06E050000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EA50000\",\"platform\":\"client\"},{\"fmspc\":\"20606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"50806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A067110000\",\"platform\":\"E3\"},{\"fmspc\":\"00606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"00706E470000\",\"platform\":\"client\"},{\"fmspc\":\"00806EA60000\",\"platform\":\"client\"},{\"fmspc\":\"00706A800000\",\"platform\":\"client\"},{\"fmspc\":\"00706A100000\",\"platform\":\"client\"},{\"fmspc\":\"F0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EC50000\",\"platform\":\"client\"},{\"fmspc\":\"90806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06F010000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"B0C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906ED50000\",\"platform\":\"E3\"},{\"fmspc\":\"40A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"D0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A065510000\",\"platform\":\"client\"},{\"fmspc\":\"10A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"30606A000000\",\"platform\":\"E5\"},{\"fmspc\":\"20806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EA10000\",\"platform\":\"E3\"},{\"fmspc\":\"30806F040000\",\"platform\":\"E5\"},{\"fmspc\":\"C0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"30A06D050000\",\"platform\":\"E5\"},{\"fmspc\":\"60C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F050000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"20906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"90C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"80C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EB10000\",\"platform\":\"client\"},{\"fmspc\":\"00606A000000\",\"platform\":\"E5\"}]" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/pck_crl_platform.json b/crates/intel-dcap-api/tests/test_data/pck_crl_platform.json new file mode 100644 index 0000000..bdad22c --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/pck_crl_platform.json @@ -0,0 +1,4 @@ +{ + "crl_data": "-----BEGIN X509 CRL-----\nMIIKYTCCCggCAQEwCgYIKoZIzj0EAwIwcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBD\nSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDUy\nNzE5MjUwNVoXDTI1MDYyNjE5MjUwNVowggk0MDMCFG/DTlAj5yiSNDXWGqS4PGGB\nZq01Fw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAO+ubpcV/KE7h+Mz\n6CYe1tmQqSatFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAP1ghkhi\nnLpzB4tNSS9LPqdBrQjNFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIV\nAIr5JBhOHVr93XPD1joS9ei1c35WFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMK\nAQEwNAIVALEleXjPqczdB1mr+MXKcvrjp4qbFw0yNTA1MjcxOTI1MDVaMAwwCgYD\nVR0VBAMKAQEwMwIUdP6mFKlyvg4oQ/IFmDWBHthy+bMXDTI1MDUyNzE5MjUwNVow\nDDAKBgNVHRUEAwoBATA0AhUA+cTvVrOrSNV34Qi67fS/iAFCFLkXDTI1MDUyNzE5\nMjUwNVowDDAKBgNVHRUEAwoBATAzAhQHHeB3j55fxPKHjzDWsHyaMOazCxcNMjUw\nNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDQCFQDN4kJPlyzqlP8jmTf02AwlAp3W\nCxcNMjUwNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFGwzGeUQm2RQfTzxEyzg\nA0nvUnMZFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAN8I11a2anSX\n9DtbtYraBNP096k3Fw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwMwIUKK9I\nW2z2fkCaOdXLWu5FmPeo+nsXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0\nAhUA+4strsCSytqKqbxP8vHCDQNGZowXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUE\nAwoBATA0AhUAzUhQrFK9zGmmpvBYyLxXu9C1+GQXDTI1MDUyNzE5MjUwNVowDDAK\nBgNVHRUEAwoBATA0AhUAmU3TZm9SdfuAX5XdAr1QyyZ52K0XDTI1MDUyNzE5MjUw\nNVowDDAKBgNVHRUEAwoBATAzAhQHAhNpACUidNkDXu31RXRi+tDvTBcNMjUwNTI3\nMTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFGHyv3Pjm04EqifYAb1z0kMZtb+AFw0y\nNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwMwIUOZK+hRuWkC7/OJWebC7/GwZR\npLUXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATAzAhQP2kOgC2jqebfC3q6s\nC0mL37KvkBcNMjUwNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFGOfE5pQQP3P\n8ZHopPsb8IbtYDlxFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAJWd\nUz+SSdweUTVEzcgwvxm38fMBFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEw\nMwIUeuN3SKn5EvTGO6erB8WTzh0dEYEXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUE\nAwoBATAzAhQTiEszJpk4wZWqFw/KddoXdTjfCxcNMjUwNTI3MTkyNTA1WjAMMAoG\nA1UdFQQDCgEBMDQCFQCF08k4G3en4E0RnJ5a1nSf8/+rhxcNMjUwNTI3MTkyNTA1\nWjAMMAoGA1UdFQQDCgEBMDQCFQCTiHykQR56kjvR/tKBmylJ8gG1tBcNMjUwNTI3\nMTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFCSY3GKDkwmW/YvyOjesviajvtRXFw0y\nNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAIpm8adJSIZnaJzDkDrFTGYr\ncS5zFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAK/BNhC902y3mF0Q\nZIGogNOgH9oHFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAO/gSywz\n0DaqyWymc78emke2TVy7Fw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIV\nAIPZrI2LtQnRxsgJrXEuhDBVntfzFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMK\nAQEwMwIUeTH9ULUHHBu/xbe23ti0W52LhSkXDTI1MDUyNzE5MjUwNVowDDAKBgNV\nHRUEAwoBATAzAhQfog4pcL3l1X97jd+DOUhOHx0IIxcNMjUwNTI3MTkyNTA1WjAM\nMAoGA1UdFQQDCgEBMDMCFB6HssOzLY0j5BHO80GXuVrwyK31Fw0yNTA1MjcxOTI1\nMDVaMAwwCgYDVR0VBAMKAQEwNAIVAJr9LukKRzVQoWfZlpEUN8dQLR8JFw0yNTA1\nMjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwMwIURIGw8RcooTtpbT6px3CgsV7FjdoX\nDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0AhUAp4WfV5gu8OZ9N7yO8u9a\nyDX/GqkXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0AhUAnWd1O4HkcJCu\np2P77ExFSbzbmTMXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATAzAhQ0v7t6\nHZxWgUfhGLYU97du0+9o3xcNMjUwNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMC\nFCw8xv6SedsVFtXOOfKomM2loXXhFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMK\nAQEwMwIUcXlIaHUJI0vpeeS33ObzG+9ktowXDTI1MDUyNzE5MjUwNVowDDAKBgNV\nHRUEAwoBATA0AhUAnXbvLDnBNuhli25zlrHXRFonYx8XDTI1MDUyNzE5MjUwNVow\nDDAKBgNVHRUEAwoBATA0AhUAw+Al/KmV829ZtIRnk54+NOY2Gm8XDTI1MDUyNzE5\nMjUwNVowDDAKBgNVHRUEAwoBATA0AhUAjF9rMlfaBbF0KeLmG6ll1nMwYGoXDTI1\nMDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0AhUAoXxRci7B4MMnj+i98FIFnL7E\n5kgXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQEw\nHwYDVR0jBBgwFoAUlW9dzb0b4elAScnU9DPOAVcL3lQwCgYIKoZIzj0EAwIDRwAw\nRAIgUpcU4PTB0Bc3qvMCWYHx5EEDXqxSLgCoYKp4C/GgxpkCIE/xDOudQg2ldK1m\nABQqvvzE8ibtGcDyaq1WI56Wv1bl\n-----END X509 CRL-----\n", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/pck_crl_processor.json b/crates/intel-dcap-api/tests/test_data/pck_crl_processor.json new file mode 100644 index 0000000..ec77f5b --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/pck_crl_processor.json @@ -0,0 +1,4 @@ +{ + "crl_data": "-----BEGIN X509 CRL-----\nMIIBKjCB0QIBATAKBggqhkjOPQQDAjBxMSMwIQYDVQQDDBpJbnRlbCBTR1ggUENL\nIFByb2Nlc3NvciBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDUy\nNzE4NDYyNVoXDTI1MDYyNjE4NDYyNVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQY\nMBaAFNDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMCA0gAMEUCIQDtYSVu\nju3asUsAGZ2Hbe9uvZmk5zvLtwDk38KrWfb5zAIgSfk6Dmqhc4+moiRuRz0wQqLj\nckwO2BEUviI+nZfN75I=\n-----END X509 CRL-----\n", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICmDCCAj6gAwIBAgIVANDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHExIzAh\nBgNVBAMMGkludGVsIFNHWCBQQ0sgUHJvY2Vzc29yIENBMRowGAYDVQQKDBFJbnRl\nbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNB\nMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL9q+NMp2IOg\ntdl1bk/uWZ5+TGQm8aCi8z78fs+fKCQ3d+uDzXnVTAT2ZhDCifyIuJwvN3wNBp9i\nHBSSMJMJrBOjgbswgbgwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqww\nUgYDVR0fBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNl\ncnZpY2VzLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFNDo\nqtp11/kuSReYPHsUZdDV8llNMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEAMAoGCCqGSM49BAMCA0gAMEUCIQCJgTbtVqOyZ1m3jqiAXM6QYa6r5sWS\n4y/G7y8uIJGxdwIgRqPvBSKzzQagBLQq5s5A70pdoiaRJ8z/0uDz4NgV91k=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/pck_crl_processor_der.json b/crates/intel-dcap-api/tests/test_data/pck_crl_processor_der.json new file mode 100644 index 0000000..3421b50 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/pck_crl_processor_der.json @@ -0,0 +1,4 @@ +{ + "crl_data_base64": "MIIBKjCB0QIBATAKBggqhkjOPQQDAjBxMSMwIQYDVQQDDBpJbnRlbCBTR1ggUENLIFByb2Nlc3NvciBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDUyNzE5MjMwOVoXDTI1MDYyNjE5MjMwOVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFNDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMCA0gAMEUCIQC2Q0kz4IioOr5HsdYUY8b0m3XSS6FwuKVUAIvroURNHgIgIo5mAP1gCBeW719AqdBaxnoNuUypHQ/X+1zfDiY69ec=", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICmDCCAj6gAwIBAgIVANDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHExIzAh\nBgNVBAMMGkludGVsIFNHWCBQQ0sgUHJvY2Vzc29yIENBMRowGAYDVQQKDBFJbnRl\nbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNB\nMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL9q+NMp2IOg\ntdl1bk/uWZ5+TGQm8aCi8z78fs+fKCQ3d+uDzXnVTAT2ZhDCifyIuJwvN3wNBp9i\nHBSSMJMJrBOjgbswgbgwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqww\nUgYDVR0fBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNl\ncnZpY2VzLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFNDo\nqtp11/kuSReYPHsUZdDV8llNMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEAMAoGCCqGSM49BAMCA0gAMEUCIQCJgTbtVqOyZ1m3jqiAXM6QYa6r5sWS\n4y/G7y8uIJGxdwIgRqPvBSKzzQagBLQq5s5A70pdoiaRJ8z/0uDz4NgV91k=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_qae_identity.json b/crates/intel-dcap-api/tests/test_data/sgx_qae_identity.json new file mode 100644 index 0000000..4c4c329 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_qae_identity.json @@ -0,0 +1,4 @@ +{ + "enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QAE\",\"version\":2,\"issueDate\":\"2025-05-27T19:31:54Z\",\"nextUpdate\":\"2025-06-26T19:31:54Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"01000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":3,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},\"signature\":\"a5dfb799f78ea3d32f7760f2b529fc80fe7efa3236c9888e8ece69379e206880f0b67b9407a9b139feb5007b785601f09050d4963116c1bd2cd5def4e3a11da8\"}", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_qe_identity.json b/crates/intel-dcap-api/tests/test_data/sgx_qe_identity.json new file mode 100644 index 0000000..3c4c157 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_qe_identity.json @@ -0,0 +1,4 @@ +{ + "enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2025-05-27T19:05:27Z\",\"nextUpdate\":\"2025-06-26T19:05:27Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00202\",\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]}]},\"signature\":\"5ecc03899589b58e8216c69c3439d1a9310d8af9ebfb37e61518a2a3cb801e0019a5fc955e38e6becc1c75a8a05bb337c93c1a61009a34cc8291fdd82f67ae19\"}", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_qe_identity_v3.json b/crates/intel-dcap-api/tests/test_data/sgx_qe_identity_v3.json new file mode 100644 index 0000000..f545dbb --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_qe_identity_v3.json @@ -0,0 +1,4 @@ +{ + "enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2025-05-27T18:38:43Z\",\"nextUpdate\":\"2025-06-26T18:38:43Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"}]},\"signature\":\"b4cc7bd5ee712a62cf6fbad0a052bd44194a25a5313b4bfff241a3c08ff00bcf0d15f1feb3a369bd9b362a6e5104c82f06d827ef676e70fdccf947566b77f6e8\"}", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_qve_identity.json b/crates/intel-dcap-api/tests/test_data/sgx_qve_identity.json new file mode 100644 index 0000000..2a29b18 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_qve_identity.json @@ -0,0 +1,4 @@ +{ + "enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QVE\",\"version\":2,\"issueDate\":\"2025-05-27T19:31:54Z\",\"nextUpdate\":\"2025-06-26T19:31:54Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"01000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},\"signature\":\"3bb26b16155b207f884ef10fad705129bf566ccc9e6bd4e9907c99bc0ccd6deb6b6451b103b495926c582ece9d22c491f05a627806e09ca07e1063de898460e7\"}", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_tcb_eval_nums.json b/crates/intel-dcap-api/tests/test_data/sgx_tcb_eval_nums.json new file mode 100644 index 0000000..9076051 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_tcb_eval_nums.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_evaluation_data_numbers_json": "{\"tcbEvaluationDataNumbers\":{\"id\":\"SGX\",\"version\":1,\"issueDate\":\"2025-05-27T19:04:23Z\",\"nextUpdate\":\"2025-06-26T19:04:23Z\",\"tcbEvalNumbers\":[{\"tcbEvaluationDataNumber\":19,\"tcbRecoveryEventDate\":\"2025-05-13T00:00:00Z\",\"tcbDate\":\"2025-05-14T00:00:00Z\"},{\"tcbEvaluationDataNumber\":18,\"tcbRecoveryEventDate\":\"2024-11-12T00:00:00Z\",\"tcbDate\":\"2024-11-13T00:00:00Z\"},{\"tcbEvaluationDataNumber\":17,\"tcbRecoveryEventDate\":\"2024-03-12T00:00:00Z\",\"tcbDate\":\"2024-03-13T00:00:00Z\"}]},\"signature\":\"19799ae10942dc046340aa279123fe743e2ab51c862ab6a04abdaab86083013ca81ac1963aa08f1a3b44f0c12e9c6d094cb98aa5ca51bc40439833ada6f0e9e1\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_00906ED50000.json b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_00906ED50000.json new file mode 100644 index 0000000..8e17eee --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_00906ED50000.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"id\":\"SGX\",\"version\":3,\"issueDate\":\"2025-05-27T19:31:07Z\",\"nextUpdate\":\"2025-06-26T19:31:07Z\",\"fmspc\":\"00906ED50000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":17,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":21},{\"svn\":21},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":21},{\"svn\":21},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":20},{\"svn\":20},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00828\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":20},{\"svn\":20},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":19},{\"svn\":19},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":19},{\"svn\":19},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00161\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":15},{\"svn\":15},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":15},{\"svn\":15},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":14},{\"svn\":14},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00161\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":14},{\"svn\":14},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":13},{\"svn\":13},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":2},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":13},{\"svn\":13},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2},{\"svn\":2},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":7},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":1},{\"svn\":1},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":7},\"tcbDate\":\"2019-01-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00233\",\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":1},{\"svn\":1},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":6},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00203\",\"INTEL-SA-00233\",\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]}]},\"signature\":\"6110be36e7515cd536981fedf215ef6b937de0f4c758b672557395a2dc987d94028eb8c4ee3c065bb5585fb2953233160253064128157a48cac7a76822f6aacb\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_alt.json b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_alt.json new file mode 100644 index 0000000..8e17eee --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_alt.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"id\":\"SGX\",\"version\":3,\"issueDate\":\"2025-05-27T19:31:07Z\",\"nextUpdate\":\"2025-06-26T19:31:07Z\",\"fmspc\":\"00906ED50000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":17,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":21},{\"svn\":21},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":21},{\"svn\":21},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":20},{\"svn\":20},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00828\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":20},{\"svn\":20},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":19},{\"svn\":19},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":19},{\"svn\":19},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00161\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":15},{\"svn\":15},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":15},{\"svn\":15},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":14},{\"svn\":14},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00161\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":14},{\"svn\":14},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":13},{\"svn\":13},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":2},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":13},{\"svn\":13},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2},{\"svn\":2},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":7},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":1},{\"svn\":1},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":7},\"tcbDate\":\"2019-01-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00233\",\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":1},{\"svn\":1},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":6},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00203\",\"INTEL-SA-00233\",\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]}]},\"signature\":\"6110be36e7515cd536981fedf215ef6b937de0f4c758b672557395a2dc987d94028eb8c4ee3c065bb5585fb2953233160253064128157a48cac7a76822f6aacb\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_early.json b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_early.json new file mode 100644 index 0000000..b57d7eb --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_early.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"id\":\"SGX\",\"version\":3,\"issueDate\":\"2025-05-27T19:31:08Z\",\"nextUpdate\":\"2025-06-26T19:31:08Z\",\"fmspc\":\"00906ED50000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":19,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":22},{\"svn\":22},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2025-05-14T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":22},{\"svn\":22},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2025-05-14T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":21},{\"svn\":21},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01153\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":21},{\"svn\":21},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":20},{\"svn\":20},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":14},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00828\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":20},{\"svn\":20},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":19},{\"svn\":19},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":19},{\"svn\":19},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00161\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":17},{\"svn\":17},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":15},{\"svn\":15},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00161\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":15},{\"svn\":15},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":14},{\"svn\":14},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":6},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00161\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":14},{\"svn\":14},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":13},{\"svn\":13},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":2},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00219\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":13},{\"svn\":13},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2},{\"svn\":2},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":7},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":1},{\"svn\":1},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":7},\"tcbDate\":\"2019-01-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00233\",\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":1},{\"svn\":1},{\"svn\":2},{\"svn\":4},{\"svn\":1},{\"svn\":128},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":6},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00203\",\"INTEL-SA-00233\",\"INTEL-SA-00220\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00219\",\"INTEL-SA-00161\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00614\",\"INTEL-SA-00617\",\"INTEL-SA-00289\",\"INTEL-SA-00828\",\"INTEL-SA-01153\",\"INTEL-SA-00334\",\"INTEL-SA-00615\"]}]},\"signature\":\"f923da7909b959d047642857106e14d3198da1222fc9bb0d6eb4aab571d55c3c583488eec8b06445666d3c19f02d2ec72cde4c2247886684d93fb70ed1f67efc\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_v3.json b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_v3.json new file mode 100644 index 0000000..16c1925 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/sgx_tcb_info_v3.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"version\":2,\"issueDate\":\"2025-05-27T19:31:07Z\",\"nextUpdate\":\"2025-06-26T19:31:07Z\",\"fmspc\":\"00906ED50000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":17,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomp01svn\":21,\"sgxtcbcomp02svn\":21,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":14,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":13},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":21,\"sgxtcbcomp02svn\":21,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":13},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":20,\"sgxtcbcomp02svn\":20,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":14,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":20,\"sgxtcbcomp02svn\":20,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":19,\"sgxtcbcomp02svn\":19,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":6,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":19,\"sgxtcbcomp02svn\":19,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":13},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":17,\"sgxtcbcomp02svn\":17,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":6,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":17,\"sgxtcbcomp02svn\":17,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":6,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":17,\"sgxtcbcomp02svn\":17,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":17,\"sgxtcbcomp02svn\":17,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":15,\"sgxtcbcomp02svn\":15,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":6,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":15,\"sgxtcbcomp02svn\":15,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":10},\"tcbDate\":\"2020-06-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":14,\"sgxtcbcomp02svn\":14,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":6,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":14,\"sgxtcbcomp02svn\":14,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":10},\"tcbDate\":\"2019-12-11T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":13,\"sgxtcbcomp02svn\":13,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":2,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":13,\"sgxtcbcomp02svn\":13,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":9},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\"},{\"tcb\":{\"sgxtcbcomp01svn\":2,\"sgxtcbcomp02svn\":2,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":7},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":1,\"sgxtcbcomp02svn\":1,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":7},\"tcbDate\":\"2019-01-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"sgxtcbcomp01svn\":1,\"sgxtcbcomp02svn\":1,\"sgxtcbcomp03svn\":2,\"sgxtcbcomp04svn\":4,\"sgxtcbcomp05svn\":1,\"sgxtcbcomp06svn\":128,\"sgxtcbcomp07svn\":0,\"sgxtcbcomp08svn\":0,\"sgxtcbcomp09svn\":0,\"sgxtcbcomp10svn\":0,\"sgxtcbcomp11svn\":0,\"sgxtcbcomp12svn\":0,\"sgxtcbcomp13svn\":0,\"sgxtcbcomp14svn\":0,\"sgxtcbcomp15svn\":0,\"sgxtcbcomp16svn\":0,\"pcesvn\":6},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"}]},\"signature\":\"fd7fe639c792132bce84469fb9a95648657c4f72c45b71f753b06c2597d09fd01fd8f2619f15f1faf1b1136d9fa5c7f2bb92252730a441090515dbefd60cc4e4\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/tdx_qe_identity.json b/crates/intel-dcap-api/tests/test_data/tdx_qe_identity.json new file mode 100644 index 0000000..7a77ea3 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/tdx_qe_identity.json @@ -0,0 +1,4 @@ +{ + "enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"TD_QE\",\"version\":2,\"issueDate\":\"2025-05-27T19:22:46Z\",\"nextUpdate\":\"2025-06-26T19:22:46Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},\"signature\":\"cba4e80e12e114ac591bcf43c155cabb2f48bc6e629dce6d5aab26127c7c23b1a3eafc52f60bab7ac39aff2866431494315fd553fa73d9688a802383eea4edc9\"}", + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/tdx_tcb_eval_nums.json b/crates/intel-dcap-api/tests/test_data/tdx_tcb_eval_nums.json new file mode 100644 index 0000000..545318e --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/tdx_tcb_eval_nums.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_evaluation_data_numbers_json": "{\"tcbEvaluationDataNumbers\":{\"id\":\"TDX\",\"version\":1,\"issueDate\":\"2025-05-27T18:50:21Z\",\"nextUpdate\":\"2025-06-26T18:50:21Z\",\"tcbEvalNumbers\":[{\"tcbEvaluationDataNumber\":19,\"tcbRecoveryEventDate\":\"2025-05-13T00:00:00Z\",\"tcbDate\":\"2025-05-14T00:00:00Z\"},{\"tcbEvaluationDataNumber\":18,\"tcbRecoveryEventDate\":\"2024-11-12T00:00:00Z\",\"tcbDate\":\"2024-11-13T00:00:00Z\"},{\"tcbEvaluationDataNumber\":17,\"tcbRecoveryEventDate\":\"2024-03-12T00:00:00Z\",\"tcbDate\":\"2024-03-13T00:00:00Z\"}]},\"signature\":\"507f5f4406a15e9fa311142b41c47da082d10ce35e863491061c49adac188a2e974561b134a7eff9e10f98be2c5bd5e28c18e3dc6327067fd1a5459d48cd1e58\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/tdx_tcb_info.json b/crates/intel-dcap-api/tests/test_data/tdx_tcb_info.json new file mode 100644 index 0000000..c2e4b43 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/tdx_tcb_info.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2025-05-27T19:31:43Z\",\"nextUpdate\":\"2025-06-26T19:31:43Z\",\"fmspc\":\"00806F050000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":17,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":6,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]}]},\"signature\":\"4eb9de091235241a82cdede1eea6ba1e7df3e158e58591ae2b743ff9fc8ab3774bbb68758da9d588486f84df74b00c10081fb49b7aafee980c70a8f54e28b4f2\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/tdx_tcb_info_00806F050000.json b/crates/intel-dcap-api/tests/test_data/tdx_tcb_info_00806F050000.json new file mode 100644 index 0000000..c313dc4 --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/tdx_tcb_info_00806F050000.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2025-05-27T19:25:02Z\",\"nextUpdate\":\"2025-06-26T19:25:02Z\",\"fmspc\":\"00806F050000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":17,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":6,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]}]},\"signature\":\"05d350ab0840b40362419623d36b11e5fcfaebcf0926deb6058232a66a2bbd12e347e8dc5e843d13351714144b3aefd23425f396e15b1a1b7fb673415122b82d\"}" +} \ No newline at end of file diff --git a/crates/intel-dcap-api/tests/test_data/tdx_tcb_info_eval17.json b/crates/intel-dcap-api/tests/test_data/tdx_tcb_info_eval17.json new file mode 100644 index 0000000..927484c --- /dev/null +++ b/crates/intel-dcap-api/tests/test_data/tdx_tcb_info_eval17.json @@ -0,0 +1,4 @@ +{ + "issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n", + "tcb_info_json": "{\"tcbInfo\":{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2025-05-27T19:31:44Z\",\"nextUpdate\":\"2025-06-26T19:31:44Z\",\"fmspc\":\"00806F050000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":17,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":6,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\"]}]},\"signature\":\"1c00c4b83ac0c9abe692b11a59df58604c6d638472822c11d7cb7753a5826be5cb3f8201da78bbaca85429c0e15a51255fc56dcbdd5e913f92e658b0cac377b1\"}" +} \ No newline at end of file diff --git a/packages/teepotCrate/default.nix b/packages/teepotCrate/default.nix index 41263c3..07bad66 100644 --- a/packages/teepotCrate/default.nix +++ b/packages/teepotCrate/default.nix @@ -49,6 +49,7 @@ let # Custom test data files (maybeMissing (inputs.src + "/crates/teepot/tests/data")) (maybeMissing (inputs.src + "/crates/teepot-vault/tests/data")) + (maybeMissing (inputs.src + "/crates/intel-dcap-api/tests/test_data")) ]; }; From bb9c5b195e59a87f656814c0b1acc0e9268f3395 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 28 May 2025 11:00:03 +0200 Subject: [PATCH 105/114] feat(intel-dcap-api): add automatic retry logic for 429 rate limiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `max_retries` field to ApiClient with default of 3 retries - Implement `execute_with_retry()` helper method in helpers.rs - Update all HTTP requests to use retry wrapper for automatic 429 handling - Add `TooManyRequests` error variant with request_id and retry_after fields - Respect Retry-After header duration before retrying requests - Add `set_max_retries()` method to configure retry behavior (0 disables) - Update documentation and add handle_rate_limit example - Enhanced error handling in check_status() for 429 responses The client now transparently handles Intel API rate limiting while remaining configurable for users who need different retry behavior or manual handling. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude Signed-off-by: Harald Hoyer --- crates/intel-dcap-api/CLAUDE.md | 17 +++- .../examples/handle_rate_limit.rs | 91 +++++++++++++++++++ crates/intel-dcap-api/src/client/fmspc.rs | 2 +- crates/intel-dcap-api/src/client/helpers.rs | 75 ++++++++++++++- crates/intel-dcap-api/src/client/mod.rs | 16 ++++ crates/intel-dcap-api/src/client/pck_crl.rs | 2 +- .../intel-dcap-api/src/client/registration.rs | 16 ++-- crates/intel-dcap-api/src/error.rs | 55 +++++++++++ crates/intel-dcap-api/src/lib.rs | 8 ++ 9 files changed, 267 insertions(+), 15 deletions(-) create mode 100644 crates/intel-dcap-api/examples/handle_rate_limit.rs diff --git a/crates/intel-dcap-api/CLAUDE.md b/crates/intel-dcap-api/CLAUDE.md index d2a01b3..851b6ae 100644 --- a/crates/intel-dcap-api/CLAUDE.md +++ b/crates/intel-dcap-api/CLAUDE.md @@ -16,6 +16,7 @@ and enclave identity verification. - Type-safe request/response structures - Support for SGX and TDX platforms - Real data integration tests +- **Automatic rate limit handling with configurable retries** ## Development Commands @@ -36,6 +37,7 @@ cargo run --example get_pck_crl # Fetch certificate revocation lists cargo run --example common_usage # Common attestation verification patterns cargo run --example integration_test # Comprehensive test of most API endpoints cargo run --example fetch_test_data # Fetch real data from Intel API for tests +cargo run --example handle_rate_limit # Demonstrate automatic rate limiting handling ``` ## Architecture @@ -45,6 +47,8 @@ cargo run --example fetch_test_data # Fetch real data from Intel API for tests - **ApiClient** (`src/client/mod.rs`): Main entry point supporting API v3/v4 - Base URL: https://api.trustedservices.intel.com - Manages HTTP client and API version selection + - Automatic retry logic for 429 (Too Many Requests) responses + - Default: 3 retries, configurable via `set_max_retries()` ### Key Modules @@ -69,6 +73,7 @@ cargo run --example fetch_test_data # Fetch real data from Intel API for tests - **error.rs**: `IntelApiError` for comprehensive error handling - Extracts error details from Error-Code and Error-Message headers + - **`TooManyRequests` variant for rate limiting (429) after retry exhaustion** - **types.rs**: Enums (CaType, ApiVersion, UpdateType, etc.) - **requests.rs**: Request structures - **responses.rs**: Response structures with JSON and certificate data @@ -78,10 +83,18 @@ cargo run --example fetch_test_data # Fetch real data from Intel API for tests All client methods follow this pattern: 1. Build request with query parameters -2. Send HTTP request with proper headers +2. Send HTTP request with proper headers (with automatic retry on 429) 3. Parse response (JSON + certificate chains) 4. Return typed response or error +### Rate Limiting & Retry Logic + +- **Automatic Retries**: All HTTP requests automatically retry on 429 (Too Many Requests) responses +- **Retry Configuration**: Default 3 retries, configurable via `ApiClient::set_max_retries()` +- **Retry-After Handling**: Waits for duration specified in Retry-After header before retrying +- **Error Handling**: `IntelApiError::TooManyRequests` returned only after all retries exhausted +- **Implementation**: `execute_with_retry()` in `src/client/helpers.rs` handles retry logic + ### Testing Strategy - **Mock Tests**: Two test suites using mockito for HTTP mocking @@ -114,6 +127,8 @@ All client methods follow this pattern: 1. **Mockito Header Encoding**: Always URL-encode headers containing newlines/special characters 2. **API Version Selection**: Some endpoints are V4-only and will return errors on V3 +3. **Rate Limiting**: Client automatically retries 429 responses; disable with `set_max_retries(0)` if manual handling + needed 4. **Platform Filters**: Only certain values are valid (All, Client, E3, E5) 5. **Test Data**: PCK certificate endpoints require valid platform data and often need subscription keys 6. **Issuer Chain Validation**: Always check that `issuer_chain` is non-empty - it's critical for signature verification diff --git a/crates/intel-dcap-api/examples/handle_rate_limit.rs b/crates/intel-dcap-api/examples/handle_rate_limit.rs new file mode 100644 index 0000000..def5af6 --- /dev/null +++ b/crates/intel-dcap-api/examples/handle_rate_limit.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +//! Example demonstrating automatic rate limit handling +//! +//! The Intel DCAP API client now automatically handles 429 Too Many Requests responses +//! by retrying up to 3 times by default. This example shows how to configure the retry +//! behavior and handle cases where all retries are exhausted. + +use intel_dcap_api::{ApiClient, IntelApiError}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create API client with default settings (3 retries) + let mut client = ApiClient::new()?; + + println!("Example 1: Default behavior (automatic retries)"); + println!("================================================"); + + // Example FMSPC value + let fmspc = "00606A000000"; + + // The client will automatically retry up to 3 times if rate limited + match client.get_sgx_tcb_info(fmspc, None, None).await { + Ok(tcb_info) => { + println!("✓ Successfully retrieved TCB info"); + println!( + " TCB Info JSON length: {} bytes", + tcb_info.tcb_info_json.len() + ); + println!( + " Issuer Chain length: {} bytes", + tcb_info.issuer_chain.len() + ); + } + Err(IntelApiError::TooManyRequests { + request_id, + retry_after, + }) => { + println!("✗ Rate limited even after 3 automatic retries"); + println!(" Request ID: {}", request_id); + println!(" Last retry-after was: {} seconds", retry_after); + } + Err(e) => { + eprintln!("✗ Other error: {}", e); + } + } + + println!("\nExample 2: Custom retry configuration"); + println!("====================================="); + + // Configure client to retry up to 5 times + client.set_max_retries(5); + println!("Set max retries to 5"); + + match client.get_sgx_tcb_info(fmspc, None, None).await { + Ok(_) => println!("✓ Request succeeded"), + Err(IntelApiError::TooManyRequests { .. }) => { + println!("✗ Still rate limited after 5 retries") + } + Err(e) => eprintln!("✗ Error: {}", e), + } + + println!("\nExample 3: Disable automatic retries"); + println!("===================================="); + + // Disable automatic retries + client.set_max_retries(0); + println!("Disabled automatic retries"); + + match client.get_sgx_tcb_info(fmspc, None, None).await { + Ok(_) => println!("✓ Request succeeded on first attempt"), + Err(IntelApiError::TooManyRequests { + request_id, + retry_after, + }) => { + println!("✗ Rate limited (no automatic retry)"); + println!(" Request ID: {}", request_id); + println!(" Retry after: {} seconds", retry_after); + println!(" You would need to implement manual retry logic here"); + } + Err(e) => eprintln!("✗ Error: {}", e), + } + + println!("\nNote: The client handles rate limiting automatically!"); + println!("You only need to handle TooManyRequests errors if:"); + println!("- You disable automatic retries (set_max_retries(0))"); + println!("- All automatic retries are exhausted"); + + Ok(()) +} diff --git a/crates/intel-dcap-api/src/client/fmspc.rs b/crates/intel-dcap-api/src/client/fmspc.rs index 3963f1f..c515ac9 100644 --- a/crates/intel-dcap-api/src/client/fmspc.rs +++ b/crates/intel-dcap-api/src/client/fmspc.rs @@ -46,7 +46,7 @@ impl ApiClient { } let request_builder = self.client.get(url); - let response = request_builder.send().await?; + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::OK]).await?; let fmspcs_json = response.text().await?; diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs index ee53cc3..ba86545 100644 --- a/crates/intel-dcap-api/src/client/helpers.rs +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -12,6 +12,8 @@ use crate::{ use percent_encoding::percent_decode_str; use reqwest::{RequestBuilder, Response, StatusCode}; use std::io; +use std::time::Duration; +use tokio::time::sleep; impl ApiClient { /// Helper to construct API paths dynamically based on version and technology (SGX/TDX). @@ -84,7 +86,7 @@ impl ApiClient { &self, request_builder: RequestBuilder, ) -> Result { - let response = request_builder.send().await?; + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::OK]).await?; let issuer_chain = self.get_required_header( @@ -109,7 +111,7 @@ impl ApiClient { &self, request_builder: RequestBuilder, ) -> Result { - let response = request_builder.send().await?; + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::OK]).await?; let issuer_chain = self.get_required_header( @@ -134,7 +136,7 @@ impl ApiClient { v4_issuer_chain_header: &'static str, v3_issuer_chain_header: Option<&'static str>, ) -> Result<(String, String), IntelApiError> { - let response = request_builder.send().await?; + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::OK]).await?; let issuer_chain = @@ -158,7 +160,7 @@ impl ApiClient { )) })?; - let response = builder_clone.send().await?; + let response = self.execute_with_retry(builder_clone).await?; let status = response.status(); if status == StatusCode::NOT_FOUND || status == StatusCode::GONE { @@ -224,4 +226,69 @@ impl ApiClient { Ok(()) } } + + /// Executes a request with automatic retry logic for rate limiting (429 responses). + /// + /// This method will automatically retry the request up to `max_retries` times + /// when receiving a 429 Too Many Requests response, waiting for the duration + /// specified in the Retry-After header. + pub(super) async fn execute_with_retry( + &self, + request_builder: RequestBuilder, + ) -> Result { + let mut retries = 0; + + loop { + // Clone the request builder for retry attempts + let builder = request_builder.try_clone().ok_or_else(|| { + IntelApiError::Io(io::Error::new( + io::ErrorKind::Other, + "Failed to clone request builder for retry", + )) + })?; + + let response = builder.send().await?; + let status = response.status(); + + if status != StatusCode::TOO_MANY_REQUESTS { + // Not a rate limit error, return the response + return Ok(response); + } + + // Handle 429 Too Many Requests + if retries >= self.max_retries { + // No more retries, return the error + let request_id = response + .headers() + .get("Request-ID") + .and_then(|v| v.to_str().ok()) + .unwrap_or("Unknown") + .to_string(); + + let retry_after = response + .headers() + .get("Retry-After") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.parse::().ok()) + .unwrap_or(60); + + return Err(IntelApiError::TooManyRequests { + request_id, + retry_after, + }); + } + + // Parse Retry-After header + let retry_after_secs = response + .headers() + .get("Retry-After") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.parse::().ok()) + .unwrap_or(60); // Default to 60 seconds + + // Wait before retrying + sleep(Duration::from_secs(retry_after_secs)).await; + retries += 1; + } + } } diff --git a/crates/intel-dcap-api/src/client/mod.rs b/crates/intel-dcap-api/src/client/mod.rs index d2d618d..3e71d5d 100644 --- a/crates/intel-dcap-api/src/client/mod.rs +++ b/crates/intel-dcap-api/src/client/mod.rs @@ -45,6 +45,8 @@ pub struct ApiClient { client: Client, base_url: Url, api_version: ApiVersion, + /// Maximum number of automatic retries for rate-limited requests (429 responses) + max_retries: u32, } impl ApiClient { @@ -114,6 +116,20 @@ impl ApiClient { .build()?, base_url: base_url.into_url()?, api_version, + max_retries: 3, // Default to 3 retries }) } + + /// Sets the maximum number of automatic retries for rate-limited requests. + /// + /// When the API returns a 429 (Too Many Requests) response, the client will + /// automatically wait for the duration specified in the Retry-After header + /// and retry the request up to this many times. + /// + /// # Arguments + /// + /// * `max_retries` - Maximum number of retries (0 disables automatic retries) + pub fn set_max_retries(&mut self, max_retries: u32) { + self.max_retries = max_retries; + } } diff --git a/crates/intel-dcap-api/src/client/pck_crl.rs b/crates/intel-dcap-api/src/client/pck_crl.rs index 0226b11..d5d0c6e 100644 --- a/crates/intel-dcap-api/src/client/pck_crl.rs +++ b/crates/intel-dcap-api/src/client/pck_crl.rs @@ -49,7 +49,7 @@ impl ApiClient { } let request_builder = self.client.get(url); - let response = request_builder.send().await?; + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::OK]).await?; let issuer_chain = self.get_required_header( diff --git a/crates/intel-dcap-api/src/client/registration.rs b/crates/intel-dcap-api/src/client/registration.rs index 136c8c0..d510649 100644 --- a/crates/intel-dcap-api/src/client/registration.rs +++ b/crates/intel-dcap-api/src/client/registration.rs @@ -36,13 +36,13 @@ impl ApiClient { let path = self.build_api_path("sgx", "registration", "platform")?; let url = self.base_url.join(&path)?; - let response = self + let request_builder = self .client .post(url) .header(header::CONTENT_TYPE, "application/octet-stream") - .body(platform_manifest) - .send() - .await?; + .body(platform_manifest); + + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::CREATED]).await?; @@ -81,14 +81,14 @@ impl ApiClient { let path = self.build_api_path("sgx", "registration", "package")?; let url = self.base_url.join(&path)?; - let response = self + let request_builder = self .client .post(url) .header("Ocp-Apim-Subscription-Key", subscription_key) .header(header::CONTENT_TYPE, "application/octet-stream") - .body(add_package_request) - .send() - .await?; + .body(add_package_request); + + let response = self.execute_with_retry(request_builder).await?; let response = check_status(response, &[StatusCode::OK]).await?; diff --git a/crates/intel-dcap-api/src/error.rs b/crates/intel-dcap-api/src/error.rs index 564bbd2..4e07216 100644 --- a/crates/intel-dcap-api/src/error.rs +++ b/crates/intel-dcap-api/src/error.rs @@ -59,6 +59,40 @@ pub enum IntelApiError { /// Indicates an invalid parameter was provided. #[error("Invalid parameter value: {0}")] InvalidParameter(&'static str), + + /// Indicates that the API rate limit has been exceeded (HTTP 429). + /// + /// This error is returned after the client has exhausted all automatic retry attempts + /// for a rate-limited request. The `retry_after` field contains the number of seconds + /// that was specified in the last Retry-After header. By default, the client automatically + /// retries rate-limited requests up to 3 times. + /// + /// # Example + /// + /// ```rust,no_run + /// use intel_dcap_api::{ApiClient, IntelApiError}; + /// + /// # async fn example() -> Result<(), Box> { + /// let mut client = ApiClient::new()?; + /// client.set_max_retries(0); // Disable automatic retries + /// + /// match client.get_sgx_tcb_info("00606A000000", None, None).await { + /// Ok(tcb_info) => println!("Success"), + /// Err(IntelApiError::TooManyRequests { request_id, retry_after }) => { + /// println!("Rate limited after all retries. Last retry-after was {} seconds.", retry_after); + /// } + /// Err(e) => eprintln!("Other error: {}", e), + /// } + /// # Ok(()) + /// # } + /// ``` + #[error("Too many requests. Retry after {retry_after} seconds")] + TooManyRequests { + /// The unique request identifier for tracing. + request_id: String, + /// Number of seconds to wait before retrying, from Retry-After header. + retry_after: u64, + }, } /// Extracts common API error details from response headers. @@ -92,6 +126,27 @@ pub(crate) async fn check_status( let status = response.status(); if expected_statuses.contains(&status) { Ok(response) + } else if status == StatusCode::TOO_MANY_REQUESTS { + // Handle 429 Too Many Requests with Retry-After header + let request_id = response + .headers() + .get("Request-ID") + .and_then(|v| v.to_str().ok()) + .unwrap_or("Unknown") + .to_string(); + + // Parse Retry-After header (can be in seconds or HTTP date format) + let retry_after = response + .headers() + .get("Retry-After") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.parse::().ok()) + .unwrap_or(60); // Default to 60 seconds if header is missing or invalid + + Err(IntelApiError::TooManyRequests { + request_id, + retry_after, + }) } else { let (request_id, error_code, error_message) = extract_api_error_details(&response); Err(IntelApiError::ApiError { diff --git a/crates/intel-dcap-api/src/lib.rs b/crates/intel-dcap-api/src/lib.rs index a0d9e20..f6f4ea4 100644 --- a/crates/intel-dcap-api/src/lib.rs +++ b/crates/intel-dcap-api/src/lib.rs @@ -8,6 +8,14 @@ //! //! Create an [`ApiClient`] to interface with the Intel API. //! +//! # Rate Limiting +//! +//! The Intel API implements rate limiting and may return HTTP 429 (Too Many Requests) responses. +//! This client automatically handles rate limiting by retrying requests up to 3 times by default, +//! waiting for the duration specified in the `Retry-After` header. You can configure the retry +//! behavior using [`ApiClient::set_max_retries`]. If all retries are exhausted, the client +//! returns an [`IntelApiError::TooManyRequests`] error. +//! //! Example //! ```rust,no_run //! use intel_dcap_api::{ApiClient, IntelApiError, TcbInfoResponse}; From 7c133c4e4b568a17b798bf0c0c4551969cd76622 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 28 May 2025 13:31:15 +0200 Subject: [PATCH 106/114] ci(nix): disable sandbox in nix-non-x86 workflow otherwise the mockito tests fail, because it cannot bind to 127.0.0.1 0 - Updated `nix build` command to include `--no-sandbox` flag. --- .github/workflows/nix-non-x86.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix-non-x86.yml b/.github/workflows/nix-non-x86.yml index 0872032..b80cf6a 100644 --- a/.github/workflows/nix-non-x86.yml +++ b/.github/workflows/nix-non-x86.yml @@ -34,5 +34,5 @@ jobs: # FIXME: this prevents it from running on macos # https://github.com/NixOS/nix/pull/12570 # run: nix run github:nixos/nixpkgs/nixos-24.11#nixci -- build - run: nix build -L .#teepot + run: nix build -L .#teepot --no-sandbox From a7e2939a540277c85e36e00f81ea7a6e135e072e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 06:43:14 +0000 Subject: [PATCH 107/114] chore(deps): update enarx/spdx digest to d4020ee --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b1340ff..0808331 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: steps: - name: checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - uses: enarx/spdx@b5bfdd4410071bf058c8333d0e70020001524b6b + - uses: enarx/spdx@d4020ee98e3101dd487c5184f27c6a6fb4f88709 with: licenses: |- Apache-2.0 From 716c782e6fd050dd3dbe89e7379f9c35aab9494f Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 30 May 2025 14:35:17 +0200 Subject: [PATCH 108/114] chore(deps): update crates and nix flakes - Updated multiple Rust dependencies, including `opentelemetry`, `const-oid`, and `webpki-roots` for enhanced features and bug fixes. - Upgraded `nixpkgs` and `crane` in the nix flake configuration. - Removed unused dependencies and introduced missing dependencies for improved build integrity. Signed-off-by: Harald Hoyer --- .github/workflows/nix.yml | 9 +- Cargo.lock | 1615 +++++++++-------- Cargo.toml | 16 +- bin/rtmr-calc/src/main.rs | 4 +- bin/tee-key-preexec/src/main.rs | 5 +- bin/verify-era-proof-attestation/Cargo.toml | 2 +- .../src/verification/signature.rs | 4 +- crates/intel-dcap-api/src/client/helpers.rs | 9 +- crates/teepot-vault/Cargo.toml | 2 +- .../teepot-vault/bin/vault-admin/src/main.rs | 5 +- crates/teepot-vault/src/server/signatures.rs | 16 +- crates/teepot/src/ethereum/mod.rs | 4 +- deny.toml | 1 + flake.lock | 37 +- flake.nix | 8 +- rust-toolchain.toml | 2 +- 16 files changed, 947 insertions(+), 792 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index ceaa93c..ddfe065 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -16,8 +16,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 with: + install_url: https://releases.nixos.org/nix/nix-2.28.3/install extra_nix_config: | access-tokens = github.com=${{ github.token }} trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= tee-pot:SS6HcrpG87S1M6HZGPsfo7d1xJccCGev7/tXc5+I4jg= @@ -37,8 +38,9 @@ jobs: runs-on: [matterlabs-default-infra-runners] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 with: + install_url: https://releases.nixos.org/nix/nix-2.28.3/install extra_nix_config: | access-tokens = github.com=${{ github.token }} trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= tee-pot:SS6HcrpG87S1M6HZGPsfo7d1xJccCGev7/tXc5+I4jg= @@ -76,8 +78,9 @@ jobs: - { nixpackage: 'container-tdx-test' } steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 with: + install_url: https://releases.nixos.org/nix/nix-2.28.3/install extra_nix_config: | access-tokens = github.com=${{ github.token }} trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= tee-pot:SS6HcrpG87S1M6HZGPsfo7d1xJccCGev7/tXc5+I4jg= diff --git a/Cargo.lock b/Cargo.lock index 565b002..4f6d1d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "bytes", "futures-core", "futures-sink", @@ -21,24 +21,24 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-tls", "actix-utils", - "ahash", "base64", - "bitflags 2.8.0", + "bitflags 2.9.1", "brotli", "bytes", "bytestring", - "derive_more 0.99.19", + "derive_more 2.0.1", "encoding_rs", "flate2", + "foldhash", "futures-core", "h2 0.3.26", "http 0.2.12", @@ -50,7 +50,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.8.5", + "rand 0.9.1", "sha1", "smallvec", "tokio", @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca2549781d8dd6d75c40cf6b6051260a2cc2f3c62343d761a969a0640646894" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" dependencies = [ "actix-rt", "actix-service", @@ -113,12 +113,11 @@ dependencies = [ [[package]] name = "actix-service" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" dependencies = [ "futures-core", - "paste", "pin-project-lite", ] @@ -133,7 +132,7 @@ dependencies = [ "actix-utils", "futures-core", "http 0.2.12", - "http 1.2.0", + "http 1.3.1", "impl-more", "pin-project-lite", "rustls-pki-types", @@ -141,7 +140,7 @@ dependencies = [ "tokio-rustls", "tokio-util", "tracing", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -156,9 +155,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.9.0" +version = "4.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" dependencies = [ "actix-codec", "actix-http", @@ -170,13 +169,13 @@ dependencies = [ "actix-tls", "actix-utils", "actix-web-codegen", - "ahash", "bytes", "bytestring", "cfg-if", "cookie", - "derive_more 0.99.19", + "derive_more 2.0.1", "encoding_rs", + "foldhash", "futures-core", "futures-util", "impl-more", @@ -194,6 +193,7 @@ dependencies = [ "smallvec", "socket2", "time", + "tracing", "url", ] @@ -206,7 +206,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -230,6 +230,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "bytes", "crypto-common", "generic-array", ] @@ -268,19 +269,6 @@ dependencies = [ "aes", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom 0.2.15", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -382,28 +370,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "async-trait" version = "0.1.88" @@ -412,7 +378,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -440,9 +406,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "awc" -version = "3.5.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79049b2461279b886e46f1107efc347ebecc7b88d74d023dda010551a124967b" +checksum = "e76d68b4f02400c2f9110437f254873e8f265b35ea87352f142bc7c8e878115a" dependencies = [ "actix-codec", "actix-http", @@ -454,7 +420,7 @@ dependencies = [ "bytes", "cfg-if", "cookie", - "derive_more 0.99.19", + "derive_more 2.0.1", "futures-core", "futures-util", "h2 0.3.26", @@ -464,7 +430,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.8.5", + "rand 0.9.1", "rustls", "serde", "serde_json", @@ -474,81 +440,32 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6a895b664295a4ba0c2c0203c7075ea585dd75cd5c37a8efac829e13e460ef" +checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" dependencies = [ "aws-lc-sys", - "paste", "zeroize", ] [[package]] name = "aws-lc-sys" -version = "0.26.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9dd2e03ee80ca2822dd6ea431163d2ef259f2066a4d6ccaca6d9dcb386aa43" +checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" dependencies = [ "bindgen 0.69.5", "cc", "cmake", "dunce", "fs_extra", - "paste", -] - -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", ] [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -573,9 +490,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" [[package]] name = "bindgen" @@ -619,7 +536,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.98", + "syn 2.0.101", "which", ] @@ -629,7 +546,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.12.1", @@ -642,7 +559,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.98", + "syn 2.0.101", "which", ] @@ -663,10 +580,25 @@ dependencies = [ ] [[package]] -name = "bitfield" -version = "0.17.0" +name = "bitfields" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" +checksum = "a1d84268bbf9b487d31fe4b849edbefcd3911422d7a07de855a2da1f70ab3d1c" +dependencies = [ + "bitfields-impl", +] + +[[package]] +name = "bitfields-impl" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c93edde7bb4416c35c85048e34f78999dcb47d199bde3b1d79286156f3e2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "thiserror 2.0.12", +] [[package]] name = "bitflags" @@ -676,9 +608,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitvec" @@ -731,9 +663,9 @@ dependencies = [ [[package]] name = "brotli" -version = "6.0.0" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -742,24 +674,14 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] -[[package]] -name = "bstr" -version = "1.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "buffer-redux" version = "1.0.2" @@ -777,28 +699,28 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -843,9 +765,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.14" +version = "1.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" dependencies = [ "jobserver", "libc", @@ -941,9 +863,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -951,9 +873,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstyle", "clap_lex", @@ -969,7 +891,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1037,9 +959,9 @@ checksum = "bed69047ed42e52c7e38d6421eeb8ceefb4f2a2b52eed59137f7bad7908f6800" [[package]] name = "config" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf9dc8d4ef88e27a8cb23e85cb116403dedd57f7971964dc4b18ccead548901" +checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" dependencies = [ "async-trait", "pathdiff", @@ -1085,12 +1007,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" version = "0.16.2" @@ -1112,6 +1028,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1129,9 +1055,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -1193,7 +1119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1229,7 +1155,24 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", +] + +[[package]] +name = "cx448" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c0cf476284b03eb6c10e78787b21c7abb7d7d43cb2f02532ba6b831ed892fa" +dependencies = [ + "crypto-bigint", + "elliptic-curve", + "pkcs8", + "rand_core 0.6.4", + "serdect 0.3.0", + "sha3", + "signature", + "subtle", + "zeroize", ] [[package]] @@ -1244,12 +1187,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] @@ -1268,16 +1211,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1293,20 +1236,20 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core 0.20.10", + "darling_core 0.20.11", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dbl" @@ -1319,9 +1262,9 @@ dependencies = [ [[package]] name = "dcap-qvl" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8bc5d87613fe4c0a7a980c3e9113d9f10b9f9404218e19333e0eff2eff4c9a" +checksum = "7c8049b28b1fe35e94bd52f4c20edf7b80b6eeb378faccdd685d5cd82cbc192e" dependencies = [ "anyhow", "asn1_der", @@ -1337,7 +1280,7 @@ dependencies = [ "pem", "reqwest", "ring", - "rustls-webpki", + "rustls-webpki 0.102.8", "scale-info", "serde", "serde-human-bytes", @@ -1349,9 +1292,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "der_derive", @@ -1368,14 +1311,14 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -1396,10 +1339,10 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1409,20 +1352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.98", -] - -[[package]] -name = "derive_more" -version = "0.99.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1431,7 +1361,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", ] [[package]] @@ -1442,7 +1381,19 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", "unicode-xid", ] @@ -1475,7 +1426,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1496,9 +1447,9 @@ dependencies = [ [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" [[package]] name = "dunce" @@ -1551,6 +1502,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", + "rand_core 0.6.4", "serde", "sha2", "subtle", @@ -1559,9 +1511,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" @@ -1570,6 +1522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", + "base64ct", "crypto-bigint", "digest", "ff", @@ -1580,15 +1533,18 @@ dependencies = [ "pkcs8", "rand_core 0.6.4", "sec1", + "serde_json", + "serdect 0.2.0", "subtle", + "tap", "zeroize", ] [[package]] name = "elsa" -version = "1.11.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2343daaeabe09879d4ea058bb4f1e63da3fc07dadc6634e01bda1b3d6a9d9d2b" +checksum = "9abf33c656a7256451ebb7d0082c5a471820c31269e49d807c538c252352186e" dependencies = [ "stable_deref_trait", ] @@ -1611,7 +1567,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1630,10 +1586,10 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6da3ea9e1d1a3b1593e15781f930120e72aa7501610b2f82e5b6739c72e8eac5" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1666,9 +1622,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -1726,10 +1682,11 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ + "bitvec", "rand_core 0.6.4", "subtle", ] @@ -1754,17 +1711,18 @@ dependencies = [ [[package]] name = "flagset" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -1774,6 +1732,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1866,7 +1830,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -1922,9 +1886,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -1979,7 +1943,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.2.0", + "http 1.3.1", "js-sys", "pin-project", "serde", @@ -2017,11 +1981,11 @@ dependencies = [ [[package]] name = "gpt" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffa5448a0d9d541f1840c0e1b5fe513360861ca83c4b920619f54efe277f9254" +checksum = "3696fafb1ecdcc2ae3ce337de73e9202806068594b77d22fdf2f3573c5ec2219" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "crc", "simple-bytes", "uuid", @@ -2050,7 +2014,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.1", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -2059,17 +2023,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", - "indexmap 2.7.1", + "http 1.3.1", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", @@ -2084,26 +2048,20 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ - "ahash", + "foldhash", ] -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - [[package]] name = "hashlink" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.3", ] [[package]] @@ -2208,17 +2166,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "hostname" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" -dependencies = [ - "cfg-if", - "libc", - "windows", -] - [[package]] name = "http" version = "0.2.12" @@ -2232,9 +2179,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -2248,27 +2195,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -2278,9 +2225,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "hyper" @@ -2291,8 +2238,8 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.8", - "http 1.2.0", + "h2 0.4.10", + "http 1.3.1", "http-body", "httparse", "httpdate", @@ -2305,12 +2252,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", - "http 1.2.0", + "http 1.3.1", "hyper", "hyper-util", "log", @@ -2319,7 +2265,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 1.0.0", ] [[package]] @@ -2353,33 +2299,41 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64", "bytes", "futures-channel", + "futures-core", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -2395,21 +2349,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -2418,31 +2373,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -2450,67 +2385,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - [[package]] name = "idea" version = "0.5.1" @@ -2539,9 +2461,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -2588,7 +2510,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -2604,20 +2526,20 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] @@ -2667,10 +2589,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "iter-read" -version = "1.1.0" +name = "iri-string" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "itertools" @@ -2692,22 +2618,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jni" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys", "log", "thiserror 1.0.69", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -2718,10 +2646,11 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] @@ -2737,15 +2666,15 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "834af00800e962dee8f7bfc0f60601de215e73e78e5497d733a2919da837d3c8" +checksum = "37b26c20e2178756451cfeb0661fb74c47dd5988cb7e3939de7e9241fd604d42" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-http-client", "jsonrpsee-proc-macros", - "jsonrpsee-types", + "jsonrpsee-types 0.24.9", "jsonrpsee-wasm-client", "jsonrpsee-ws-client", "tracing", @@ -2753,15 +2682,15 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def0fd41e2f53118bd1620478d12305b2c75feef57ea1f93ef70568c98081b7e" +checksum = "bacb85abf4117092455e1573625e21b8f8ef4dec8aff13361140b2dc266cdff2" dependencies = [ "base64", "futures-channel", "futures-util", "gloo-net", - "http 1.2.0", + "http 1.3.1", "jsonrpsee-core", "pin-project", "rustls", @@ -2778,18 +2707,18 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76637f6294b04e747d68e69336ef839a3493ca62b35bf488ead525f7da75c5bb" +checksum = "456196007ca3a14db478346f58c7238028d55ee15c1df15115596e411ff27925" dependencies = [ "async-trait", "bytes", "futures-timer", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "http-body-util", - "jsonrpsee-types", + "jsonrpsee-types 0.24.9", "pin-project", "rustc-hash 2.1.1", "serde", @@ -2803,9 +2732,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c24e981ad17798bbca852b0738bfb7b94816ed687bd0d5da60bfa35fa0fdc3" +checksum = "c872b6c9961a4ccc543e321bb5b89f6b2d2c7fe8b61906918273a3333c95400c" dependencies = [ "async-trait", "base64", @@ -2814,7 +2743,7 @@ dependencies = [ "hyper-rustls", "hyper-util", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.24.9", "rustls", "rustls-platform-verifier", "serde", @@ -2836,42 +2765,54 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "jsonrpsee-types" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6" +checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" dependencies = [ - "http 1.2.0", + "http 1.3.1", "serde", "serde_json", "thiserror 1.0.69", ] [[package]] -name = "jsonrpsee-wasm-client" -version = "0.24.8" +name = "jsonrpsee-types" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e41af42ca39657313748174d02766e5287d3a57356f16756dbd8065b933977" +checksum = "66df7256371c45621b3b7d2fb23aea923d577616b9c0e9c0b950a6ea5c2be0ca" +dependencies = [ + "http 1.3.1", + "serde", + "serde_json", + "thiserror 2.0.12", +] + +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6558a9586cad43019dafd0b6311d0938f46efc116b34b28c74778bc11a2edf6" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.24.9", ] [[package]] name = "jsonrpsee-ws-client" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4f3642a292f5b76d8a16af5c88c16a0860f2ccc778104e5c848b28183d9538" +checksum = "01b3323d890aa384f12148e8d2a1fd18eb66e9e7e825f9de4fa53bcc19b93eef" dependencies = [ - "http 1.2.0", + "http 1.3.1", "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.24.9", "url", ] @@ -2921,25 +2862,34 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.53.0", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libz-rs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" +dependencies = [ + "zlib-rs", +] [[package]] name = "linked-hash-map" @@ -2954,10 +2904,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] -name = "litemap" -version = "0.7.4" +name = "linux-raw-sys" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "local-channel" @@ -2978,9 +2934,9 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -2988,9 +2944,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru-cache" @@ -3001,6 +2957,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "matchers" version = "0.1.0" @@ -3010,12 +2972,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "md-5" version = "0.10.6" @@ -3046,23 +3002,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3075,13 +3031,13 @@ dependencies = [ "bytes", "colored", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "http-body-util", "hyper", "hyper-util", "log", - "rand 0.9.0", + "rand 0.9.1", "regex", "serde_json", "serde_urlencoded", @@ -3107,7 +3063,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -3132,16 +3088,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -3214,7 +3160,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -3240,9 +3186,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "opaque-debug" @@ -3252,11 +3198,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "cfg-if", "foreign-types", "libc", @@ -3273,7 +3219,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -3284,9 +3230,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -3296,9 +3242,9 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236e667b670a5cdf90c258f5a55794ec5ac5027e960c224bff8367a59e1e6426" +checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" dependencies = [ "futures-core", "futures-sink", @@ -3310,9 +3256,9 @@ dependencies = [ [[package]] name = "opentelemetry-appender-tracing" -version = "0.28.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c513c7af3bec30113f3d4620134ff923295f1e9c580fda2b8abe0831f925ddc0" +checksum = "2634cdf0b98cbbd3f5fc587eee1788ebe5c709dd65f359414f9eb682153c283e" dependencies = [ "log", "opentelemetry", @@ -3324,27 +3270,24 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8863faf2910030d139fb48715ad5ff2f35029fc5f244f6d5f689ddcf4d26253" +checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" dependencies = [ "async-trait", "bytes", - "http 1.2.0", + "http 1.3.1", "opentelemetry", "reqwest", - "tracing", ] [[package]] name = "opentelemetry-otlp" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bef114c6d41bea83d6dc60eb41720eedd0261a67af57b66dd2b84ac46c01d91" +checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" dependencies = [ - "async-trait", - "futures-core", - "http 1.2.0", + "http 1.3.1", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -3359,9 +3302,9 @@ dependencies = [ [[package]] name = "opentelemetry-proto" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8870d3024727e99212eb3bb1762ec16e255e3e6f58eeb3dc8db1aa226746d" +checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" dependencies = [ "opentelemetry", "opentelemetry_sdk", @@ -3371,29 +3314,26 @@ dependencies = [ [[package]] name = "opentelemetry-semantic-conventions" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fb3a2f78c2d55362cd6c313b8abedfbc0142ab3c2676822068fd2ab7d51f9b7" +checksum = "83d059a296a47436748557a353c5e6c5705b9470ef6c95cfc52c21a8814ddac2" [[package]] name = "opentelemetry_sdk" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84dfad6042089c7fc1f6118b7040dc2eb4ab520abbf410b79dc481032af39570" +checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" dependencies = [ - "async-trait", "futures-channel", "futures-executor", "futures-util", - "glob", "opentelemetry", "percent-encoding", - "rand 0.8.5", + "rand 0.9.1", "serde_json", "thiserror 2.0.12", "tokio", "tokio-stream", - "tracing", ] [[package]] @@ -3442,9 +3382,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.7.4" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ "arrayvec", "bitvec", @@ -3458,21 +3398,21 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.7.4" +version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -3480,9 +3420,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -3502,12 +3442,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pathdiff" version = "0.2.3" @@ -3575,21 +3509,22 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pgp" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30249ac8a98b356b473b04bc5358c75a260aa96a295d0743ce752fe7b173f235" +checksum = "f91d320242d9b686612b15526fe38711afdf856e112eaa4775ce25b0d9b12b11" dependencies = [ + "aead", "aes", "aes-gcm", "aes-kw", "argon2", "base64", - "bitfield", + "bitfields", "block-padding", "blowfish", - "bstr", "buffer-redux", "byteorder", + "bytes", "camellia", "cast5", "cfb-mode", @@ -3598,8 +3533,9 @@ dependencies = [ "const-oid", "crc24", "curve25519-dalek", + "cx448", "derive_builder", - "derive_more 1.0.0", + "derive_more 2.0.1", "des", "digest", "dsa", @@ -3612,7 +3548,6 @@ dependencies = [ "hex", "hkdf", "idea", - "iter-read", "k256", "log", "md-5", @@ -3625,6 +3560,7 @@ dependencies = [ "p384", "p521", "rand 0.8.5", + "regex", "ripemd", "rsa", "sha1", @@ -3633,7 +3569,7 @@ dependencies = [ "sha3", "signature", "smallvec", - "thiserror 2.0.12", + "snafu", "twofish", "x25519-dalek", "zeroize", @@ -3641,22 +3577,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -3694,9 +3630,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polyval" @@ -3710,6 +3646,15 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3718,21 +3663,21 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy", ] [[package]] name = "prettyplease" -version = "0.2.29" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -3759,18 +3704,18 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -3795,7 +3740,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -3818,14 +3763,14 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -3843,13 +3788,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.10" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", "getrandom 0.3.3", - "rand 0.9.0", + "lru-slab", + "rand 0.9.1", "ring", "rustc-hash 2.1.1", "rustls", @@ -3863,9 +3809,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" dependencies = [ "cfg_aliases", "libc", @@ -3877,9 +3823,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -3909,13 +3855,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.24", ] [[package]] @@ -3944,7 +3889,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -3958,11 +3903,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] @@ -4017,9 +3962,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" dependencies = [ "base64", "bytes", @@ -4027,9 +3972,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.8", + "h2 0.4.10", "hickory-resolver", - "http 1.2.0", + "http 1.3.1", "http-body", "http-body-util", "hyper", @@ -4046,34 +3991,29 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", "tower 0.5.2", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "windows-registry", + "webpki-roots 1.0.0", ] [[package]] name = "resolv-conf" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48375394603e3dd4b2d64371f7148fd8c7baa2680e28741f2cb8d23b59e3d4c4" -dependencies = [ - "hostname", -] +checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3" [[package]] name = "rfc6979" @@ -4087,13 +4027,13 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.9" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -4120,9 +4060,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" dependencies = [ "const-oid", "digest", @@ -4144,7 +4084,7 @@ name = "rtmr-calc" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.38", + "clap 4.5.39", "gpt", "hex", "pe-sign", @@ -4192,67 +4132,71 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.23" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.3", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile", "rustls-pki-types", "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", + "security-framework 3.2.0", ] [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", + "zeroize", ] [[package]] name = "rustls-platform-verifier" -version = "0.3.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", @@ -4260,11 +4204,11 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", + "rustls-webpki 0.103.3", + "security-framework 3.2.0", "security-framework-sys", - "webpki-roots", - "winapi", + "webpki-root-certs 0.26.11", + "windows-sys 0.59.0", ] [[package]] @@ -4278,6 +4222,17 @@ name = "rustls-webpki" version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "aws-lc-rs", "ring", @@ -4287,15 +4242,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -4328,7 +4283,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -4356,6 +4311,7 @@ dependencies = [ "der", "generic-array", "pkcs8", + "serdect 0.2.0", "subtle", "zeroize", ] @@ -4371,13 +4327,13 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +checksum = "6a3dff2d01c9aa65c3186a45ff846bfea52cbe6de3b6320ed2a358d90dad0d76" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys 0.10.1", + "rand 0.9.1", + "secp256k1-sys 0.11.0", ] [[package]] @@ -4391,9 +4347,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" dependencies = [ "cc", ] @@ -4413,11 +4369,23 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.8.0", - "core-foundation", + "bitflags 2.9.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-foundation-sys", "libc", - "num-bigint", "security-framework-sys", ] @@ -4433,9 +4401,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "send_wrapper" @@ -4445,9 +4413,9 @@ checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -4464,13 +4432,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -4479,7 +4447,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.9.0", "itoa", "memchr", "ryu", @@ -4528,7 +4496,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.1", + "indexmap 2.9.0", "serde", "serde_derive", "serde_json", @@ -4554,10 +4522,10 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -4566,13 +4534,33 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.9.0", "itoa", "ryu", "serde", "unsafe-libyaml", ] +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "serdect" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f42f67da2385b51a5f9652db9c93d78aeaf7610bf5ec366080b6de810604af53" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4621,7 +4609,7 @@ name = "sha384-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.38", + "clap 4.5.39", "hex", "sha2", "teepot", @@ -4644,9 +4632,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -4684,15 +4672,36 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "snafu" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320b01e011bf8d5d7a4a4a4be966d9160968935849c83b918827f6a435e7f627" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1961e2ef424c1424204d3a5d6975f934f56b6d50ff5732382d84ebf460e147f7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4778,7 +4787,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -4800,9 +4809,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -4820,13 +4829,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -4835,8 +4844,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.8.0", - "core-foundation", + "bitflags 2.9.1", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -4877,7 +4886,7 @@ name = "tdx-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.38", + "clap 4.5.39", "hex", "teepot", "tracing", @@ -4900,8 +4909,8 @@ name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.38", - "secp256k1 0.30.0", + "clap 4.5.39", + "secp256k1 0.31.0", "teepot", "tracing", "tracing-log", @@ -4913,7 +4922,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.38", + "clap 4.5.39", "rsa", "teepot", "tracing", @@ -4941,7 +4950,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.38", + "clap 4.5.39", "serde", "teepot", "teepot-vault", @@ -4958,7 +4967,7 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap 4.5.38", + "clap 4.5.39", "hex", "rustls", "serde_json", @@ -4978,7 +4987,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.38", + "clap 4.5.39", "rustls", "serde_json", "teepot", @@ -4999,7 +5008,7 @@ dependencies = [ "bytemuck", "bytes", "chrono", - "clap 4.5.38", + "clap 4.5.39", "config", "const-oid", "dcap-qvl", @@ -5019,7 +5028,7 @@ dependencies = [ "reqwest", "rsa", "rustls", - "secp256k1 0.30.0", + "secp256k1 0.31.0", "serde", "serde_json", "sha2", @@ -5045,7 +5054,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.38", + "clap 4.5.39", "serde_json", "teepot-vault", "tracing", @@ -5072,7 +5081,7 @@ dependencies = [ "awc", "base64", "bytes", - "clap 4.5.38", + "clap 4.5.39", "const-oid", "futures-core", "hex", @@ -5085,7 +5094,7 @@ dependencies = [ "teepot", "thiserror 2.0.12", "tracing", - "webpki-roots", + "webpki-roots 1.0.0", "x509-cert", ] @@ -5096,7 +5105,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.38", + "clap 4.5.39", "serde_json", "teepot-vault", "tracing", @@ -5106,15 +5115,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.17.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", "getrandom 0.3.3", "once_cell", - "rustix", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -5129,11 +5137,11 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -5178,7 +5186,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -5189,7 +5197,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -5204,9 +5212,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -5219,15 +5227,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -5244,9 +5252,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -5285,14 +5293,14 @@ checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "tokio" -version = "1.43.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -5314,7 +5322,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -5329,9 +5337,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", "tokio", @@ -5350,9 +5358,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -5364,9 +5372,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -5376,20 +5384,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ - "indexmap 2.7.1", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", @@ -5398,17 +5406,14 @@ dependencies = [ [[package]] name = "tonic" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" dependencies = [ - "async-stream", "async-trait", - "axum", "base64", "bytes", - "h2 0.4.8", - "http 1.2.0", + "http 1.3.1", "http-body", "http-body-util", "hyper", @@ -5417,10 +5422,9 @@ dependencies = [ "percent-encoding", "pin-project", "prost", - "socket2", "tokio", "tokio-stream", - "tower 0.4.13", + "tower 0.5.2", "tower-layer", "tower-service", "tracing", @@ -5434,13 +5438,8 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", "tower-layer", "tower-service", "tracing", @@ -5454,9 +5453,31 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap 2.9.0", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http 1.3.1", + "http-body", + "iri-string", + "pin-project-lite", + "tower 0.5.2", "tower-layer", "tower-service", ] @@ -5506,7 +5527,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -5589,7 +5610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -5627,9 +5648,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" @@ -5683,12 +5704,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -5697,11 +5712,13 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.13.2" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -5717,7 +5734,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.38", + "clap 4.5.39", "hex", "pgp", "serde_json", @@ -5733,7 +5750,7 @@ dependencies = [ "actix-web", "anyhow", "base64", - "clap 4.5.38", + "clap 4.5.39", "serde_json", "teepot-vault", "tracing", @@ -5758,7 +5775,7 @@ name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.38", + "clap 4.5.39", "teepot", ] @@ -5767,12 +5784,12 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "bytes", - "clap 4.5.38", + "clap 4.5.39", "enumset", "hex", - "jsonrpsee-types", + "jsonrpsee-types 0.25.1", "reqwest", - "secp256k1 0.30.0", + "secp256k1 0.31.0", "serde", "serde_json", "serde_with 3.12.0", @@ -5817,7 +5834,7 @@ checksum = "6a511871dc5de990a3b2a0e715facfbc5da848c0c0395597a1415029fb7c250a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -5876,7 +5893,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", "wasm-bindgen-shared", ] @@ -5911,7 +5928,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5946,10 +5963,37 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.26.8" +name = "webpki-root-certs" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.0", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a83f7e1a9f8712695c03eabe9ed3fbca0feff0152f33f12593e5a6303cb1a4" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -5963,7 +6007,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.44", ] [[package]] @@ -6004,22 +6048,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.52.0" +name = "windows-core" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-core", - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings 0.4.2", ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ - "windows-targets 0.52.6", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] @@ -6035,7 +6095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ "windows-result", - "windows-strings", + "windows-strings 0.3.1", "windows-targets 0.53.0", ] @@ -6057,6 +6117,24 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6084,6 +6162,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -6131,6 +6224,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6149,6 +6248,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6167,6 +6272,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6197,6 +6308,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6215,6 +6332,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6233,6 +6356,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6251,6 +6380,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6271,9 +6406,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -6294,20 +6429,14 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -6346,9 +6475,9 @@ dependencies = [ [[package]] name = "yaml-rust2" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" +checksum = "18b783b2c2789414f8bb84ca3318fc9c2d7e7be1c22907d37839a58dedb369d3" dependencies = [ "arraydeque", "encoding_rs", @@ -6357,9 +6486,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -6369,75 +6498,54 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", "synstructure", ] @@ -6459,14 +6567,25 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -6475,13 +6594,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.101", ] [[package]] @@ -6683,28 +6802,34 @@ dependencies = [ ] [[package]] -name = "zstd" -version = "0.13.2" +name = "zlib-rs" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.1" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index e7304fe..e0f24d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "ex bytes = "1" clap = { version = "4.5", features = ["std", "derive", "env", "error-context", "help", "usage", "wrap_help"], default-features = false } config = { version = "0.15.8", default-features = false, features = ["yaml", "json", "toml", "async"] } -const-oid = { version = "0.9", default-features = false } +const-oid = { version = "0.9.6", default-features = false } enumset = { version = "1.1", features = ["serde"] } getrandom = { version = "0.3.1", features = ["std"] } gpt = "4.0.0" @@ -35,19 +35,19 @@ hex = { version = "0.4.3", features = ["std"], default-features = false } intel-dcap-api = { path = "crates/intel-dcap-api" } num-integer = "0.1.46" num-traits = "0.2.18" -opentelemetry = { version = "0.28.0", features = ["default", "logs"] } -opentelemetry-appender-tracing = { version = "0.28.1", features = ["experimental_metadata_attributes", "log"] } -opentelemetry-otlp = { version = "0.28.0", features = ["grpc-tonic", "logs"] } -opentelemetry-semantic-conventions = { version = "0.28.0", features = ["semconv_experimental"] } -opentelemetry_sdk = { version = "0.28.0", features = ["tokio", "rt-tokio"] } +opentelemetry = { version = "0.30", features = ["default", "logs"] } +opentelemetry-appender-tracing = { version = "0.30", features = ["experimental_metadata_attributes", "log"] } +opentelemetry-otlp = { version = "0.30", features = ["grpc-tonic", "logs"] } +opentelemetry-semantic-conventions = { version = "0.30", features = ["semconv_experimental"] } +opentelemetry_sdk = { version = "0.30", features = ["tokio", "rt-tokio"] } p256 = "0.13.2" pe-sign = "0.1.10" -pgp = "0.15" +pgp = { version = "0.16", default-features = false } pkcs8 = { version = "0.10" } reqwest = { version = "0.12", features = ["json"] } rsa = { version = "0.9.6", features = ["sha2", "pem"] } rustls = { version = "0.23.20", default-features = false, features = ["std", "logging", "tls12", "ring"] } -secp256k1 = { version = "0.30", features = ["rand", "global-context"] } +secp256k1 = { version = "0.31", features = ["rand", "global-context"] } serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" serde_with = { version = "3.8", features = ["base64", "hex"] } diff --git a/bin/rtmr-calc/src/main.rs b/bin/rtmr-calc/src/main.rs index 2817da3..564d351 100644 --- a/bin/rtmr-calc/src/main.rs +++ b/bin/rtmr-calc/src/main.rs @@ -7,7 +7,7 @@ use pesign::PE; use sha2::{Digest, Sha384}; use std::{ fmt::{Display, Formatter}, - io::{Error, ErrorKind, Read, Seek, SeekFrom}, + io::{Error, Read, Seek, SeekFrom}, path::PathBuf, }; use teepot::{ @@ -125,7 +125,7 @@ fn main() -> Result<()> { let pstart = header .part_start .checked_mul(lb_size.as_u64()) - .ok_or_else(|| Error::new(ErrorKind::Other, "partition overflow - start offset"))?; + .ok_or_else(|| Error::other("partition overflow - start offset"))?; let _ = device.seek(SeekFrom::Start(pstart))?; assert_eq!(header.part_size, 128); diff --git a/bin/tee-key-preexec/src/main.rs b/bin/tee-key-preexec/src/main.rs index 14c10c3..758310d 100644 --- a/bin/tee-key-preexec/src/main.rs +++ b/bin/tee-key-preexec/src/main.rs @@ -27,10 +27,9 @@ fn main_with_error() -> Result<()> { use anyhow::Context; use secp256k1::{rand, Secp256k1}; use std::{os::unix::process::CommandExt, process::Command}; - use teepot::tdx::rtmr::TdxRtmrEvent; use teepot::{ ethereum::public_key_to_ethereum_address, prover::reportdata::ReportDataV1, - quote::get_quote, + quote::get_quote, tdx::rtmr::TdxRtmrEvent, }; use tracing_log::LogTracer; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; @@ -45,7 +44,7 @@ fn main_with_error() -> Result<()> { tracing::subscriber::set_global_default(subscriber).context("Failed to set logger")?; let args = Args::parse(); - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let secp = Secp256k1::new(); let (signing_key, verifying_key) = secp.generate_keypair(&mut rng); let ethereum_address = public_key_to_ethereum_address(&verifying_key); diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index a566639..d34f38e 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -12,7 +12,7 @@ bytes.workspace = true clap.workspace = true enumset.workspace = true hex.workspace = true -jsonrpsee-types = "0.24" +jsonrpsee-types = "0.25.1" reqwest.workspace = true secp256k1.workspace = true serde.workspace = true diff --git a/bin/verify-era-proof-attestation/src/verification/signature.rs b/bin/verify-era-proof-attestation/src/verification/signature.rs index f940ba4..ab34835 100644 --- a/bin/verify-era-proof-attestation/src/verification/signature.rs +++ b/bin/verify-era-proof-attestation/src/verification/signature.rs @@ -59,7 +59,7 @@ impl SignatureVerifier { let signature = Signature::from_compact(signature) .map_err(|e| error::Error::signature_verification(e.to_string()))?; let root_hash_msg = Message::from_digest(root_hash.0); - Ok(signature.verify(&root_hash_msg, &report.pubkey).is_ok()) + Ok(signature.verify(root_hash_msg, &report.pubkey).is_ok()) } /// Verify a V1 report @@ -139,7 +139,7 @@ impl SignatureVerifier { continue; }; - let Ok(public) = SECP256K1.recover_ecdsa(message, &rec_sig) else { + let Ok(public) = SECP256K1.recover_ecdsa(*message, &rec_sig) else { continue; }; diff --git a/crates/intel-dcap-api/src/client/helpers.rs b/crates/intel-dcap-api/src/client/helpers.rs index ba86545..d699a94 100644 --- a/crates/intel-dcap-api/src/client/helpers.rs +++ b/crates/intel-dcap-api/src/client/helpers.rs @@ -11,8 +11,7 @@ use crate::{ }; use percent_encoding::percent_decode_str; use reqwest::{RequestBuilder, Response, StatusCode}; -use std::io; -use std::time::Duration; +use std::{io, time::Duration}; use tokio::time::sleep; impl ApiClient { @@ -154,8 +153,7 @@ impl ApiClient { resource_description: &str, ) -> Result<(), IntelApiError> { let builder_clone = request_builder.try_clone().ok_or_else(|| { - IntelApiError::Io(io::Error::new( - io::ErrorKind::Other, + IntelApiError::Io(io::Error::other( "Failed to clone request builder for status check", )) })?; @@ -241,8 +239,7 @@ impl ApiClient { loop { // Clone the request builder for retry attempts let builder = request_builder.try_clone().ok_or_else(|| { - IntelApiError::Io(io::Error::new( - io::ErrorKind::Other, + IntelApiError::Io(io::Error::other( "Failed to clone request builder for retry", )) })?; diff --git a/crates/teepot-vault/Cargo.toml b/crates/teepot-vault/Cargo.toml index 9967d5d..7cb2cbd 100644 --- a/crates/teepot-vault/Cargo.toml +++ b/crates/teepot-vault/Cargo.toml @@ -26,7 +26,7 @@ sha2.workspace = true teepot.workspace = true thiserror.workspace = true tracing.workspace = true -webpki-roots = "0.26.1" +webpki-roots = "1.0.0" x509-cert.workspace = true [dev-dependencies] diff --git a/crates/teepot-vault/bin/vault-admin/src/main.rs b/crates/teepot-vault/bin/vault-admin/src/main.rs index 7e29c21..b11c3de 100644 --- a/crates/teepot-vault/bin/vault-admin/src/main.rs +++ b/crates/teepot-vault/bin/vault-admin/src/main.rs @@ -3,7 +3,10 @@ use anyhow::{anyhow, bail, Context, Result}; use clap::{Args, Parser, Subcommand}; -use pgp::{types::PublicKeyTrait, Deserializable, SignedPublicKey}; +use pgp::{ + composed::{Deserializable, SignedPublicKey}, + types::KeyDetails, +}; use serde_json::Value; use std::{ default::Default, diff --git a/crates/teepot-vault/src/server/signatures.rs b/crates/teepot-vault/src/server/signatures.rs index 785a68c..b3d6808 100644 --- a/crates/teepot-vault/src/server/signatures.rs +++ b/crates/teepot-vault/src/server/signatures.rs @@ -1,14 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2023-2024 Matter Labs +// Copyright (c) 2023-2025 Matter Labs //! Signature checking utilities -use crate::json::secrets::AdminConfig; -use crate::server::{HttpResponseError, Status as _}; +use crate::{ + json::secrets::AdminConfig, + server::{HttpResponseError, Status as _}, +}; use actix_web::http::StatusCode; use anyhow::{anyhow, bail, Context, Result}; -use pgp::types::PublicKeyTrait; -use pgp::{Deserializable, SignedPublicKey, StandaloneSignature}; +use pgp::{ + composed::{Deserializable, SignedPublicKey, StandaloneSignature}, + types::PublicKeyTrait, +}; use tracing::debug; /// Verify a pgp signature for some message given some public keys @@ -91,7 +95,7 @@ impl VerifySig for AdminConfig { mod tests { use super::verify_sig; use base64::{engine::general_purpose, Engine as _}; - use pgp::{Deserializable, SignedPublicKey}; + use pgp::composed::{Deserializable, SignedPublicKey}; const TEST_DATA: &str = include_str!("../../tests/data/test.json"); diff --git a/crates/teepot/src/ethereum/mod.rs b/crates/teepot/src/ethereum/mod.rs index 12dbe11..9f01082 100644 --- a/crates/teepot/src/ethereum/mod.rs +++ b/crates/teepot/src/ethereum/mod.rs @@ -17,7 +17,7 @@ pub fn recover_signer(sig: &[u8; 65], root_hash: &Message) -> Result<[u8; 20]> { &sig[0..64], RecoveryId::try_from(i32::from(sig[64]) - 27)?, )?; - let public = SECP256K1.recover_ecdsa(root_hash, &sig)?; + let public = SECP256K1.recover_ecdsa(*root_hash, &sig)?; Ok(public_key_to_ethereum_address(&public)) } @@ -42,7 +42,7 @@ mod tests { /// Signs the message in Ethereum-compatible format for on-chain verification. fn sign_message(sec: &SecretKey, message: Message) -> Result<[u8; 65]> { - let s = SECP256K1.sign_ecdsa_recoverable(&message, sec); + let s = SECP256K1.sign_ecdsa_recoverable(message, sec); let (rec_id, data) = s.serialize_compact(); let mut signature = [0u8; 65]; diff --git a/deny.toml b/deny.toml index 1c4ee4e..bbe34d2 100644 --- a/deny.toml +++ b/deny.toml @@ -33,6 +33,7 @@ allow = [ "OpenSSL", "CC0-1.0", "Zlib", + "CDLA-Permissive-2.0", ] confidence-threshold = 0.8 exceptions = [] diff --git a/flake.lock b/flake.lock index 62f2b11..49ab19f 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,16 @@ "nodes": { "crane": { "locked": { - "lastModified": 1731974531, - "narHash": "sha256-z7hiGBWsbWwSnu5UMmYyfHEehlSmfB8sCA8iH4nmxm8=", + "lastModified": 1745454774, + "narHash": "sha256-oLvmxOnsEKGtwczxp/CwhrfmQUG2ym24OMWowcoRhH8=", "owner": "ipetkov", "repo": "crane", - "rev": "8ff9c457d60951bdd37a05ae903423de7ff55c6e", + "rev": "efd36682371678e2b6da3f108fdb5c613b3ec598", "type": "github" }, "original": { "owner": "ipetkov", - "ref": "8ff9c457d60951bdd37a05ae903423de7ff55c6e", + "ref": "efd36682371678e2b6da3f108fdb5c613b3ec598", "repo": "crane", "type": "github" } @@ -156,6 +156,22 @@ "type": "github" } }, + "nixpkgs-25-05": { + "locked": { + "lastModified": 1748437600, + "narHash": "sha256-hYKMs3ilp09anGO7xzfGs3JqEgUqFMnZ8GMAqI6/k04=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "7282cb574e0607e65224d33be8241eae7cfe0979", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1717281328, @@ -217,6 +233,7 @@ "nixsgx-flake", "nixpkgs" ], + "nixpkgs-25-05": "nixpkgs-25-05", "nixsgx-flake": "nixsgx-flake", "rust-overlay": "rust-overlay", "snowfall-lib": [ @@ -234,11 +251,11 @@ ] }, "locked": { - "lastModified": 1743993291, - "narHash": "sha256-u8GHvduU1gCtoFXvTS/wGjH1ouv5S/GRGq6MAT+sG/k=", + "lastModified": 1748572605, + "narHash": "sha256-k0nhPtkVDQkVJckRw6fGIeeDBktJf1BH0i8T48o7zkk=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "0cb3c8979c65dc6a5812dfe67499a8c7b8b4325b", + "rev": "405ef13a5b80a0a4d4fc87c83554423d80e5f929", "type": "github" }, "original": { @@ -350,11 +367,11 @@ "nixsgx-flake": "nixsgx-flake_2" }, "locked": { - "lastModified": 1719832445, - "narHash": "sha256-Dnueq3A1sf8zT+bY6CcuaxPvX4AK7B6Sveqb8YfoY8o=", + "lastModified": 1747897304, + "narHash": "sha256-8O9ry5FaD1fkRqvHV5hPtsg5G+Z0RX6MRkazn5bmK50=", "owner": "matter-labs", "repo": "vault-auth-tee", - "rev": "2b53a4387fc8ecfb7826acd93d4895e7e810677d", + "rev": "dc802364964d9fe01b2e164e3fb3005bcdf91272", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d4c56ed..f3ec3fe 100644 --- a/flake.nix +++ b/flake.nix @@ -7,6 +7,7 @@ }; inputs = { + nixpkgs-25-05.url = "github:nixos/nixpkgs/nixos-25.05"; nixsgx-flake.url = "github:matter-labs/nixsgx"; nixpkgs.follows = "nixsgx-flake/nixpkgs"; snowfall-lib.follows = "nixsgx-flake/snowfall-lib"; @@ -21,7 +22,7 @@ inputs.nixpkgs.follows = "nixsgx-flake/nixpkgs"; }; - crane.url = "github:ipetkov/crane?ref=8ff9c457d60951bdd37a05ae903423de7ff55c6e"; # v0.19.3 + crane.url = "github:ipetkov/crane?ref=efd36682371678e2b6da3f108fdb5c613b3ec598"; # v0.20.3 }; outputs = inputs: @@ -39,6 +40,11 @@ nixsgx-flake.overlays.default vault-auth-tee-flake.overlays.default rust-overlay.overlays.default + (next: prev: { + # need recent cargo-deny understanding the 2024 edition + inherit (inputs.nixpkgs-25-05.legacyPackages.${prev.system}) + cargo-deny; + }) ]; alias = { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a237e46..f259a5e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.86" +channel = "1.87" components = ["rustfmt", "clippy", "rust-src"] From c42d692863091bfca8723ac95e9232a9378f188f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 15:07:28 +0000 Subject: [PATCH 109/114] chore(deps): update docker/login-action action to v3.4.0 --- .github/workflows/nix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index ddfe065..3d850ea 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -94,7 +94,7 @@ jobs: token: ${{ secrets.ATTIC_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} From 412e3b1698ca6d9be3ee100dc58dd4e1792a75e1 Mon Sep 17 00:00:00 2001 From: "Lucille L. Blumire" Date: Mon, 23 Jun 2025 10:05:44 +0100 Subject: [PATCH 110/114] chore(deps): Update all dependencies to latest --- Cargo.lock | 574 ++++++++++---------- Cargo.toml | 15 + bin/verify-era-proof-attestation/Cargo.toml | 12 +- crates/intel-dcap-api/Cargo.toml | 4 +- crates/teepot-vault/Cargo.toml | 6 +- crates/teepot/Cargo.toml | 8 +- 6 files changed, 304 insertions(+), 315 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f6d1d9..c7e4685 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -206,7 +206,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -220,9 +220,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anyhow" @@ -378,7 +378,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -400,9 +400,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "awc" @@ -490,9 +490,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.7.3" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bindgen" @@ -536,7 +536,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.101", + "syn 2.0.104", "which", ] @@ -559,7 +559,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.101", + "syn 2.0.104", "which", ] @@ -596,7 +596,7 @@ checksum = "07c93edde7bb4416c35c85048e34f78999dcb47d199bde3b1d79286156f3e2fb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "thiserror 2.0.12", ] @@ -693,9 +693,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "byte-slice-cast" @@ -705,9 +705,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -720,7 +720,7 @@ checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -765,9 +765,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.24" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -800,9 +800,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -863,9 +863,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -873,9 +873,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstyle", "clap_lex", @@ -884,21 +884,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cmac" @@ -1119,7 +1119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1155,7 +1155,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1220,7 +1220,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1242,7 +1242,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1311,7 +1311,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1342,7 +1342,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1352,7 +1352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1381,8 +1381,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", - "unicode-xid", + "syn 2.0.104", ] [[package]] @@ -1393,7 +1392,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "unicode-xid", ] @@ -1426,7 +1425,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1457,6 +1456,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + [[package]] name = "eax" version = "0.5.0" @@ -1567,7 +1572,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1589,7 +1594,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1622,12 +1627,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1717,9 +1722,9 @@ checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "libz-rs-sys", @@ -1830,7 +1835,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -1893,7 +1898,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -2048,9 +2053,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", ] @@ -2061,7 +2066,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.3", + "hashbrown 0.15.4", ] [[package]] @@ -2252,9 +2257,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.6" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ "http 1.3.1", "hyper", @@ -2265,7 +2270,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", ] [[package]] @@ -2299,9 +2304,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" +checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" dependencies = [ "base64", "bytes", @@ -2510,7 +2515,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -2531,7 +2536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "serde", ] @@ -2765,7 +2770,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -2862,9 +2867,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" @@ -2873,7 +2878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] @@ -2884,9 +2889,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libz-rs-sys" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" +checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" dependencies = [ "zlib-rs", ] @@ -2984,9 +2989,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "mime" @@ -3002,9 +3007,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -3017,7 +3022,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.59.0", ] @@ -3144,23 +3149,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3219,7 +3225,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3256,9 +3262,9 @@ dependencies = [ [[package]] name = "opentelemetry-appender-tracing" -version = "0.30.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2634cdf0b98cbbd3f5fc587eee1788ebe5c709dd65f359414f9eb682153c283e" +checksum = "e68f63eca5fad47e570e00e893094fc17be959c80c79a7d6ec1abdd5ae6ffc16" dependencies = [ "log", "opentelemetry", @@ -3405,7 +3411,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3459,7 +3465,7 @@ dependencies = [ "der", "digest", "num-traits", - "pem-rfc7468 1.0.0-rc.2", + "pem-rfc7468 1.0.0-rc.3", "reqwest", "rsa", "sha1", @@ -3494,9 +3500,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "1.0.0-rc.2" +version = "1.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dfbfa5c6f0906884269722c5478e72fd4d6c0e24fe600332c6d62359567ce1" +checksum = "a8e58fab693c712c0d4e88f8eb3087b6521d060bcaf76aeb20cb192d809115ba" dependencies = [ "base64ct", ] @@ -3592,7 +3598,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3672,12 +3678,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.32" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3722,9 +3728,9 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.22.3" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" +checksum = "cf41c1a7c32ed72abe5082fb19505b969095c12da9f5732a4bc9878757fd087c" dependencies = [ "dtoa", "itoa", @@ -3740,7 +3746,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3763,7 +3769,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -3809,9 +3815,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" dependencies = [ "cfg_aliases", "libc", @@ -3832,9 +3838,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "radium" @@ -3903,13 +3909,33 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "regex" version = "1.11.1" @@ -3962,9 +3988,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.18" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64", "bytes", @@ -3981,7 +4007,6 @@ dependencies = [ "hyper-rustls", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", "mime", @@ -4006,7 +4031,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", ] [[package]] @@ -4084,7 +4109,7 @@ name = "rtmr-calc" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.39", + "clap 4.5.40", "gpt", "hex", "pe-sign", @@ -4095,9 +4120,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -4154,9 +4179,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "aws-lc-rs", "log", @@ -4283,7 +4308,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4295,6 +4320,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -4438,7 +4475,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4456,9 +4493,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -4488,19 +4525,20 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" dependencies = [ "base64", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.9.0", + "schemars", "serde", "serde_derive", "serde_json", - "serde_with_macros 3.12.0", + "serde_with_macros 3.13.0", "time", ] @@ -4518,14 +4556,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4609,7 +4647,7 @@ name = "sha384-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.39", + "clap 4.5.40", "hex", "sha2", "teepot", @@ -4663,18 +4701,15 @@ checksum = "c11532d9d241904f095185f35dcdaf930b1427a94d5b01d7002d74ba19b44cc4" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "snafu" @@ -4694,7 +4729,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4787,7 +4822,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4809,9 +4844,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -4835,7 +4870,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -4886,7 +4921,7 @@ name = "tdx-extend" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.39", + "clap 4.5.40", "hex", "teepot", "tracing", @@ -4909,7 +4944,7 @@ name = "tee-key-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.39", + "clap 4.5.40", "secp256k1 0.31.0", "teepot", "tracing", @@ -4922,7 +4957,7 @@ name = "tee-ratls-preexec" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.39", + "clap 4.5.40", "rsa", "teepot", "tracing", @@ -4950,7 +4985,7 @@ version = "0.3.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.39", + "clap 4.5.40", "serde", "teepot", "teepot-vault", @@ -4967,7 +5002,7 @@ dependencies = [ "anyhow", "awc", "bytemuck", - "clap 4.5.39", + "clap 4.5.40", "hex", "rustls", "serde_json", @@ -4987,7 +5022,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.39", + "clap 4.5.40", "rustls", "serde_json", "teepot", @@ -5008,7 +5043,7 @@ dependencies = [ "bytemuck", "bytes", "chrono", - "clap 4.5.39", + "clap 4.5.40", "config", "const-oid", "dcap-qvl", @@ -5054,7 +5089,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.39", + "clap 4.5.40", "serde_json", "teepot-vault", "tracing", @@ -5081,7 +5116,7 @@ dependencies = [ "awc", "base64", "bytes", - "clap 4.5.39", + "clap 4.5.40", "const-oid", "futures-core", "hex", @@ -5089,12 +5124,12 @@ dependencies = [ "rustls", "serde", "serde_json", - "serde_with 3.12.0", + "serde_with 3.13.0", "sha2", "teepot", "thiserror 2.0.12", "tracing", - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", "x509-cert", ] @@ -5105,7 +5140,7 @@ dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.39", + "clap 4.5.40", "serde_json", "teepot-vault", "tracing", @@ -5186,7 +5221,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -5197,17 +5232,16 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -5293,7 +5327,7 @@ checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -5322,7 +5356,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -5372,9 +5406,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -5384,18 +5418,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.9.0", "serde", @@ -5466,9 +5500,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ "bitflags 2.9.1", "bytes", @@ -5521,20 +5555,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -5610,7 +5644,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -5734,7 +5768,7 @@ dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.39", + "clap 4.5.40", "hex", "pgp", "serde_json", @@ -5750,7 +5784,7 @@ dependencies = [ "actix-web", "anyhow", "base64", - "clap 4.5.39", + "clap 4.5.40", "serde_json", "teepot-vault", "tracing", @@ -5775,7 +5809,7 @@ name = "verify-attestation" version = "0.3.0" dependencies = [ "anyhow", - "clap 4.5.39", + "clap 4.5.40", "teepot", ] @@ -5784,7 +5818,7 @@ name = "verify-era-proof-attestation" version = "0.3.0" dependencies = [ "bytes", - "clap 4.5.39", + "clap 4.5.40", "enumset", "hex", "jsonrpsee-types 0.25.1", @@ -5792,7 +5826,7 @@ dependencies = [ "secp256k1 0.31.0", "serde", "serde_json", - "serde_with 3.12.0", + "serde_with 3.13.0", "serde_yaml", "teepot", "thiserror 2.0.12", @@ -5814,9 +5848,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vise" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ade36f3548b1524396f4de7b36f4f210c8a01dfab568eb2bff466af64eb6e5" +checksum = "cec485349f926890c1d90a27e8f3147b552bf16cfd80212cd5ff72e8645056fd" dependencies = [ "compile-fmt", "ctor", @@ -5828,13 +5862,13 @@ dependencies = [ [[package]] name = "vise-macros" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a511871dc5de990a3b2a0e715facfbc5da848c0c0395597a1415029fb7c250a" +checksum = "fe466916e9bf50cc69aba41affc11970885e9dd2b9e448e20e1fb8fc726132ed" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -5858,9 +5892,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -5893,7 +5927,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -5928,7 +5962,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5968,14 +6002,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.0", + "webpki-root-certs 1.0.1", ] [[package]] name = "webpki-root-certs" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a83f7e1a9f8712695c03eabe9ed3fbca0feff0152f33f12593e5a6303cb1a4" +checksum = "86138b15b2b7d561bc4469e77027b8dd005a43dc502e9031d1f5afc8ce1f280e" dependencies = [ "rustls-pki-types", ] @@ -5986,14 +6020,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.0", + "webpki-roots 1.0.1", ] [[package]] name = "webpki-roots" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" dependencies = [ "rustls-pki-types", ] @@ -6057,7 +6091,7 @@ dependencies = [ "windows-interface", "windows-link", "windows-result", - "windows-strings 0.4.2", + "windows-strings", ] [[package]] @@ -6068,7 +6102,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -6079,24 +6113,24 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" dependencies = [ + "windows-link", "windows-result", - "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-strings", ] [[package]] @@ -6108,15 +6142,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -6162,6 +6187,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -6210,9 +6244,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -6406,9 +6440,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -6475,9 +6509,9 @@ dependencies = [ [[package]] name = "yaml-rust2" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18b783b2c2789414f8bb84ca3318fc9c2d7e7be1c22907d37839a58dedb369d3" +checksum = "4ce2a4ff45552406d02501cea6c18d8a7e50228e7736a872951fe2fe75c91be7" dependencies = [ "arraydeque", "encoding_rs", @@ -6504,28 +6538,28 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -6545,7 +6579,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", "synstructure", ] @@ -6567,7 +6601,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] @@ -6600,14 +6634,14 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.104", ] [[package]] name = "zksync_basic_types" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7c1c35e9886151899e0636967b60f65b3bccd18f1e3ba71a98859e9d53bfab" +checksum = "1fd013c73df5c418a482e66d7bc260af7217170d2537c7c204c96516eb4ebf15" dependencies = [ "anyhow", "chrono", @@ -6621,63 +6655,16 @@ dependencies = [ "serde_with 1.14.0", "sha2", "strum", - "thiserror 1.0.69", + "thiserror 2.0.12", "tiny-keccak", "url", ] -[[package]] -name = "zksync_concurrency" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec98400a9e8ba02bfd029eacfe7d6fb7b85b8ef00de59d6bb119d29cc9f7442" -dependencies = [ - "anyhow", - "once_cell", - "pin-project", - "rand 0.8.5", - "sha3", - "thiserror 1.0.69", - "time", - "tokio", - "tracing", - "tracing-subscriber", - "vise", -] - -[[package]] -name = "zksync_config" -version = "27.0.0-non-semver-compat" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cf4af6d7e83c9ed0422a36c603b8bf84079ab510d295fda74f95ce49f62388" -dependencies = [ - "anyhow", - "rand 0.8.5", - "secrecy", - "serde", - "zksync_basic_types", - "zksync_concurrency", - "zksync_consensus_utils", - "zksync_crypto_primitives", -] - -[[package]] -name = "zksync_consensus_utils" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f9fa69ef68e6a1955a1d7b33077103fb6d106b560fec0d599c6de268f5be03" -dependencies = [ - "anyhow", - "rand 0.8.5", - "thiserror 1.0.69", - "zksync_concurrency", -] - [[package]] name = "zksync_contracts" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48199dbf89c06eb242ba1c5f1d8d66dbefb1a8b6c41f08201b084cd56b08ceb5" +checksum = "2e37376b4a06b82af7459ab7c0a4981c65bbd2c8e1646deb524988b59b0d901d" dependencies = [ "envy", "hex", @@ -6690,9 +6677,9 @@ dependencies = [ [[package]] name = "zksync_crypto_primitives" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd63cde705950e4dd9d1f5b3a532d2d8304e7af27efd197bd67c15f4d0954ab7" +checksum = "edc75467647cb0b9b18818f49c60a9ad83d638db88cd244be3fda78dcd8f5b5c" dependencies = [ "anyhow", "blake2", @@ -6702,26 +6689,15 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror 1.0.69", + "thiserror 2.0.12", "zksync_basic_types", ] -[[package]] -name = "zksync_da_client" -version = "27.0.0-non-semver-compat" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8889a7e5d7f003424cd476b28f4a8e8632aee6371209a84dc301df1f646405" -dependencies = [ - "anyhow", - "async-trait", - "serde", -] - [[package]] name = "zksync_mini_merkle_tree" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0816cec4ccc46ca86e9f31507e3112e6036a99aa29e38b4f13d2fe70da14efc4" +checksum = "7cb18556e92bf099bdf2275ec78e1023456d542e435142d420ff234d4735be35" dependencies = [ "once_cell", "zksync_basic_types", @@ -6730,9 +6706,9 @@ dependencies = [ [[package]] name = "zksync_system_constants" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f8e8c2887e282651cc354affe217b749b0c3a31200bdf8c597a9a467056255" +checksum = "5196ee6615e7b6c4f29d12c25d7f5dbd1ceb646d25cc245aeb34b0fc8285d950" dependencies = [ "once_cell", "zksync_basic_types", @@ -6740,15 +6716,15 @@ dependencies = [ [[package]] name = "zksync_types" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf281daa468c05be17029d42693b6e1f0ad946f44ff44bc448d377f18d45b15" +checksum = "75a5383dacdc4ce427c937073d028300c006442a9c6d91bdb3a686cf4f155800" dependencies = [ "anyhow", "async-trait", "blake2", "chrono", - "derive_more 1.0.0", + "derive_more 2.0.1", "hex", "num_enum", "once_cell", @@ -6756,21 +6732,20 @@ dependencies = [ "serde", "serde_json", "serde_with 1.14.0", - "thiserror 1.0.69", + "thiserror 2.0.12", "tracing", "zksync_basic_types", "zksync_contracts", "zksync_crypto_primitives", - "zksync_da_client", "zksync_mini_merkle_tree", "zksync_system_constants", ] [[package]] name = "zksync_utils" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "858ae870fc2b2b6af07de7cbb3e9b09418774d42d25d380dd0bfc01009767258" +checksum = "246b8013f18bb8721b7d9f9f1d56cb5ff7863ee2f54cdbc22a0e41ff158f1208" dependencies = [ "anyhow", "once_cell", @@ -6780,9 +6755,9 @@ dependencies = [ [[package]] name = "zksync_web3_decl" -version = "27.0.0-non-semver-compat" +version = "28.6.0-non-semver-compat" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b938259cc07b01c56a54d6ec24939cda621c39f0a4d7c294daa883e95445d0aa" +checksum = "58417285e72f11ad2e421fef394445dca54e77f8221faa26f1d993bc004c21e2" dependencies = [ "anyhow", "async-trait", @@ -6793,19 +6768,18 @@ dependencies = [ "rustls", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", "tracing", "vise", - "zksync_config", "zksync_types", ] [[package]] name = "zlib-rs" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" +checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" [[package]] name = "zstd" diff --git a/Cargo.toml b/Cargo.toml index e0f24d8..d4f8b66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ repository = "https://github.com/matter-labs/teepot" homepage = "https://github.com/matter-labs/teepot" [workspace.dependencies] +actix-http = "3" actix-web = { version = "4.5", features = ["rustls-0_23"] } anyhow = "1.0.82" asn1_der = { version = "0.7", default-features = false, features = ["native_types"] } @@ -25,14 +26,20 @@ awc = { version = "3.5", features = ["rustls-0_23-webpki-roots"] } base64 = "0.22.0" bytemuck = { version = "1.15.0", features = ["derive", "min_const_generics", "extern_crate_std"] } bytes = "1" +chrono = "0.4.40" clap = { version = "4.5", features = ["std", "derive", "env", "error-context", "help", "usage", "wrap_help"], default-features = false } config = { version = "0.15.8", default-features = false, features = ["yaml", "json", "toml", "async"] } const-oid = { version = "0.9.6", default-features = false } +dcap-qvl = "0.2.3" enumset = { version = "1.1", features = ["serde"] } +futures = "0.3.31" +futures-core = { version = "0.3.30", default-features = false } getrandom = { version = "0.3.1", features = ["std"] } gpt = "4.0.0" hex = { version = "0.4.3", features = ["std"], default-features = false } intel-dcap-api = { path = "crates/intel-dcap-api" } +jsonrpsee-types = "0.25.1" +mockito = "1.4" num-integer = "0.1.46" num-traits = "0.2.18" opentelemetry = { version = "0.30", features = ["default", "logs"] } @@ -42,6 +49,7 @@ opentelemetry-semantic-conventions = { version = "0.30", features = ["semconv_ex opentelemetry_sdk = { version = "0.30", features = ["tokio", "rt-tokio"] } p256 = "0.13.2" pe-sign = "0.1.10" +percent-encoding = "2.3.1" pgp = { version = "0.16", default-features = false } pkcs8 = { version = "0.10" } reqwest = { version = "0.12", features = ["json"] } @@ -51,15 +59,18 @@ secp256k1 = { version = "0.31", features = ["rand", "global-context"] } serde = { version = "1", features = ["derive", "rc"] } serde_json = "1" serde_with = { version = "3.8", features = ["base64", "hex"] } +serde_yaml = "0.9.33" sha2 = "0.10.8" sha3 = "0.10.8" signature = "2.2.0" tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } teepot = { path = "crates/teepot" } +teepot-tee-quote-verification-rs = { path = "crates/teepot-tee-quote-verification-rs" } teepot-vault = { path = "crates/teepot-vault" } testaso = "0.1.0" thiserror = "2.0.11" tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time", "signal"] } +tokio-util = "0.7.14" tracing = "0.1" tracing-actix-web = "0.7" tracing-futures = { version = "0.2.5", features = ["std"] } @@ -67,5 +78,9 @@ tracing-log = "0.2" tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "ansi"] } tracing-test = { version = "0.2.5", features = ["no-env-filter"] } url = "2.5.2" +webpki-roots = "1.0.0" x509-cert = { version = "0.2", features = ["builder", "signature", "default"] } zeroize = { version = "1.7.0", features = ["serde"] } +zksync_basic_types = "28.6.0-non-semver-compat" +zksync_types = "28.6.0-non-semver-compat" +zksync_web3_decl = "28.6.0-non-semver-compat" diff --git a/bin/verify-era-proof-attestation/Cargo.toml b/bin/verify-era-proof-attestation/Cargo.toml index d34f38e..2c5538f 100644 --- a/bin/verify-era-proof-attestation/Cargo.toml +++ b/bin/verify-era-proof-attestation/Cargo.toml @@ -12,20 +12,20 @@ bytes.workspace = true clap.workspace = true enumset.workspace = true hex.workspace = true -jsonrpsee-types = "0.25.1" +jsonrpsee-types.workspace = true reqwest.workspace = true secp256k1.workspace = true serde.workspace = true serde_json.workspace = true serde_with = { workspace = true, features = ["hex"] } -serde_yaml = "0.9.33" +serde_yaml.workspace = true teepot.workspace = true thiserror.workspace = true tokio.workspace = true -tokio-util = "0.7.14" +tokio-util.workspace = true tracing.workspace = true tracing-subscriber.workspace = true url.workspace = true -zksync_basic_types = "27.0.0-non-semver-compat" -zksync_types = "27.0.0-non-semver-compat" -zksync_web3_decl = "27.0.0-non-semver-compat" +zksync_basic_types.workspace = true +zksync_types.workspace = true +zksync_web3_decl.workspace = true diff --git a/crates/intel-dcap-api/Cargo.toml b/crates/intel-dcap-api/Cargo.toml index 310daf7..03c93b5 100644 --- a/crates/intel-dcap-api/Cargo.toml +++ b/crates/intel-dcap-api/Cargo.toml @@ -12,7 +12,7 @@ categories = ["api-bindings", "cryptography", "authentication"] [dependencies] base64.workspace = true -percent-encoding = "2.3.1" +percent-encoding.workspace = true reqwest = { workspace = true, features = ["json"] } serde.workspace = true serde_json.workspace = true @@ -23,7 +23,7 @@ url.workspace = true [dev-dependencies] base64.workspace = true hex.workspace = true -mockito = "1.4" +mockito.workspace = true x509-cert.workspace = true [[example]] diff --git a/crates/teepot-vault/Cargo.toml b/crates/teepot-vault/Cargo.toml index 7cb2cbd..0c0d4c6 100644 --- a/crates/teepot-vault/Cargo.toml +++ b/crates/teepot-vault/Cargo.toml @@ -8,14 +8,14 @@ authors.workspace = true repository.workspace = true [dependencies] -actix-http = "3" +actix-http.workspace = true actix-web.workspace = true anyhow.workspace = true awc.workspace = true bytes.workspace = true clap.workspace = true const-oid.workspace = true -futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } +futures-core = { workspace = true, features = ["alloc"] } hex.workspace = true pgp.workspace = true rustls.workspace = true @@ -26,7 +26,7 @@ sha2.workspace = true teepot.workspace = true thiserror.workspace = true tracing.workspace = true -webpki-roots = "1.0.0" +webpki-roots.workspace = true x509-cert.workspace = true [dev-dependencies] diff --git a/crates/teepot/Cargo.toml b/crates/teepot/Cargo.toml index 57e2408..b10fb7f 100644 --- a/crates/teepot/Cargo.toml +++ b/crates/teepot/Cargo.toml @@ -11,8 +11,8 @@ authors.workspace = true repository.workspace = true [target.'cfg(not(all(target_os = "linux", target_arch = "x86_64")))'.dependencies] -dcap-qvl = "0.2.3" -chrono = "0.4.40" +dcap-qvl.workspace = true +chrono.workspace = true bytes.workspace = true [features] @@ -28,7 +28,7 @@ clap.workspace = true config.workspace = true const-oid.workspace = true enumset.workspace = true -futures = "0.3.31" +futures.workspace = true getrandom.workspace = true hex.workspace = true num-integer.workspace = true @@ -49,7 +49,7 @@ serde_json.workspace = true sha2.workspace = true sha3.workspace = true signature.workspace = true -teepot-tee-quote-verification-rs = { path = "../teepot-tee-quote-verification-rs", optional = true } +teepot-tee-quote-verification-rs = { workspace = true, optional = true } thiserror.workspace = true tokio.workspace = true tracing.workspace = true From b4e0014e4e534d8c8d164bb3d4a1d95f80c6a701 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 24 Jun 2025 14:45:36 +0200 Subject: [PATCH 111/114] chore(deps): prepare release 0.6.0 - vendor unpublished tdx-attest-rs and tdx-attest-sys crates to be able to publish to crates.io - Updated package versions in `Cargo.toml` and `Cargo.lock` to 0.6.0. Signed-off-by: Harald Hoyer --- Cargo.lock | 246 +++------ Cargo.toml | 13 +- README.md | 9 + bin/rtmr-calc/Cargo.toml | 1 + bin/sha384-extend/Cargo.toml | 1 + bin/tdx-test/Cargo.toml | 1 + crates/teepot-tdx-attest-rs/Cargo.lock | 293 ++++++++++ crates/teepot-tdx-attest-rs/Cargo.toml | 15 + crates/teepot-tdx-attest-rs/License.txt | 38 ++ crates/teepot-tdx-attest-rs/src/lib.rs | 302 ++++++++++ crates/teepot-tdx-attest-sys/Cargo.lock | 286 ++++++++++ crates/teepot-tdx-attest-sys/Cargo.toml | 17 + crates/teepot-tdx-attest-sys/License.txt | 38 ++ crates/teepot-tdx-attest-sys/bindings.h | 33 ++ crates/teepot-tdx-attest-sys/build.rs | 85 +++ crates/teepot-tdx-attest-sys/src/lib.rs | 50 ++ .../Cargo.lock | 516 ++++++++++++++++++ .../Cargo.toml | 4 +- .../src/empty.rs | 3 +- .../src/intel.rs | 5 +- .../src/lib.rs | 3 +- packages/teepotCrate/default.nix | 2 + 22 files changed, 1772 insertions(+), 189 deletions(-) create mode 100644 crates/teepot-tdx-attest-rs/Cargo.lock create mode 100644 crates/teepot-tdx-attest-rs/Cargo.toml create mode 100644 crates/teepot-tdx-attest-rs/License.txt create mode 100644 crates/teepot-tdx-attest-rs/src/lib.rs create mode 100644 crates/teepot-tdx-attest-sys/Cargo.lock create mode 100644 crates/teepot-tdx-attest-sys/Cargo.toml create mode 100644 crates/teepot-tdx-attest-sys/License.txt create mode 100644 crates/teepot-tdx-attest-sys/bindings.h create mode 100644 crates/teepot-tdx-attest-sys/build.rs create mode 100644 crates/teepot-tdx-attest-sys/src/lib.rs create mode 100644 crates/teepot-tee-quote-verification-rs/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index c7e4685..df7f24f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,15 +308,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anstyle" version = "1.0.11" @@ -387,17 +378,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -494,29 +474,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" -[[package]] -name = "bindgen" -version = "0.59.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "clap 2.34.0", - "env_logger", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "which", -] - [[package]] name = "bindgen" version = "0.65.1" @@ -563,6 +520,26 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.104", +] + [[package]] name = "bitcoin-io" version = "0.1.3" @@ -846,21 +823,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap", - "unicode-width", - "vec_map", -] - [[package]] name = "clap" version = "4.5.40" @@ -1597,19 +1559,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "envy" version = "0.4.2" @@ -2075,15 +2024,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hex" version = "0.4.3" @@ -2228,12 +2168,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" - [[package]] name = "hyper" version = "1.6.0" @@ -2551,7 +2485,7 @@ dependencies = [ [[package]] name = "intel-dcap-api" -version = "0.3.0" +version = "0.6.0" dependencies = [ "base64", "hex", @@ -4106,10 +4040,10 @@ dependencies = [ [[package]] name = "rtmr-calc" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", - "clap 4.5.40", + "clap", "gpt", "hex", "pe-sign", @@ -4644,10 +4578,10 @@ dependencies = [ [[package]] name = "sha384-extend" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", - "clap 4.5.40", + "clap", "hex", "sha2", "teepot", @@ -4785,12 +4719,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" @@ -4900,28 +4828,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tdx-attest-rs" -version = "0.1.2" -source = "git+https://github.com/intel/SGXDataCenterAttestationPrimitives.git?rev=aa239d25a437a28f3f4de92c38f5b6809faac842#aa239d25a437a28f3f4de92c38f5b6809faac842" -dependencies = [ - "tdx-attest-sys", -] - -[[package]] -name = "tdx-attest-sys" -version = "0.1.0" -source = "git+https://github.com/intel/SGXDataCenterAttestationPrimitives.git?rev=aa239d25a437a28f3f4de92c38f5b6809faac842#aa239d25a437a28f3f4de92c38f5b6809faac842" -dependencies = [ - "bindgen 0.59.2", -] - [[package]] name = "tdx-extend" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", - "clap 4.5.40", + "clap", "hex", "teepot", "tracing", @@ -4929,7 +4841,7 @@ dependencies = [ [[package]] name = "tdx-test" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", "serde", @@ -4941,10 +4853,10 @@ dependencies = [ [[package]] name = "tee-key-preexec" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", - "clap 4.5.40", + "clap", "secp256k1 0.31.0", "teepot", "tracing", @@ -4954,10 +4866,10 @@ dependencies = [ [[package]] name = "tee-ratls-preexec" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", - "clap 4.5.40", + "clap", "rsa", "teepot", "tracing", @@ -4968,7 +4880,7 @@ dependencies = [ [[package]] name = "tee-self-attestation-test" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", @@ -4981,11 +4893,11 @@ dependencies = [ [[package]] name = "tee-stress-client" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", - "clap 4.5.40", + "clap", "serde", "teepot", "teepot-vault", @@ -4996,13 +4908,13 @@ dependencies = [ [[package]] name = "tee-vault-admin" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", "awc", "bytemuck", - "clap 4.5.40", + "clap", "hex", "rustls", "serde_json", @@ -5017,12 +4929,12 @@ dependencies = [ [[package]] name = "tee-vault-unseal" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.40", + "clap", "rustls", "serde_json", "teepot", @@ -5034,7 +4946,7 @@ dependencies = [ [[package]] name = "teepot" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", "asn1_der", @@ -5043,7 +4955,7 @@ dependencies = [ "bytemuck", "bytes", "chrono", - "clap 4.5.40", + "clap", "config", "const-oid", "dcap-qvl", @@ -5084,12 +4996,12 @@ dependencies = [ [[package]] name = "teepot-read" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.40", + "clap", "serde_json", "teepot-vault", "tracing", @@ -5097,18 +5009,32 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "teepot-tdx-attest-rs" +version = "0.1.2" +dependencies = [ + "teepot-tdx-attest-sys", +] + +[[package]] +name = "teepot-tdx-attest-sys" +version = "0.1.0" +dependencies = [ + "bindgen 0.70.1", +] + [[package]] name = "teepot-tee-quote-verification-rs" -version = "0.3.0" +version = "0.6.0" dependencies = [ "intel-tee-quote-verification-sys", "serde", - "tdx-attest-rs", + "teepot-tdx-attest-rs", ] [[package]] name = "teepot-vault" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-http", "actix-web", @@ -5116,7 +5042,7 @@ dependencies = [ "awc", "base64", "bytes", - "clap 4.5.40", + "clap", "const-oid", "futures-core", "hex", @@ -5135,12 +5061,12 @@ dependencies = [ [[package]] name = "teepot-write" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", "awc", - "clap 4.5.40", + "clap", "serde_json", "teepot-vault", "tracing", @@ -5161,15 +5087,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.4.2" @@ -5186,15 +5103,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b4d2149a2f578665ca39f8115084635847e9dd6921b5442dcafc7f87bb8e99" -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -5686,12 +5594,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-xid" version = "0.2.6" @@ -5763,12 +5665,12 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vault-admin" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", "bytemuck", - "clap 4.5.40", + "clap", "hex", "pgp", "serde_json", @@ -5779,12 +5681,12 @@ dependencies = [ [[package]] name = "vault-unseal" -version = "0.3.0" +version = "0.6.0" dependencies = [ "actix-web", "anyhow", "base64", - "clap 4.5.40", + "clap", "serde_json", "teepot-vault", "tracing", @@ -5798,27 +5700,21 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "verify-attestation" -version = "0.3.0" +version = "0.6.0" dependencies = [ "anyhow", - "clap 4.5.40", + "clap", "teepot", ] [[package]] name = "verify-era-proof-attestation" -version = "0.3.0" +version = "0.6.0" dependencies = [ "bytes", - "clap 4.5.40", + "clap", "enumset", "hex", "jsonrpsee-types 0.25.1", diff --git a/Cargo.toml b/Cargo.toml index d4f8b66..306c7fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,19 @@ [workspace] members = ["crates/*", "bin/*", "crates/teepot-vault/bin/*"] -exclude = ["crates/teepot-tee-quote-verification-rs"] resolver = "2" +# exclude x86_64 only crates +exclude = [ + "crates/teepot-tee-quote-verification-rs", + "crates/teepot-tdx-attest-rs", + "crates/teepot-tdx-attest-sys", +] + [profile.release] strip = true [workspace.package] -version = "0.3.0" +version = "0.6.0" edition = "2021" authors = ["Harald Hoyer "] # rest of the workspace, if not specified in the package section @@ -63,9 +69,8 @@ serde_yaml = "0.9.33" sha2 = "0.10.8" sha3 = "0.10.8" signature = "2.2.0" -tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } teepot = { path = "crates/teepot" } -teepot-tee-quote-verification-rs = { path = "crates/teepot-tee-quote-verification-rs" } +teepot-tee-quote-verification-rs = { version = "0.6.0", path = "crates/teepot-tee-quote-verification-rs" } teepot-vault = { path = "crates/teepot-vault" } testaso = "0.1.0" thiserror = "2.0.11" diff --git a/README.md b/README.md index 6169c0d..1608503 100644 --- a/README.md +++ b/README.md @@ -112,3 +112,12 @@ Attributes: ```shell nixos-rebuild -L --flake .#tdxtest build-vm && ./result/bin/run-tdxtest-vm ``` + +## Release + +```shell +$ cargo release 0.1.0 --manifest-path crates/teepot-tdx-attest-sys/Cargo.toml --sign +$ cargo release 0.1.2 --manifest-path crates/teepot-tdx-attest-rs/Cargo.toml --sign +$ cargo release 0.6.0 --manifest-path crates/teepot-tee-quote-verification-rs/Cargo.toml --sign +$ cargo release 0.6.0 --sign +``` diff --git a/bin/rtmr-calc/Cargo.toml b/bin/rtmr-calc/Cargo.toml index aeb7e96..f60255f 100644 --- a/bin/rtmr-calc/Cargo.toml +++ b/bin/rtmr-calc/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "rtmr-calc" +publish = false version.workspace = true edition.workspace = true authors.workspace = true diff --git a/bin/sha384-extend/Cargo.toml b/bin/sha384-extend/Cargo.toml index 85e8974..fac9e4c 100644 --- a/bin/sha384-extend/Cargo.toml +++ b/bin/sha384-extend/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "sha384-extend" +publish = false version.workspace = true edition.workspace = true authors.workspace = true diff --git a/bin/tdx-test/Cargo.toml b/bin/tdx-test/Cargo.toml index ea2a368..debc34f 100644 --- a/bin/tdx-test/Cargo.toml +++ b/bin/tdx-test/Cargo.toml @@ -6,6 +6,7 @@ authors.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true +publish = false [dependencies] anyhow.workspace = true diff --git a/crates/teepot-tdx-attest-rs/Cargo.lock b/crates/teepot-tdx-attest-rs/Cargo.lock new file mode 100644 index 0000000..f8b313e --- /dev/null +++ b/crates/teepot-tdx-attest-rs/Cargo.lock @@ -0,0 +1,293 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "prettyplease" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "teepot-tdx-attest-rs" +version = "0.1.2" +dependencies = [ + "teepot-tdx-attest-sys", +] + +[[package]] +name = "teepot-tdx-attest-sys" +version = "0.1.0" +dependencies = [ + "bindgen", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/crates/teepot-tdx-attest-rs/Cargo.toml b/crates/teepot-tdx-attest-rs/Cargo.toml new file mode 100644 index 0000000..0e88ec7 --- /dev/null +++ b/crates/teepot-tdx-attest-rs/Cargo.toml @@ -0,0 +1,15 @@ +# Fork of the original crate: https://github.com/intel/SGXDataCenterAttestationPrimitives + +[package] +name = "teepot-tdx-attest-rs" +version = "0.1.2" +edition = "2021" +license = "BSD-3-Clause" +repository = "https://github.com/matter-labs/teepot" +homepage = "https://github.com/matter-labs/teepot" +description = "Fork of tdx-attest-rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tdx-attest-sys = { version = "0.1.0", path = "../teepot-tdx-attest-sys", package = "teepot-tdx-attest-sys" } diff --git a/crates/teepot-tdx-attest-rs/License.txt b/crates/teepot-tdx-attest-rs/License.txt new file mode 100644 index 0000000..c49d62f --- /dev/null +++ b/crates/teepot-tdx-attest-rs/License.txt @@ -0,0 +1,38 @@ +BSD License + +Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============================================================== + +pce.signed.dll, qve.signed.dll,id_enclave.signed.dll and qe3.signed.dll, +libsgx_pce.signed.so, libsgx_qve.signed.so, libsgx_id_enclave.signed.so, +libsgx_qe3.signed.so and libsgx_tdqe.signed.so are licensed under +3-Clause BSD License. + diff --git a/crates/teepot-tdx-attest-rs/src/lib.rs b/crates/teepot-tdx-attest-rs/src/lib.rs new file mode 100644 index 0000000..cbf0e84 --- /dev/null +++ b/crates/teepot-tdx-attest-rs/src/lib.rs @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2022 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +//! This is the Intel TDX attestation library for Rust. +#![allow(non_camel_case_types)] + +use std::{mem, option::Option}; +pub use tdx_attest_sys::{ + tdx_attest_error_t, tdx_report_data_t, tdx_report_t, tdx_rtmr_event_t, tdx_uuid_t, +}; + +/// Request a Quote of the calling TD. +/// +/// # Param +/// - **tdx_report_data**\ +/// A set of data that the caller/TD wants to cryptographically bind to the Quote, typically a hash. May be all zeros for the Report data. +/// - **att_key_id_list**\ +/// List (array) of the attestation key IDs supported by the Quote verifier. +/// - **att_key_id**\ +/// The selected attestation key ID when the function returns. +/// - **flags**\ +/// Reserved, must be zero. +/// +/// # Return +/// - ***TDX_ATTEST_SUCCESS***\ +/// Successfully generated the Quote.\ +/// - ***TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID***\ +/// The platform Quoting infrastructure does not support any of the keys.\ +/// - ***TDX_ATT_ERROR_INVALID_PARAMETER***\ +/// The parameter is incorrect.\ +/// - ***TDX_ATTEST_ERROR_DEVICE_FAILURE***\ +/// Failed to acess tdx attest device.\ +/// - ***TDX_ATTEST_ERROR_VSOCK_FAILURE***\ +/// vsock related failure.\ +/// - ***TDX_ATTEST_ERROR_OUT_OF_MEMORY***\ +/// Heap memory allocation error in library or enclave.\ +/// - ***TDX_ATT_ERROR_UNEXPECTED***\ +/// An unexpected internal error occurred.\ +/// +/// # Examples +/// ``` +/// use tdx_attest_rs::*; +/// +/// let tdx_report_data = tdx_report_data_t{ +/// d: [0; 64usize], +/// }; +/// let att_key_id_list = [tdx_uuid_t{ +/// d: [0; 16usize], +/// }; 2usize]; +/// let list_size = 1024; +/// let mut att_key_id = tdx_uuid_t{ +/// d: [0; 16usize], +/// }; +/// let result = tdx_att_get_quote(Some(&tdx_report_data), Some(&att_key_id_list), Some(&mut att_key_id), 0); +/// ``` +pub fn tdx_att_get_quote( + tdx_report_data: Option<&tdx_report_data_t>, + att_key_id_list: Option<&[tdx_uuid_t]>, + att_key_id: Option<&mut tdx_uuid_t>, + flags: u32, +) -> (tdx_attest_error_t, Option>) { + let p_tdx_report_data = match tdx_report_data { + Some(p) => p as *const tdx_report_data_t, + None => &tdx_report_data_t { d: [0; 64usize] }, + }; + let (p_att_key_id_list, att_key_id_list_size) = match att_key_id_list { + Some(p) => (p.as_ptr() as *const tdx_uuid_t, p.len() as u32), + None => (std::ptr::null(), 0u32), + }; + let p_att_key_id = match att_key_id { + Some(p) => p as *mut tdx_uuid_t, + None => std::ptr::null_mut(), + }; + let mut buf = std::ptr::null_mut(); + let mut buf_len = 0; + unsafe { + let result = tdx_attest_sys::tdx_att_get_quote( + p_tdx_report_data, + p_att_key_id_list, + att_key_id_list_size, + p_att_key_id, + &mut buf, + &mut buf_len, + flags, + ); + match result { + tdx_attest_error_t::TDX_ATTEST_SUCCESS => { + assert!(!buf.is_null()); + assert!(buf_len > 0); + let quote = std::slice::from_raw_parts(buf, buf_len as usize).to_vec(); + tdx_attest_sys::tdx_att_free_quote(buf); + return (result, Some(quote)); + } + _ => return (result, None), + } + } +} + +/// Request a TDX Report of the calling TD. +/// +/// # Param +/// - **tdx_report_data**\ +/// A set of data that the caller/TD wants to cryptographically bind to the Quote, typically a hash. May be all zeros for the Report data. +/// - **tdx_report**\ +/// the generated TDX Report. +/// +/// # Return +/// - ***TDX_ATTEST_SUCCESS***\ +/// Successfully generate report.\ +/// - ***TDX_ATTEST_ERROR_INVALID_PARAMETER***\ +/// The parameter is incorrect. +/// - ***TDX_ATTEST_ERROR_DEVICE_FAILURE***\ +/// Failed to acess tdx attest device.\ +/// - ***TDX_ATTEST_ERROR_REPORT_FAILURE***\ +/// Failed to get the TD Report.\ +/// - ***TDX_ATT_ERROR_UNEXPECTED***\ +/// An unexpected internal error occurred.\ +/// +/// # Examples +/// ``` +/// use tdx_attest_rs::*; +/// +/// let tdx_report_data = tdx_report_data_t{ +/// d: [0; 64usize], +/// }; +/// let mut tdx_report =tdx_report_t{ +/// d: [0; 1024usize], +/// }; +/// let result = tdx_att_get_report(Some(&tdx_report_data), &mut tdx_report); +/// ``` +pub fn tdx_att_get_report( + tdx_report_data: Option<&tdx_report_data_t>, + tdx_report: &mut tdx_report_t, +) -> tdx_attest_error_t { + let p_tdx_report_data = match tdx_report_data { + Some(p) => p as *const tdx_report_data_t, + None => &tdx_report_data_t { d: [0; 64usize] }, + }; + unsafe { tdx_attest_sys::tdx_att_get_report(p_tdx_report_data, tdx_report) } +} + +/// Extend one of the TDX runtime measurement registers (RTMRs). +/// +/// # Param +/// - **rtmr_event**\ +/// A set of data that contains the index of the RTMR to extend, the data with which to extend it and a description of the data. +/// +/// # Return +/// - ***TDX_ATTEST_SUCCESS***\ +/// Successfully extended the RTMR.\ +/// - ***TDX_ATTEST_ERROR_INVALID_PARAMETER***\ +/// The parameter is incorrect. +/// - ***TDX_ATTEST_ERROR_DEVICE_FAILURE***\ +/// Failed to acess tdx attest device.\ +/// - ***TDX_ATTEST_ERROR_INVALID_RTMR_INDEX***\ +/// Only supported RTMR index is 2 and 3.\ +/// - ***TDX_ATTEST_ERROR_EXTEND_FAILURE***\ +/// Failed to extend data.\ +/// - ***TDX_ATTEST_ERROR_NOT_SUPPORTED***\ +/// rtmr_event.event_data_size != 0.\ +/// - ***TDX_ATT_ERROR_UNEXPECTED***\ +/// An unexpected internal error occurred.\ +/// +/// # Examples +/// ``` +/// use tdx_attest_rs::*; +/// +/// let rtmr_event = [0u8; 68usize]; +/// let result = tdx_att_extend(&rtmr_event); +/// ``` + +pub fn tdx_att_extend(rtmr_event: &[u8]) -> tdx_attest_error_t { + if rtmr_event.len() < mem::size_of::() { + return tdx_attest_error_t::TDX_ATTEST_ERROR_INVALID_PARAMETER; + } + unsafe { + let s: tdx_rtmr_event_t = std::ptr::read(rtmr_event.as_ptr() as *const _); + if rtmr_event.len() - mem::size_of::() != s.event_data_size as usize { + return tdx_attest_error_t::TDX_ATTEST_ERROR_INVALID_PARAMETER; + } + tdx_attest_sys::tdx_att_extend(rtmr_event.as_ptr() as *const tdx_rtmr_event_t) + } +} + +/// Retrieve the list of attestation key IDs supported by the platform. +/// +/// # Param +/// +/// # Return +/// - ***TDX_ATTEST_SUCCESS***\ +/// Successfully populated the att_key_id_list.\ +/// - ***TDX_ATT_ERROR_UNEXPECTED***\ +/// An unexpected internal error occurred.\ +/// +/// # Examples +/// ``` +/// use tdx_attest_rs::*; +/// let (result, att_key_id_list) = tdx_att_get_supported_att_key_ids(); +/// ``` +pub fn tdx_att_get_supported_att_key_ids() -> (tdx_attest_error_t, Option>) { + let mut list_count = 0; + unsafe { + let result = tdx_attest_sys::tdx_att_get_supported_att_key_ids( + std::ptr::null_mut() as *mut tdx_uuid_t, + &mut list_count, + ); + match result { + tdx_attest_error_t::TDX_ATTEST_SUCCESS => { + let mut att_key_id_list = vec![tdx_uuid_t { d: [0; 16usize] }; list_count as usize]; + let result = tdx_attest_sys::tdx_att_get_supported_att_key_ids( + att_key_id_list.as_mut_ptr(), + &mut list_count, + ); + match result { + tdx_attest_error_t::TDX_ATTEST_SUCCESS => { + return (result, Some(att_key_id_list)) + } + _ => return (result, None), + } + } + _ => return (result, None), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_tdx_att_get_report() { + let tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; + let mut tdx_report = tdx_report_t { d: [0; 1024usize] }; + let result = tdx_att_get_report(Some(&tdx_report_data), &mut tdx_report); + assert_eq!(result, tdx_attest_error_t::TDX_ATTEST_ERROR_DEVICE_FAILURE); + let result = tdx_att_get_report(None, &mut tdx_report); + assert_eq!(result, tdx_attest_error_t::TDX_ATTEST_ERROR_DEVICE_FAILURE); + } + + #[test] + fn test_tdx_att_get_quote() { + let tdx_report_data = tdx_report_data_t { d: [0; 64usize] }; + let mut att_key_id = tdx_uuid_t { d: [0; 16usize] }; + let (result, quote) = + tdx_att_get_quote(Some(&tdx_report_data), None, Some(&mut att_key_id), 0); + println!("att_key_id {:?}", att_key_id.d); + match quote { + q => println!("quote {:?}", q), + } + assert_eq!(result, tdx_attest_error_t::TDX_ATTEST_ERROR_DEVICE_FAILURE); + let (result, _quote) = tdx_att_get_quote(None, None, None, 0); + assert_eq!(result, tdx_attest_error_t::TDX_ATTEST_ERROR_DEVICE_FAILURE); + } + + #[test] + fn test_tdx_att_extend() { + let mut rtmr_event = [0u8; mem::size_of::()]; + rtmr_event[0] = 1; + let result = tdx_att_extend(&rtmr_event); + assert_eq!(result, tdx_attest_error_t::TDX_ATTEST_ERROR_DEVICE_FAILURE); + } + + #[test] + fn test_tdx_att_get_supported_att_key_ids() { + let (result, att_key_ids) = tdx_att_get_supported_att_key_ids(); + let ids = att_key_ids.unwrap(); + println!("att_key_id size {:?}", ids.len()); + for id in ids { + println!("att_key_id {:?}", id.d); + } + assert_eq!(result, tdx_attest_error_t::TDX_ATTEST_SUCCESS); + } +} diff --git a/crates/teepot-tdx-attest-sys/Cargo.lock b/crates/teepot-tdx-attest-sys/Cargo.lock new file mode 100644 index 0000000..79d6f01 --- /dev/null +++ b/crates/teepot-tdx-attest-sys/Cargo.lock @@ -0,0 +1,286 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "prettyplease" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "teepot-tdx-attest-sys" +version = "0.1.0" +dependencies = [ + "bindgen", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/crates/teepot-tdx-attest-sys/Cargo.toml b/crates/teepot-tdx-attest-sys/Cargo.toml new file mode 100644 index 0000000..7e9db7a --- /dev/null +++ b/crates/teepot-tdx-attest-sys/Cargo.toml @@ -0,0 +1,17 @@ +# Fork of the original crate: https://github.com/intel/SGXDataCenterAttestationPrimitives + +[package] +name = "teepot-tdx-attest-sys" +version = "0.1.0" +links = "tdx_attest" +edition = "2021" +license = "BSD-3-Clause" +repository = "https://github.com/matter-labs/teepot" +homepage = "https://github.com/matter-labs/teepot" +description = "Fork of tdx-attest-sys" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[build-dependencies] +bindgen = "0.70.1" diff --git a/crates/teepot-tdx-attest-sys/License.txt b/crates/teepot-tdx-attest-sys/License.txt new file mode 100644 index 0000000..c49d62f --- /dev/null +++ b/crates/teepot-tdx-attest-sys/License.txt @@ -0,0 +1,38 @@ +BSD License + +Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============================================================== + +pce.signed.dll, qve.signed.dll,id_enclave.signed.dll and qe3.signed.dll, +libsgx_pce.signed.so, libsgx_qve.signed.so, libsgx_id_enclave.signed.so, +libsgx_qe3.signed.so and libsgx_tdqe.signed.so are licensed under +3-Clause BSD License. + diff --git a/crates/teepot-tdx-attest-sys/bindings.h b/crates/teepot-tdx-attest-sys/bindings.h new file mode 100644 index 0000000..01a400d --- /dev/null +++ b/crates/teepot-tdx-attest-sys/bindings.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2022 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "tdx_attest.h" diff --git a/crates/teepot-tdx-attest-sys/build.rs b/crates/teepot-tdx-attest-sys/build.rs new file mode 100644 index 0000000..7737907 --- /dev/null +++ b/crates/teepot-tdx-attest-sys/build.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2022 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +extern crate bindgen; + +use std::{env, path::PathBuf}; + +fn main() { + // Tell cargo to tell rustc to link the system tdx_attest + // shared library. + println!("cargo:rustc-link-lib=tdx_attest"); + + // Tell cargo to invalidate the built crate whenever the wrapper changes + println!("cargo:rerun-if-changed=bindings.h"); + + // Set sdk to search path if SGX_SDK is in environment variable + let mut sdk_inc = String::from(""); + match env::var("SGX_SDK") { + Ok(val) => { + sdk_inc.push_str("-I"); + sdk_inc.push_str(&val); + sdk_inc.push_str("/include/"); + } + _ => (), + } + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let bindings = bindgen::Builder::default() + // The input header we would like to generate + // bindings for. + .header("bindings.h") + // Include search path + .clang_arg(sdk_inc) + // Convert C enum to Rust enum + .rustified_enum("_tdx_attest_error_t") + // Disable debug trait for packed C structures + .no_debug("_tdx_uuid_t") + .no_debug("_tdx_report_data_t") + .no_debug("_tdx_report_t") + .no_debug("_tdx_rtmr_event_t") + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/crates/teepot-tdx-attest-sys/src/lib.rs b/crates/teepot-tdx-attest-sys/src/lib.rs new file mode 100644 index 0000000..c4194d4 --- /dev/null +++ b/crates/teepot-tdx-attest-sys/src/lib.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2022 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +//! Intel(R) Software Guard Extensions Data Center Attestation Primitives (Intel(R) SGX DCAP) +//! Rust raw FFI bindings for TDX Attestation Library +//! ================================================ +//! +//! Please install the following prerequisite: +//! * Intel(R) SGX DCAP Driver +//! * Intel(R) SGX SDK +//! * Intel(R) SGX DCAP Packages +//! * Intel(R) SGX DCAP PCCS (Provisioning Certificate Caching Service) +//! +//! *Please refer to [SGX DCAP Linux installation guide]( +//! https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_SW_Installation_Guide_for_Linux.pdf) +//! to install above dependencies.* + +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/crates/teepot-tee-quote-verification-rs/Cargo.lock b/crates/teepot-tee-quote-verification-rs/Cargo.lock new file mode 100644 index 0000000..a906ad0 --- /dev/null +++ b/crates/teepot-tee-quote-verification-rs/Cargo.lock @@ -0,0 +1,516 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "intel-tee-quote-verification-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c8bc48d598fa48310e41f65a706e0beb2a74f5f9e5a26c5c2ca6cd83416fcc" +dependencies = [ + "bindgen 0.65.1", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.2", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "prettyplease" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "teepot-tdx-attest-rs" +version = "0.1.2" +dependencies = [ + "teepot-tdx-attest-sys", +] + +[[package]] +name = "teepot-tdx-attest-sys" +version = "0.1.0" +dependencies = [ + "bindgen 0.70.1", +] + +[[package]] +name = "teepot-tee-quote-verification-rs" +version = "0.6.0" +dependencies = [ + "intel-tee-quote-verification-sys", + "serde", + "teepot-tdx-attest-rs", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/crates/teepot-tee-quote-verification-rs/Cargo.toml b/crates/teepot-tee-quote-verification-rs/Cargo.toml index 8c0b6f3..cac4734 100644 --- a/crates/teepot-tee-quote-verification-rs/Cargo.toml +++ b/crates/teepot-tee-quote-verification-rs/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "teepot-tee-quote-verification-rs" -version = "0.3.0" +version = "0.6.0" edition = "2021" license = "BSD-3-Clause" repository = "https://github.com/matter-labs/teepot" @@ -14,4 +14,4 @@ serde = { version = "1", features = ["derive", "rc"] } [target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] intel-tee-quote-verification-sys = { version = "0.2.1" } -tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } +teepot-tdx-attest-rs = { version = "0.1.2", path = "../teepot-tdx-attest-rs" } diff --git a/crates/teepot-tee-quote-verification-rs/src/empty.rs b/crates/teepot-tee-quote-verification-rs/src/empty.rs index 9753abc..756b0ba 100644 --- a/crates/teepot-tee-quote-verification-rs/src/empty.rs +++ b/crates/teepot-tee-quote-verification-rs/src/empty.rs @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2025 Matter Labs +// SPDX-License-Identifier: BSD-3-Clause pub const NOTHING_TO_SEE_HERE: u8 = 0; diff --git a/crates/teepot-tee-quote-verification-rs/src/intel.rs b/crates/teepot-tee-quote-verification-rs/src/intel.rs index 2ce66e3..6e897c2 100644 --- a/crates/teepot-tee-quote-verification-rs/src/intel.rs +++ b/crates/teepot-tee-quote-verification-rs/src/intel.rs @@ -1,6 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024-2025 Matter Labs - // SPDX-License-Identifier: BSD-3-Clause /* * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. @@ -39,7 +36,7 @@ //! This is a safe wrapper for **sgx-dcap-quoteverify-sys**. pub mod tdx_attest_rs { - pub use tdx_attest_rs::*; + pub use teepot_tdx_attest_rs::*; } use serde::{Deserialize, Serialize}; diff --git a/crates/teepot-tee-quote-verification-rs/src/lib.rs b/crates/teepot-tee-quote-verification-rs/src/lib.rs index 75dd91f..9b51eeb 100644 --- a/crates/teepot-tee-quote-verification-rs/src/lib.rs +++ b/crates/teepot-tee-quote-verification-rs/src/lib.rs @@ -1,5 +1,4 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2024-2025 Matter Labs +// SPDX-License-Identifier: BSD-3-Clause #[cfg_attr(all(target_os = "linux", target_arch = "x86_64"), path = "intel.rs")] #[cfg_attr( diff --git a/packages/teepotCrate/default.nix b/packages/teepotCrate/default.nix index 07bad66..66006b5 100644 --- a/packages/teepotCrate/default.nix +++ b/packages/teepotCrate/default.nix @@ -50,6 +50,8 @@ let (maybeMissing (inputs.src + "/crates/teepot/tests/data")) (maybeMissing (inputs.src + "/crates/teepot-vault/tests/data")) (maybeMissing (inputs.src + "/crates/intel-dcap-api/tests/test_data")) + # special files + (maybeMissing (inputs.src + "/crates/teepot-tdx-attest-sys/bindings.h")) ]; }; From 49bb4a3befc4f76067e3ffc414fae6064e66336b Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 25 Jun 2025 09:31:29 +0200 Subject: [PATCH 112/114] chore(deps): update `teepot` crates to version 0.6.0 - Set `teepot`, `teepot-tee-quote-verification-rs`, and `teepot-vault` crate versions to 0.6.0 in `Cargo.toml`. - Ensures consistency with the planned 0.6.0 release preparation. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 306c7fe..a49e38b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,9 +69,9 @@ serde_yaml = "0.9.33" sha2 = "0.10.8" sha3 = "0.10.8" signature = "2.2.0" -teepot = { path = "crates/teepot" } +teepot = { version = "0.6.0", path = "crates/teepot" } teepot-tee-quote-verification-rs = { version = "0.6.0", path = "crates/teepot-tee-quote-verification-rs" } -teepot-vault = { path = "crates/teepot-vault" } +teepot-vault = { version = "0.6.0", path = "crates/teepot-vault" } testaso = "0.1.0" thiserror = "2.0.11" tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time", "signal"] } From ddbf099e45faa2c29f86cdadf1da2fe9ceffff8f Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 25 Jun 2025 09:47:38 +0200 Subject: [PATCH 113/114] docs: add README files for teepot-related crates - Added comprehensive README files for the following new crates: - `teepot` - `teepot-tdx-attest-rs` - `teepot-tdx-attest-sys` - `teepot-tee-quote-verification-rs` - `teepot-vault` - Each includes an overview, usage examples, installation instructions, and licensing details. --- crates/teepot-tdx-attest-rs/README.md | 149 ++++++++++++++ crates/teepot-tdx-attest-sys/README.md | 46 +++++ .../README.md | 182 ++++++++++++++++++ crates/teepot-vault/README.md | 134 +++++++++++++ crates/teepot/README.md | 72 +++++++ 5 files changed, 583 insertions(+) create mode 100644 crates/teepot-tdx-attest-rs/README.md create mode 100644 crates/teepot-tdx-attest-sys/README.md create mode 100644 crates/teepot-tee-quote-verification-rs/README.md create mode 100644 crates/teepot-vault/README.md create mode 100644 crates/teepot/README.md diff --git a/crates/teepot-tdx-attest-rs/README.md b/crates/teepot-tdx-attest-rs/README.md new file mode 100644 index 0000000..ac2dbbf --- /dev/null +++ b/crates/teepot-tdx-attest-rs/README.md @@ -0,0 +1,149 @@ +# teepot-tdx-attest-rs + +[![Crates.io](https://img.shields.io/crates/v/teepot-tdx-attest-rs.svg)](https://crates.io/crates/teepot-tdx-attest-rs) +[![Documentation](https://docs.rs/teepot-tdx-attest-rs/badge.svg)](https://docs.rs/teepot-tdx-attest-rs) +[![License](https://img.shields.io/crates/l/teepot-tdx-attest-rs.svg)](LICENSE) + +Rust bindings for Intel TDX (Trust Domain Extensions) attestation functionality. This crate provides a safe Rust interface to the Intel TDX attestation library, enabling trusted execution environments to generate attestation quotes and reports. + +This is a fork of the original [tdx-attest-rs](https://github.com/intel/SGXDataCenterAttestationPrimitives) crate, maintained as part of the [Teepot](https://github.com/matter-labs/teepot) project. + +## Features + +- Request TDX attestation quotes +- Generate TDX reports +- Extend runtime measurement registers (RTMRs) +- Query supported attestation key IDs +- Safe Rust wrappers around the Intel TDX attestation C library + +## Installation + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +teepot-tdx-attest-rs = "0.1.2" +``` + +## Usage + +### Generate a TDX Quote + +```rust +use teepot_tdx_attest_rs::*; + +// Prepare report data (typically a hash you want to bind to the quote) +let tdx_report_data = tdx_report_data_t { + d: [0; 64], // Your data here +}; + +// List of supported attestation key IDs +let att_key_id_list = [tdx_uuid_t { + d: [0; 16], // Your key ID +}]; + +let mut att_key_id = tdx_uuid_t { + d: [0; 16], +}; + +// Request the quote +let (result, quote) = tdx_att_get_quote( + Some(&tdx_report_data), + Some(&att_key_id_list), + Some(&mut att_key_id), + 0 +); + +match result { + tdx_attest_error_t::TDX_ATTEST_SUCCESS => { + // Process the quote + if let Some(quote_data) = quote { + println!("Quote generated successfully, size: {}", quote_data.len()); + } + } + _ => { + println!("Failed to generate quote: {:?}", result); + } +} +``` + +### Generate a TDX Report + +```rust +use teepot_tdx_attest_rs::*; + +let tdx_report_data = tdx_report_data_t { + d: [0; 64], // Your report data +}; + +let mut tdx_report = tdx_report_t { + d: [0; 1024], +}; + +let result = tdx_att_get_report(Some(&tdx_report_data), &mut tdx_report); + +if result == tdx_attest_error_t::TDX_ATTEST_SUCCESS { + println!("Report generated successfully"); +} +``` + +### Extend RTMR + +```rust +use teepot_tdx_attest_rs::*; + +// Prepare RTMR event data +let rtmr_event = vec![0u8; 68]; // Your event data + +let result = tdx_att_extend(&rtmr_event); + +if result == tdx_attest_error_t::TDX_ATTEST_SUCCESS { + println!("RTMR extended successfully"); +} +``` + +### Get Supported Attestation Key IDs + +```rust +use teepot_tdx_attest_rs::*; + +let (result, att_key_ids) = tdx_att_get_supported_att_key_ids(); + +if result == tdx_attest_error_t::TDX_ATTEST_SUCCESS { + if let Some(ids) = att_key_ids { + println!("Found {} supported attestation key IDs", ids.len()); + } +} +``` + +## Error Handling + +The crate uses the `tdx_attest_error_t` enum for error reporting. Common error values include: + +- `TDX_ATTEST_SUCCESS` - Operation completed successfully +- `TDX_ATTEST_ERROR_INVALID_PARAMETER` - Invalid parameter provided +- `TDX_ATTEST_ERROR_DEVICE_FAILURE` - Failed to access TDX attestation device +- `TDX_ATTEST_ERROR_OUT_OF_MEMORY` - Memory allocation failure +- `TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID` - Unsupported attestation key ID + +## Requirements + +- Intel TDX-enabled hardware +- TDX attestation runtime environment +- The `teepot-tdx-attest-sys` crate (automatically included as a dependency) + +## Safety + +This crate provides safe Rust wrappers around unsafe FFI calls to the Intel TDX attestation library. All pointer operations are handled internally, and the API uses Rust's type system to ensure safety. + +## License + +This project is licensed under the BSD-3-Clause License - see the [License.txt](License.txt) file for details. + +## Contributing + +This is a fork maintained as part of the Teepot project. For contributions, please visit the [Teepot repository](https://github.com/matter-labs/teepot). + +## Original Work + +This crate is based on Intel's SGX Data Center Attestation Primitives. The original source can be found at [Intel's repository](https://github.com/intel/SGXDataCenterAttestationPrimitives). \ No newline at end of file diff --git a/crates/teepot-tdx-attest-sys/README.md b/crates/teepot-tdx-attest-sys/README.md new file mode 100644 index 0000000..abd4cb9 --- /dev/null +++ b/crates/teepot-tdx-attest-sys/README.md @@ -0,0 +1,46 @@ +# teepot-tdx-attest-sys + +[![Crates.io](https://img.shields.io/crates/v/teepot-tdx-attest-sys.svg)](https://crates.io/crates/teepot-tdx-attest-sys) +[![Documentation](https://docs.rs/teepot-tdx-attest-sys/badge.svg)](https://docs.rs/teepot-tdx-attest-sys) +[![License](https://img.shields.io/crates/l/teepot-tdx-attest-sys.svg)](https://github.com/matter-labs/teepot/blob/main/crates/teepot-tdx-attest-sys/License.txt) + +Raw FFI bindings to Intel TDX Attestation Library (`libtdx_attest`). + +This crate provides low-level FFI bindings for Intel Trust Domain Extensions (TDX) attestation functionality. It is a fork of the original [tdx-attest-sys](https://github.com/intel/SGXDataCenterAttestationPrimitives) crate from Intel's SGX Data Center Attestation Primitives. + +## Prerequisites + +Before using this crate, you need to install: + +- Intel® SGX DCAP Driver +- Intel® SGX SDK +- Intel® SGX DCAP Packages +- Intel® SGX DCAP PCCS (Provisioning Certificate Caching Service) + +Please refer to the [SGX DCAP Linux installation guide](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_SW_Installation_Guide_for_Linux.pdf) for detailed installation instructions. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +teepot-tdx-attest-sys = "0.1.0" +``` + +This crate provides raw FFI bindings. For a more ergonomic Rust API, consider using a higher-level wrapper crate. + +## Building + +The crate uses `bindgen` to generate Rust bindings from the C headers during build time. Make sure you have: + +- The TDX attestation library (`libtdx_attest`) installed on your system +- If using Intel SGX SDK, set the `SGX_SDK` environment variable to point to your SDK installation + +## License + +This project is licensed under the BSD-3-Clause License. See the [License.txt](License.txt) file for details. + +## Repository + +This crate is part of the [Teepot](https://github.com/matter-labs/teepot) project. \ No newline at end of file diff --git a/crates/teepot-tee-quote-verification-rs/README.md b/crates/teepot-tee-quote-verification-rs/README.md new file mode 100644 index 0000000..bc3480a --- /dev/null +++ b/crates/teepot-tee-quote-verification-rs/README.md @@ -0,0 +1,182 @@ +# teepot-tee-quote-verification-rs + +[![Crates.io](https://img.shields.io/crates/v/teepot-tee-quote-verification-rs.svg)](https://crates.io/crates/teepot-tee-quote-verification-rs) +[![Documentation](https://docs.rs/teepot-tee-quote-verification-rs/badge.svg)](https://docs.rs/teepot-tee-quote-verification-rs) +[![License](https://img.shields.io/crates/l/teepot-tee-quote-verification-rs.svg)](https://github.com/matter-labs/teepot/blob/main/LICENSE) + +A Rust wrapper for Intel® Software Guard Extensions (SGX) and Trust Domain Extensions (TDX) quote verification. + +This crate is a fork of the original [intel-tee-quote-verification-rs](https://github.com/intel/SGXDataCenterAttestationPrimitives) crate, providing safe Rust bindings for the Intel Quote Verification Library (QVL). + +## Features + +- Safe Rust wrappers for SGX and TDX quote verification APIs +- Support for both SGX ECDSA and TDX ECDSA quote verification +- Collateral management for quote verification +- Supplemental data handling +- Cross-platform support (Linux x86_64) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +teepot-tee-quote-verification-rs = "0.6.0" +``` + +### Example: Verify an SGX Quote + +```rust +use teepot_tee_quote_verification_rs::*; + +fn verify_sgx_quote(quote: &[u8]) -> Result<(), quote3_error_t> { + // Get collateral for the quote + let collateral = tee_qv_get_collateral(quote)?; + + // Get supplemental data size + let supp_data_size = sgx_qv_get_quote_supplemental_data_size()?; + let mut supp_data = sgx_ql_qv_supplemental_t::default(); + + // Verify the quote + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + + let (expiration_status, verification_result) = sgx_qv_verify_quote( + quote, + Some(&collateral), + current_time, + None, // QvE report info (None for host-based verification) + supp_data_size, + Some(&mut supp_data), + )?; + + match verification_result { + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => { + println!("Quote verification passed!"); + Ok(()) + } + _ => { + println!("Quote verification failed: {:?}", verification_result); + Err(quote3_error_t::SGX_QL_ERROR_INVALID_PARAMETER) + } + } +} +``` + +### Example: Verify a TDX Quote + +```rust +use teepot_tee_quote_verification_rs::*; + +fn verify_tdx_quote(quote: &[u8]) -> Result<(), quote3_error_t> { + // Get collateral for the quote + let collateral = tee_qv_get_collateral(quote)?; + + // Get supplemental data size + let supp_data_size = tdx_qv_get_quote_supplemental_data_size()?; + let mut supp_data = sgx_ql_qv_supplemental_t::default(); + + // Verify the quote + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + + let (expiration_status, verification_result) = tdx_qv_verify_quote( + quote, + Some(&collateral), + current_time, + None, // QvE report info + supp_data_size, + Some(&mut supp_data), + )?; + + match verification_result { + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => { + println!("TDX quote verification passed!"); + Ok(()) + } + _ => { + println!("TDX quote verification failed: {:?}", verification_result); + Err(quote3_error_t::SGX_QL_ERROR_INVALID_PARAMETER) + } + } +} +``` + +### Unified TEE Quote Verification + +For a unified interface that works with both SGX and TDX quotes: + +```rust +use teepot_tee_quote_verification_rs::*; + +fn verify_tee_quote(quote: &[u8]) -> Result<(), quote3_error_t> { + // Get collateral + let collateral = tee_qv_get_collateral(quote)?; + + // Get supplemental data version and size + let (version, data_size) = tee_get_supplemental_data_version_and_size(quote)?; + + // Prepare supplemental data descriptor + let mut supp_data_desc = tee_supp_data_descriptor_t { + major_version: version, + data_size, + p_data: std::ptr::null_mut(), + }; + + // Allocate buffer for supplemental data if needed + let mut supp_data_buffer = vec![0u8; data_size as usize]; + if data_size > 0 { + supp_data_desc.p_data = supp_data_buffer.as_mut_ptr(); + } + + // Verify quote + let current_time = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + + let (expiration_status, verification_result) = tee_verify_quote( + quote, + Some(&collateral), + current_time, + None, + Some(&mut supp_data_desc), + )?; + + println!("Verification result: {:?}", verification_result); + println!("Collateral expiration status: {}", expiration_status); + + Ok(()) +} +``` + +## Platform Support + +This crate is currently supported on: +- Linux x86_64 + +On other platforms, the crate will compile but provide stub implementations. + +## Dependencies + +On Linux x86_64, this crate depends on: +- `intel-tee-quote-verification-sys`: System bindings for Intel QVL +- `teepot-tdx-attest-rs`: TDX attestation support + +## License + +This project is licensed under the BSD-3-Clause License. See the [LICENSE](https://github.com/matter-labs/teepot/blob/main/LICENSE) file for details. + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request to the [Teepot repository](https://github.com/matter-labs/teepot). + +## Related Crates + +- [intel-tee-quote-verification-rs](https://github.com/intel/SGXDataCenterAttestationPrimitives) - The original Intel crate +- [teepot-tdx-attest-rs](https://crates.io/crates/teepot-tdx-attest-rs) - TDX attestation support \ No newline at end of file diff --git a/crates/teepot-vault/README.md b/crates/teepot-vault/README.md new file mode 100644 index 0000000..016abe7 --- /dev/null +++ b/crates/teepot-vault/README.md @@ -0,0 +1,134 @@ +# teepot-vault + +[![Crates.io](https://img.shields.io/crates/v/teepot-vault.svg)](https://crates.io/crates/teepot-vault) +[![Documentation](https://docs.rs/teepot-vault/badge.svg)](https://docs.rs/teepot-vault) +[![License](https://img.shields.io/crates/l/teepot-vault.svg)](LICENSE) + +A TEE (Trusted Execution Environment) secret manager that provides secure storage and retrieval of secrets for TEE applications, with a focus on Intel SGX enclaves. + +## Features + +- **Remote Attestation**: Verify Intel SGX enclaves and other TEEs using attestation reports +- **Secure Communication**: Establish TLS connections with custom certificate verification based on TEE attestation +- **HashiCorp Vault Integration**: Store and retrieve secrets with TEE-specific access controls +- **Multi-signature Support**: PGP-based multi-signature verification for administrative commands +- **Configurable TCB Levels**: Support for different Trusted Computing Base security levels + +## Installation + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +teepot-vault = "0.6.0" +``` + +## Usage + +### Creating a Vault Connection + +```rust +use teepot_vault::client::{AttestationArgs, VaultConnection}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let args = AttestationArgs { + sgx_mrsigner: Some("your_mrsigner_hex".to_string()), + sgx_mrenclave: Some("your_mrenclave_hex".to_string()), + server: "https://vault.example.com".to_string(), + sgx_allowed_tcb_levels: Some(vec!["Ok".to_string(), "ConfigNeeded".to_string()]), + }; + + let vault_conn = VaultConnection::new(&args, "my-tee-app".to_string()).await?; + + Ok(()) +} +``` + +### Storing and Retrieving Secrets + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize)] +struct MySecret { + api_key: String, + private_key: Vec, +} + +// Store a secret +let my_secret = MySecret { + api_key: "secret-key".to_string(), + private_key: vec![1, 2, 3, 4], +}; +vault_conn.store_secret(my_secret, "secrets/my-app/config").await?; + +// Retrieve a secret +let secret: MySecret = vault_conn.load_secret("secrets/my-app/config").await?.unwrap(); +``` + +### Custom TEE Connections + +For more control over the connection and custom operations: + +```rust +use teepot_vault::client::TeeConnection; + +let tee_conn = TeeConnection::new(&args); +let client = tee_conn.client(); // Get the HTTP client for custom requests + +// Perform custom authenticated requests +let response = client + .get("https://vault.example.com/custom/endpoint") + .send() + .await?; +``` + +## Server Components + +The crate also provides server-side utilities for building TEE-aware services: + +```rust +use teepot_vault::server::{HttpResponseError, Status}; +use actix_web::{web, App, HttpServer, Result}; + +async fn handler() -> Result { + // Your TEE service logic here + Ok("Secure response".to_string()) +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + HttpServer::new(|| { + App::new() + .route("/api/secure", web::get().to(handler)) + }) + .bind("127.0.0.1:8080")? + .run() + .await +} +``` + +## Requirements + +- Rust 1.70 or later +- For SGX support: Intel SGX SDK and PSW (Platform Software) +- HashiCorp Vault instance (for vault operations) +- TEE environment (Intel SGX, Intel TDX, or compatible) + +## Security Considerations + +This crate is designed for use in high-security environments. When using it: + +1. Always verify attestation reports before trusting a TEE +2. Use appropriate TCB levels for your security requirements +3. Ensure proper key management for PGP signatures +4. Follow HashiCorp Vault best practices for secret management + +## License + +This project is licensed under the Apache License 2.0 - see the LICENSE file for details. + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. \ No newline at end of file diff --git a/crates/teepot/README.md b/crates/teepot/README.md new file mode 100644 index 0000000..2ab3478 --- /dev/null +++ b/crates/teepot/README.md @@ -0,0 +1,72 @@ +# teepot + +TEE (Trusted Execution Environment) utilities for Intel SGX and TDX attestation. + +## Overview + +Teepot provides comprehensive support for generating and verifying attestation quotes from Intel SGX enclaves and TDX trust domains. It handles the complete attestation workflow including quote generation, collateral fetching, and verification with detailed TCB (Trusted Computing Base) status reporting. + +## Features + +- **Multi-TEE Support**: Works with both Intel SGX and Intel TDX +- **Attestation Quote Generation**: Generate quotes with custom report data +- **Quote Verification**: Verify quotes with automatic collateral fetching +- **TCB Level Management**: Filter quotes by security level +- **Cross-Platform**: Native support for Linux x86_64, fallback implementation for other platforms +- **Gramine SGX Support**: Special support for Gramine-based SGX enclaves +- **Comprehensive Error Handling**: Detailed error context for debugging + +## Usage + +### Basic Quote Generation and Verification + +```rust +use teepot::quote::{get_quote, get_collateral, verify_quote_with_collateral}; + +// Generate a quote with custom data +let report_data = [0u8; 64]; // Your custom data here +let quote = get_quote(&report_data)?; + +// Fetch collateral for verification +let collateral = get_collateral("e)?; + +// Verify the quote +let result = verify_quote_with_collateral("e, collateral.as_ref(), None)?; +println!("TCB Level: {:?}", result.tcb_level); +``` + +### High-Level Attestation API + +```rust +use teepot::quote::attestation::get_quote_and_collateral; + +// Generate quote and fetch collateral in one call +let (quote, collateral, result) = get_quote_and_collateral(&report_data)?; +``` + +### TCB Level Filtering + +```rust +use teepot::quote::{TcbLevel, verify_quote_with_collateral}; + +// Only accept quotes with up-to-date TCB +let accepted_levels = vec![TcbLevel::Ok]; +let result = verify_quote_with_collateral("e, collateral.as_ref(), Some(&accepted_levels))?; +``` + +## Supported Platforms + +- **Full support**: Linux x86_64 with Intel SGX/TDX drivers +- **Verification only**: All other platforms via `dcap-qvl` + +## Dependencies + +On Linux x86_64, the crate uses Intel's DCAP libraries for quote generation. Make sure you have: +- Intel SGX DCAP Quote Generation Library +- Intel SGX DCAP Quote Verification Library + +## License + +This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details. + +Note: Some code is derived from the [Enarx project](https://github.com/enarx/). \ No newline at end of file From ce9560cff040b21eda4b4636227cb644bd8c4eb9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:14:32 +0000 Subject: [PATCH 114/114] chore(deps): update cachix/install-nix-action action to v31 --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0808331..35718cb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,5 +28,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - uses: cachix/install-nix-action@v30 + - uses: cachix/install-nix-action@v31 - run: nix run nixpkgs#taplo -- fmt --check