mirror of
https://github.com/matter-labs/teepot.git
synced 2025-07-21 15:13:56 +02:00
Merge pull request #300 from matter-labs/darwin
feat: compat code for non `x86_64-linux`
This commit is contained in:
commit
93c35dad38
44 changed files with 1543 additions and 531 deletions
38
.github/workflows/nix-non-x86.yml
vendored
Normal file
38
.github/workflows/nix-non-x86.yml
vendored
Normal file
|
@ -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
|
||||
|
557
Cargo.lock
generated
557
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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"] }
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -6,14 +6,18 @@
|
|||
#![deny(missing_docs)]
|
||||
#![deny(clippy::all)]
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use tracing::error;
|
||||
|
||||
#[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::{error, level_filters::LevelFilter};
|
||||
use tracing::level_filters::LevelFilter;
|
||||
|
||||
/// Extend a TDX rtmr with a hash digest for measured boot.
|
||||
#[derive(Parser, Debug)]
|
||||
|
@ -31,7 +35,7 @@ struct Arguments {
|
|||
pub log_level: LevelFilter,
|
||||
}
|
||||
|
||||
fn main_with_error() -> Result<()> {
|
||||
pub fn main_with_error() -> Result<()> {
|
||||
let args = Arguments::parse();
|
||||
tracing::subscriber::set_global_default(setup_logging(
|
||||
env!("CARGO_CRATE_NAME"),
|
||||
|
@ -50,9 +54,16 @@ fn main_with_error() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let ret = main_with_error();
|
||||
#[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() -> anyhow::Result<()> {
|
||||
let ret = os::main_with_error();
|
||||
if let Err(e) = &ret {
|
||||
error!(error = %e, "Execution failed");
|
||||
}
|
||||
|
|
|
@ -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<OsString>,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
|
|
|
@ -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<QuoteVerif
|
|||
"Verifying quote ({} bytes)...",
|
||||
attestation_quote_bytes.len()
|
||||
);
|
||||
let collateral = error::QuoteContext::context(
|
||||
tee_qv_get_collateral(attestation_quote_bytes),
|
||||
"Failed to get collateral",
|
||||
)?;
|
||||
let collateral = get_collateral(attestation_quote_bytes)?;
|
||||
let unix_time: i64 = std::time::SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)?
|
||||
.as_secs() as _;
|
||||
|
@ -76,7 +70,7 @@ fn verify_attestation_quote(attestation_quote_bytes: &[u8]) -> Result<QuoteVerif
|
|||
fn print_quote_verification_summary(quote_verification_result: &QuoteVerificationResult) {
|
||||
let QuoteVerificationResult {
|
||||
collateral_expired,
|
||||
result,
|
||||
result: tcblevel,
|
||||
quote,
|
||||
advisories,
|
||||
..
|
||||
|
@ -84,7 +78,6 @@ fn print_quote_verification_summary(quote_verification_result: &QuoteVerificatio
|
|||
if *collateral_expired {
|
||||
println!("Freshly fetched collateral expired");
|
||||
}
|
||||
let tcblevel = TcbLevel::from(*result);
|
||||
for advisory in advisories {
|
||||
println!("\tInfo: Advisory ID: {advisory}");
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// 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 teepot::quote::{get_collateral, verify_quote_with_collateral, QuoteVerificationResult};
|
||||
|
||||
use crate::error;
|
||||
|
||||
|
@ -15,10 +12,7 @@ impl AttestationVerifier {
|
|||
/// Verify an attestation quote
|
||||
pub fn verify_quote(attestation_quote_bytes: &[u8]) -> error::Result<QuoteVerificationResult> {
|
||||
// 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()
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,11 +219,10 @@ impl TeeConnection {
|
|||
)));
|
||||
}
|
||||
|
||||
let tcblevel = TcbLevel::from(result);
|
||||
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!(
|
||||
|
|
|
@ -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(),
|
||||
|
@ -298,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<T: serde::Serialize>(
|
||||
&self,
|
||||
val: T,
|
||||
rel_path: &str,
|
||||
|
@ -307,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<T: serde::Serialize>(
|
||||
&self,
|
||||
tee_name: &str,
|
||||
val: T,
|
||||
|
@ -331,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<T: serde::de::DeserializeOwned>(
|
||||
&self,
|
||||
rel_path: &str,
|
||||
) -> Result<Option<T>, HttpResponseError> {
|
||||
|
@ -339,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<T: serde::de::DeserializeOwned>(
|
||||
&self,
|
||||
tee_name: &str,
|
||||
rel_path: &str,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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<Option<Attestation>> = 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,9 +80,8 @@ 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))
|
||||
&& allowed_tcb_levels.is_some_and(|levels| !levels.contains(tcblevel))
|
||||
{
|
||||
error!("Quote verification result: {}", tcblevel);
|
||||
bail!("Quote verification result: {}", tcblevel);
|
||||
|
|
|
@ -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<tdx_attest_error_t> for QuoteError {
|
||||
fn from(code: tdx_attest_error_t) -> Self {
|
||||
Self::TdxAttGetQuote {
|
||||
|
@ -64,16 +86,29 @@ impl<T> QuoteContext for Result<T, std::io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> QuoteContext for Result<T, quote3_error_t> {
|
||||
impl<T> QuoteContext for Option<T> {
|
||||
type Ok = T;
|
||||
fn context<I: Into<String>>(self, msg: I) -> Result<T, QuoteError> {
|
||||
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<I: std::fmt::Display>(self, msg: I) -> Result<Self::Ok, QuoteError>;
|
||||
}
|
||||
|
||||
impl<T, E: std::fmt::Display> QuoteContextErr for Result<T, E> {
|
||||
type Ok = T;
|
||||
fn str_context<I: std::fmt::Display>(self, msg: I) -> Result<T, QuoteError> {
|
||||
self.map_err(|e| QuoteError::Unexpected(format!("{}: {}", msg, e)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
impl<T> QuoteContext for Result<T, tdx_attest_error_t> {
|
||||
type Ok = T;
|
||||
fn context<I: Into<String>>(self, msg: I) -> Result<T, QuoteError> {
|
||||
|
|
260
crates/teepot/src/quote/intel.rs
Normal file
260
crates/teepot/src/quote/intel.rs
Normal file
|
@ -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<String>) -> 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<Collateral, QuoteError> {
|
||||
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<String>, 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<QuoteVerificationResult, QuoteError> {
|
||||
// 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<Box<MaybeUninit<sgx_ql_qv_supplemental_t>>>,
|
||||
supp_data_descriptor: Option<tee_supp_data_descriptor_t>,
|
||||
}
|
||||
|
||||
fn initialize_supplemental_data(quote: &[u8]) -> Result<TeeSuppDataDescriptor, QuoteError> {
|
||||
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::<sgx_ql_qv_supplemental_t>() 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::<sgx_ql_qv_supplemental_t>(): {}",
|
||||
mem::size_of::<sgx_ql_qv_supplemental_t>()
|
||||
);
|
||||
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<Box<[u8]>, 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<TEEType, QuoteError> {
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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<Collateral, QuoteError> {
|
||||
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<QuoteVerificationResult, QuoteError> {
|
||||
let mut supp_data: mem::MaybeUninit<sgx_ql_qv_supplemental_t> = 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::<sgx_ql_qv_supplemental_t>() 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::<sgx_ql_qv_supplemental_t>(): {}",
|
||||
mem::size_of::<sgx_ql_qv_supplemental_t>()
|
||||
);
|
||||
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)
|
||||
}
|
||||
|
|
259
crates/teepot/src/quote/phala.rs
Normal file
259
crates/teepot/src/quote/phala.rs
Normal file
|
@ -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<String, QuoteError> {
|
||||
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<Collateral, QuoteError> {
|
||||
// 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<Collateral, QuoteError> {
|
||||
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<Box<[u8]>, 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<String, QuoteError> {
|
||||
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::Value, QuoteError> {
|
||||
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<QuoteCollateralV3, QuoteError> {
|
||||
// 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<QuoteVerificationResult, QuoteError> {
|
||||
// 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)
|
||||
}
|
|
@ -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<sgx_ql_qv_result_t> 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<Self, Self::Err> {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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<Box<[u8]>, 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,
|
||||
];
|
||||
|
|
|
@ -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<TdxRtmrEvent> for Vec<u8> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::UEFI_MARKER_DIGEST_BYTES;
|
||||
use crate::tdx::UEFI_MARKER_DIGEST_BYTES;
|
||||
|
||||
#[test]
|
||||
fn test_uefi_marker_digest() {
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -32,6 +32,7 @@ allow = [
|
|||
"BSD-3-Clause",
|
||||
"OpenSSL",
|
||||
"CC0-1.0",
|
||||
"Zlib",
|
||||
]
|
||||
confidence-threshold = 0.8
|
||||
exceptions = []
|
||||
|
|
6
flake.lock
generated
6
flake.lock
generated
|
@ -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": {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ lib
|
||||
, stdenv
|
||||
, openssl
|
||||
, curl
|
||||
, dockerTools
|
||||
|
@ -8,10 +9,13 @@
|
|||
, teepot
|
||||
, nixsgx
|
||||
}:
|
||||
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.Entrypoint = [ "${teepot.teepot.tdx_test}/bin/tdx-test" ];
|
||||
config.Env = [
|
||||
"SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"
|
||||
];
|
||||
|
@ -23,8 +27,8 @@ dockerTools.buildLayeredImage {
|
|||
teepot.teepot.tdx_test
|
||||
openssl.out
|
||||
curl.out
|
||||
nixsgx.sgx-dcap.quote_verify
|
||||
nixsgx.sgx-dcap.default_qpl
|
||||
# nixsgx.sgx-dcap.quote_verify
|
||||
# nixsgx.sgx-dcap.default_qpl
|
||||
usrBinEnv
|
||||
binSh
|
||||
caCertificates
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ dockerTools
|
||||
, lib
|
||||
, stdenv
|
||||
, buildEnv
|
||||
, teepot
|
||||
, openssl
|
||||
, curl
|
||||
, nixsgx
|
||||
}:
|
||||
if (stdenv.hostPlatform.isDarwin) then {
|
||||
# FIXME: dockerTools.buildLayeredImage seems to be broken on Darwin
|
||||
} else
|
||||
dockerTools.buildLayeredImage {
|
||||
name = "vault-unseal";
|
||||
|
||||
|
@ -14,17 +19,25 @@ dockerTools.buildLayeredImage {
|
|||
|
||||
contents = buildEnv {
|
||||
name = "image-root";
|
||||
paths = with dockerTools; with nixsgx;[
|
||||
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
|
||||
] ++ lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [
|
||||
sgx-dcap.quote_verify
|
||||
sgx-dcap.default_qpl
|
||||
];
|
||||
pathsToLink = [
|
||||
"/bin"
|
||||
"/lib"
|
||||
"/etc"
|
||||
];
|
||||
pathsToLink = [ "/bin" "/lib" "/etc" ];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,11 +2,16 @@
|
|||
# Copyright (c) 2024 Matter Labs
|
||||
{ dockerTools
|
||||
, buildEnv
|
||||
, lib
|
||||
, stdenv
|
||||
, teepot
|
||||
, openssl
|
||||
, curl
|
||||
, nixsgx
|
||||
}:
|
||||
if (stdenv.hostPlatform.isDarwin) then {
|
||||
# FIXME: dockerTools.buildLayeredImage seems to be broken on Darwin
|
||||
} else
|
||||
dockerTools.buildLayeredImage {
|
||||
name = "verify-attestation-sgx";
|
||||
|
||||
|
@ -15,17 +20,26 @@ dockerTools.buildLayeredImage {
|
|||
contents = buildEnv {
|
||||
name = "image-root";
|
||||
|
||||
paths = with dockerTools; with nixsgx;[
|
||||
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
|
||||
] ++ lib.optionals (stdenv.hostPlatform.system == "x86_64-linux") [
|
||||
sgx-dcap.quote_verify
|
||||
sgx-dcap.default_qpl
|
||||
];
|
||||
pathsToLink = [
|
||||
"/bin"
|
||||
"/lib"
|
||||
"/etc"
|
||||
"/share"
|
||||
];
|
||||
pathsToLink = [ "/bin" "/lib" "/etc" "/share" ];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,20 +3,29 @@
|
|||
{ dockerTools
|
||||
, buildEnv
|
||||
, teepot
|
||||
, stdenv
|
||||
, openssl
|
||||
, curl
|
||||
, nixsgx
|
||||
, pkg-config
|
||||
}:
|
||||
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.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;[
|
||||
paths =
|
||||
with dockerTools;
|
||||
with nixsgx;
|
||||
[
|
||||
pkg-config
|
||||
openssl.out
|
||||
curl.out
|
||||
|
@ -28,6 +37,11 @@ dockerTools.buildLayeredImage {
|
|||
caCertificates
|
||||
fakeNss
|
||||
];
|
||||
pathsToLink = [ "/bin" "/lib" "/etc" "/share" ];
|
||||
pathsToLink = [
|
||||
"/bin"
|
||||
"/lib"
|
||||
"/etc"
|
||||
"/share"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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/"
|
||||
|
||||
'' + 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 ]}" \
|
||||
--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"
|
||||
'';
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "1.83"
|
||||
channel = "1.86"
|
||||
components = ["rustfmt", "clippy", "rust-src"]
|
||||
|
|
|
@ -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; [
|
||||
packages =
|
||||
with pkgs;
|
||||
[
|
||||
dive
|
||||
taplo
|
||||
vault
|
||||
cargo-release
|
||||
google-cloud-sdk-gce
|
||||
azure-cli
|
||||
kubectl
|
||||
kubectx
|
||||
k9s
|
||||
google-cloud-sdk
|
||||
];
|
||||
|
||||
TEE_LD_LIBRARY_PATH = lib.makeLibraryPath [
|
||||
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";
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue