chore: split-out vault code from teepot in teepot-vault

Signed-off-by: Harald Hoyer <harald@matterlabs.dev>
This commit is contained in:
Harald Hoyer 2025-02-18 13:37:34 +01:00
parent 63c16b1177
commit f8bd9e6a08
Signed by: harald
GPG key ID: F519A1143B3FBE32
61 changed files with 450 additions and 308 deletions

51
Cargo.lock generated
View file

@ -5559,6 +5559,7 @@ dependencies = [
"clap 4.5.30", "clap 4.5.30",
"serde", "serde",
"teepot", "teepot",
"teepot-vault",
"tracing", "tracing",
"tracing-log 0.2.0", "tracing-log 0.2.0",
"tracing-subscriber", "tracing-subscriber",
@ -5578,6 +5579,7 @@ dependencies = [
"serde_json", "serde_json",
"sha2", "sha2",
"teepot", "teepot",
"teepot-vault",
"tracing", "tracing",
"tracing-actix-web", "tracing-actix-web",
"tracing-log 0.2.0", "tracing-log 0.2.0",
@ -5595,6 +5597,7 @@ dependencies = [
"rustls", "rustls",
"serde_json", "serde_json",
"teepot", "teepot",
"teepot-vault",
"tracing", "tracing",
"tracing-log 0.2.0", "tracing-log 0.2.0",
"tracing-subscriber", "tracing-subscriber",
@ -5604,19 +5607,14 @@ dependencies = [
name = "teepot" name = "teepot"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"actix-http",
"actix-web",
"anyhow", "anyhow",
"async-trait", "async-trait",
"awc",
"base64 0.22.1", "base64 0.22.1",
"bytemuck", "bytemuck",
"bytes",
"clap 4.5.30", "clap 4.5.30",
"config", "config",
"const-oid", "const-oid",
"enumset", "enumset",
"futures-core",
"getrandom 0.3.1", "getrandom 0.3.1",
"hex", "hex",
"num-integer", "num-integer",
@ -5627,7 +5625,6 @@ dependencies = [
"opentelemetry-semantic-conventions 0.28.0", "opentelemetry-semantic-conventions 0.28.0",
"opentelemetry_sdk 0.28.0", "opentelemetry_sdk 0.28.0",
"p256", "p256",
"pgp",
"pkcs8 0.10.2", "pkcs8 0.10.2",
"reqwest 0.12.12", "reqwest 0.12.12",
"rsa", "rsa",
@ -5635,7 +5632,6 @@ dependencies = [
"secp256k1 0.30.0", "secp256k1 0.30.0",
"serde", "serde",
"serde_json", "serde_json",
"serde_with 3.12.0",
"sha2", "sha2",
"sha3", "sha3",
"signature 2.2.0", "signature 2.2.0",
@ -5649,10 +5645,8 @@ dependencies = [
"tracing-log 0.2.0", "tracing-log 0.2.0",
"tracing-subscriber", "tracing-subscriber",
"tracing-test", "tracing-test",
"webpki-roots",
"x509-cert", "x509-cert",
"zeroize", "zeroize",
"zksync_basic_types",
] ]
[[package]] [[package]]
@ -5664,7 +5658,7 @@ dependencies = [
"awc", "awc",
"clap 4.5.30", "clap 4.5.30",
"serde_json", "serde_json",
"teepot", "teepot-vault",
"tracing", "tracing",
"tracing-log 0.2.0", "tracing-log 0.2.0",
"tracing-subscriber", "tracing-subscriber",
@ -5678,6 +5672,35 @@ dependencies = [
"serde", "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]] [[package]]
name = "teepot-write" name = "teepot-write"
version = "0.3.0" version = "0.3.0"
@ -5687,7 +5710,7 @@ dependencies = [
"awc", "awc",
"clap 4.5.30", "clap 4.5.30",
"serde_json", "serde_json",
"teepot", "teepot-vault",
"tracing", "tracing",
"tracing-log 0.2.0", "tracing-log 0.2.0",
"tracing-subscriber", "tracing-subscriber",
@ -6396,6 +6419,7 @@ dependencies = [
"pgp", "pgp",
"serde_json", "serde_json",
"teepot", "teepot",
"teepot-vault",
"tracing", "tracing",
] ]
@ -6408,7 +6432,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"clap 4.5.30", "clap 4.5.30",
"serde_json", "serde_json",
"teepot", "teepot-vault",
"tracing", "tracing",
"tracing-log 0.2.0", "tracing-log 0.2.0",
"tracing-subscriber", "tracing-subscriber",
@ -6432,10 +6456,7 @@ version = "0.3.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 4.5.30", "clap 4.5.30",
"hex",
"secp256k1 0.30.0",
"teepot", "teepot",
"zksync_basic_types",
] ]
[[package]] [[package]]

View file

@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["crates/*", "bin/*"] members = ["crates/*", "bin/*", "crates/teepot-vault/bin/*"]
resolver = "2" resolver = "2"
[profile.release] [profile.release]
@ -16,7 +16,6 @@ repository = "https://github.com/matter-labs/teepot"
homepage = "https://github.com/matter-labs/teepot" homepage = "https://github.com/matter-labs/teepot"
[workspace.dependencies] [workspace.dependencies]
actix-http = "3"
actix-web = { version = "4.5", features = ["rustls-0_23"] } actix-web = { version = "4.5", features = ["rustls-0_23"] }
anyhow = "1.0.82" anyhow = "1.0.82"
async-trait = "0.1.86" 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"] } 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", default-features = false }
enumset = { version = "1.1", features = ["serde"] } enumset = { version = "1.1", features = ["serde"] }
futures-core = { version = "0.3.30", features = ["alloc"], default-features = false }
getrandom = { version = "0.3.1", features = ["std"] } getrandom = { version = "0.3.1", features = ["std"] }
gpt = "4.0.0" gpt = "4.0.0"
hex = { version = "0.4.3", features = ["std"], default-features = false } hex = { version = "0.4.3", features = ["std"], default-features = false }
@ -58,6 +56,7 @@ sha3 = "0.10.8"
signature = "2.2.0" signature = "2.2.0"
tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" } tdx-attest-rs = { version = "0.1.2", git = "https://github.com/intel/SGXDataCenterAttestationPrimitives.git", rev = "aa239d25a437a28f3f4de92c38f5b6809faac842" }
teepot = { path = "crates/teepot" } teepot = { path = "crates/teepot" }
teepot-vault = { path = "crates/teepot-vault" }
testaso = "0.1.0" testaso = "0.1.0"
thiserror = "2.0.11" thiserror = "2.0.11"
tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time", "signal"] } 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-subscriber = { version = "0.3", features = ["env-filter", "json", "ansi"] }
tracing-test = { version = "0.2.5", features = ["no-env-filter"] } tracing-test = { version = "0.2.5", features = ["no-env-filter"] }
url = "2.5.2" url = "2.5.2"
webpki-roots = "0.26.1"
x509-cert = { version = "0.2", features = ["builder", "signature"] } x509-cert = { version = "0.2", features = ["builder", "signature"] }
zeroize = { version = "1.7.0", features = ["serde"] } zeroize = { version = "1.7.0", features = ["serde"] }
zksync_basic_types = "=0.1.0"
zksync_types = "=0.1.0"
zksync_web3_decl = "=0.1.0"

View file

@ -2,31 +2,37 @@
## Parts of this project ## Parts of this project
- `teepot`: The main rust crate that abstracts TEEs and key-value stores. ### teepot - lib
- `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.
## 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 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 for Authentication. The key-value store is implemented using Hashicorp Vault running in an Intel SGX enclave via the
Gramine runtime. 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 ## Development
### Prerequisites ### Prerequisites
@ -77,7 +83,7 @@ $ nix run .#fmt
### Build as the CI would ### Build as the CI would
```shell ```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 ### Build and test individual container

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! 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::os::unix::process::CommandExt;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use teepot::server::pki::make_signed_cert; use teepot::pki::make_signed_cert;
use tracing::error; use tracing::error;
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023-2024 Matter Labs // Copyright (c) 2023-2025 Matter Labs
//! Simple TEE self-attestation test //! Simple TEE self-attestation test
@ -8,7 +8,7 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use base64::{engine::general_purpose, Engine as _}; 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_log::LogTracer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};

View file

@ -10,7 +10,4 @@ repository.workspace = true
[dependencies] [dependencies]
anyhow.workspace = true anyhow.workspace = true
clap.workspace = true clap.workspace = true
hex.workspace = true
secp256k1.workspace = true
teepot.workspace = true teepot.workspace = true
zksync_basic_types.workspace = true

View file

@ -3,19 +3,14 @@
//! Tool for SGX attestation and batch signature verification //! Tool for SGX attestation and batch signature verification
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{bail, Context, Result};
use clap::{Args, Parser, Subcommand}; use clap::Parser;
use core::convert::TryInto;
use hex::encode;
use secp256k1::Message;
use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH}; use std::{fs, io::Read, path::PathBuf, str::FromStr, time::UNIX_EPOCH};
use teepot::{ use teepot::{
client::TcbLevel,
ethereum::recover_signer,
prover::reportdata::ReportData,
quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}, quote::{error, tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult},
sgx::TcbLevel,
}; };
use zksync_basic_types::H256;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(author = "Matter Labs", version, about = "SGX attestation and batch signature verifier", long_about = None)] #[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. /// Attestation quote proving the signature originated from a TEE enclave.
#[clap(name = "attestation_file", value_parser)] #[clap(name = "attestation_file", value_parser)]
attestation: ArgSource, attestation: ArgSource,
/// An optional subcommand, for instance, for optional signature verification.
#[clap(subcommand)]
command: Option<SubCommands>,
} }
#[derive(Debug, Clone)] #[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<()> { fn main() -> Result<()> {
let args = Arguments::parse(); let args = Arguments::parse();
let attestation_quote_bytes = match args.attestation { let attestation_quote_bytes = match args.attestation {
@ -75,40 +51,6 @@ fn main() -> Result<()> {
}; };
let quote_verification_result = verify_attestation_quote(&attestation_quote_bytes)?; let quote_verification_result = verify_attestation_quote(&attestation_quote_bytes)?;
print_quote_verification_summary(&quote_verification_result); print_quote_verification_summary(&quote_verification_result);
match &args.command {
Some(SubCommands::SignVerify(signature_args)) => {
verify_signature(&quote_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(()) Ok(())
} }

View file

@ -21,6 +21,6 @@ tokio.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true
url.workspace = true url.workspace = true
zksync_basic_types.workspace = true zksync_basic_types = "=0.1.0"
zksync_types.workspace = true zksync_types = "=0.1.0"
zksync_web3_decl.workspace = true zksync_web3_decl = "=0.1.0"

View file

@ -9,13 +9,13 @@ use secp256k1::{
Message, SECP256K1, Message, SECP256K1,
}; };
use teepot::{ use teepot::{
client::TcbLevel,
ethereum::{public_key_to_ethereum_address, recover_signer}, ethereum::{public_key_to_ethereum_address, recover_signer},
prover::reportdata::ReportData, prover::reportdata::ReportData,
quote::{ quote::{
error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral, error::QuoteContext, tee_qv_get_collateral, verify_quote_with_collateral,
QuoteVerificationResult, Report, QuoteVerificationResult, Report,
}, },
sgx::TcbLevel,
}; };
use tracing::{debug, info, trace, warn}; use tracing::{debug, info, trace, warn};
use zksync_basic_types::{L1BatchNumber, H256}; use zksync_basic_types::{L1BatchNumber, H256};

View file

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

View file

@ -13,6 +13,7 @@ anyhow.workspace = true
clap.workspace = true clap.workspace = true
serde.workspace = true serde.workspace = true
teepot.workspace = true teepot.workspace = true
teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-log.workspace = true tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! Server to handle requests to the Vault TEE
@ -11,14 +11,17 @@ use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; 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::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::{error, trace};
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::Registry; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]

View file

@ -18,6 +18,7 @@ rustls.workspace = true
serde_json.workspace = true serde_json.workspace = true
sha2.workspace = true sha2.workspace = true
teepot.workspace = true teepot.workspace = true
teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-actix-web.workspace = true tracing-actix-web.workspace = true
tracing-log.workspace = true tracing-log.workspace = true

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs // Copyright (c) 2023-2025 Matter Labs
//! post commands //! post commands
@ -9,12 +9,12 @@ use anyhow::{anyhow, Context, Result};
use awc::http::StatusCode; use awc::http::StatusCode;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::sync::Arc; use std::sync::Arc;
use teepot::client::vault::VaultConnection; use teepot_vault::client::vault::VaultConnection;
use teepot::json::http::{ use teepot_vault::json::http::{
VaultCommandRequest, VaultCommandResponse, VaultCommands, VaultCommandsResponse, VaultCommandRequest, VaultCommandResponse, VaultCommands, VaultCommandsResponse,
}; };
use teepot::json::secrets::{AdminConfig, AdminState}; use teepot_vault::json::secrets::{AdminConfig, AdminState};
use teepot::server::{signatures::VerifySig, HttpResponseError, Status}; use teepot_vault::server::{signatures::VerifySig, HttpResponseError, Status};
use tracing::instrument; use tracing::instrument;
/// Post command /// Post command

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs // Copyright (c) 2023-2025 Matter Labs
//! digest //! digest
@ -9,9 +9,9 @@ use anyhow::{Context, Result};
use awc::http::StatusCode; use awc::http::StatusCode;
use serde_json::json; use serde_json::json;
use std::sync::Arc; use std::sync::Arc;
use teepot::client::vault::VaultConnection; use teepot_vault::client::vault::VaultConnection;
use teepot::json::secrets::AdminState; use teepot_vault::json::secrets::AdminState;
use teepot::server::{HttpResponseError, Status}; use teepot_vault::server::{HttpResponseError, Status};
use tracing::instrument; use tracing::instrument;
/// Get last digest /// Get last digest

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! Server to handle requests to the Vault TEE
@ -17,14 +17,14 @@ use digest::get_digest;
use rustls::ServerConfig; use rustls::ServerConfig;
use sign::post_sign; use sign::post_sign;
use std::{net::Ipv6Addr, sync::Arc}; 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}, json::http::{SignRequest, VaultCommandRequest, DIGEST_URL},
server::{ server::{
attestation::{get_quote_and_collateral, VaultAttestationArgs}, attestation::{get_quote_and_collateral, VaultAttestationArgs},
new_json_cfg, new_json_cfg,
pki::make_self_signed_cert, pki::make_self_signed_cert,
}, },
sgx::{parse_tcb_levels, EnumSet, TcbLevel},
}; };
use tracing::{error, info}; use tracing::{error, info};
use tracing_actix_web::TracingLogger; use tracing_actix_web::TracingLogger;
@ -81,6 +81,8 @@ async fn main() -> Result<()> {
info!("Starting HTTPS server at port {}", args.port); info!("Starting HTTPS server at port {}", args.port);
info!("Quote verified! Connection secure!");
let server_state = Arc::new(ServerState { let server_state = Arc::new(ServerState {
report_data, report_data,
vault_attestation: args.attestation, vault_attestation: args.attestation,
@ -116,9 +118,9 @@ async fn main() -> Result<()> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json::json; 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] #[test]
fn test_vault_commands() { fn test_vault_commands() {

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023 Matter Labs // Copyright (c) 2023-2025 Matter Labs
//! post signing request //! post signing request
@ -9,14 +9,14 @@ use actix_web::web;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::sync::Arc; 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::PrivateKey as _;
use teepot::sgx::sign::{Author, Signature}; use teepot::sgx::sign::{Author, Signature};
use teepot::sgx::sign::{Body, RS256PrivateKey}; 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; use tracing::instrument;
/// Sign command /// Sign command

View file

@ -15,6 +15,7 @@ clap.workspace = true
rustls.workspace = true rustls.workspace = true
serde_json.workspace = true serde_json.workspace = true
teepot.workspace = true teepot.workspace = true
teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-log.workspace = true tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023-2024 Matter Labs // Copyright (c) 2023-2025 Matter Labs
use crate::{get_vault_status, UnsealServerState, Worker}; use crate::{get_vault_status, UnsealServerState, Worker};
use actix_web::error::ErrorBadRequest; use actix_web::error::ErrorBadRequest;
@ -7,10 +7,10 @@ use actix_web::{web, HttpResponse};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use awc::http::StatusCode; use awc::http::StatusCode;
use serde_json::json; use serde_json::json;
use teepot::client::TeeConnection; use teepot_vault::client::TeeConnection;
use teepot::json::http::{Init, InitResponse, VaultInitRequest}; use teepot_vault::json::http::{Init, InitResponse, VaultInitRequest};
use teepot::json::secrets::AdminConfig; use teepot_vault::json::secrets::AdminConfig;
use teepot::server::{HttpResponseError, Status}; use teepot_vault::server::{HttpResponseError, Status};
use tracing::{debug, error, info, instrument, trace}; use tracing::{debug, error, info, instrument, trace};
#[instrument(level = "info", name = "/v1/sys/init", skip_all)] #[instrument(level = "info", name = "/v1/sys/init", skip_all)]

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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. //! Server to initialize and unseal the Vault TEE.
@ -15,27 +15,19 @@ use awc::Client;
use clap::Parser; use clap::Parser;
use init::post_init; use init::post_init;
use rustls::ServerConfig; use rustls::ServerConfig;
use std::{ use std::fmt::Debug;
fmt::Debug, use std::io::Read;
io::Read, use std::net::Ipv6Addr;
net::Ipv6Addr, use std::path::PathBuf;
path::PathBuf, use std::sync::{Arc, RwLock};
sync::{Arc, RwLock}, use std::time::Duration;
time::Duration, use teepot::pki::make_self_signed_cert;
}; use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel};
use teepot::{ use teepot_vault::client::{AttestationArgs, TeeConnection};
client::{AttestationArgs, TeeConnection}, use teepot_vault::json::http::{Init, Unseal};
json::{ use teepot_vault::json::secrets::AdminConfig;
http::{Init, Unseal}, use teepot_vault::server::attestation::{get_quote_and_collateral, VaultAttestationArgs};
secrets::AdminConfig, use teepot_vault::server::new_json_cfg;
},
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::{error, info};
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023-2024 Matter Labs // Copyright (c) 2023-2025 Matter Labs
use crate::{get_vault_status, UnsealServerConfig, UnsealServerState, Worker, VAULT_TOKEN_HEADER}; use crate::{get_vault_status, UnsealServerConfig, UnsealServerState, Worker, VAULT_TOKEN_HEADER};
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
@ -12,11 +12,11 @@ use std::fs::File;
use std::future::Future; use std::future::Future;
use std::io::Read; use std::io::Read;
use std::time::Duration; use std::time::Duration;
use teepot::client::vault::VaultConnection; use teepot_vault::client::vault::VaultConnection;
use teepot::client::TeeConnection; use teepot_vault::client::TeeConnection;
use teepot::json::http::Unseal; use teepot_vault::json::http::Unseal;
use teepot::json::secrets::{AdminConfig, AdminState}; use teepot_vault::json::secrets::{AdminConfig, AdminState};
use teepot::server::{HttpResponseError, Status}; use teepot_vault::server::{HttpResponseError, Status};
use tracing::{debug, error, info, instrument, trace}; use tracing::{debug, error, info, instrument, trace};
#[instrument(level = "info", name = "/v1/sys/unseal", skip_all)] #[instrument(level = "info", name = "/v1/sys/unseal", skip_all)]

View file

@ -15,7 +15,7 @@ anyhow.workspace = true
awc.workspace = true awc.workspace = true
clap.workspace = true clap.workspace = true
serde_json.workspace = true serde_json.workspace = true
teepot.workspace = true teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-log.workspace = true tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! 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::collections::HashMap;
use std::os::unix::process::CommandExt; use std::os::unix::process::CommandExt;
use std::process::Command; use std::process::Command;
use teepot::client::vault::VaultConnection; use teepot_vault::client::vault::VaultConnection;
use teepot::server::attestation::VaultAttestationArgs; use teepot_vault::server::attestation::VaultAttestationArgs;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};

View file

@ -15,7 +15,7 @@ anyhow.workspace = true
awc.workspace = true awc.workspace = true
clap.workspace = true clap.workspace = true
serde_json.workspace = true serde_json.workspace = true
teepot.workspace = true teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-log.workspace = true tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! Write secrets to a Vault TEE from environment variables
@ -9,10 +9,8 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap; use std::{collections::HashMap, env};
use std::env; use teepot_vault::{client::vault::VaultConnection, server::attestation::VaultAttestationArgs};
use teepot::client::vault::VaultConnection;
use teepot::server::attestation::VaultAttestationArgs;
use tracing::{debug, info, warn}; use tracing::{debug, info, warn};
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};

View file

@ -16,4 +16,5 @@ hex.workspace = true
pgp.workspace = true pgp.workspace = true
serde_json.workspace = true serde_json.workspace = true
teepot.workspace = true teepot.workspace = true
teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true

View file

@ -13,8 +13,8 @@ Verified signature for `81A312C59D679D930FA9E8B06D728F29A2DBABF8`
--sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \
--sgx-allowed-tcb-levels SwHardeningNeeded \ --sgx-allowed-tcb-levels SwHardeningNeeded \
--server https://127.0.0.1:8444 \ --server https://127.0.0.1:8444 \
bin/tee-vault-admin/tests/data/test.json \ crates/teepot-vault/tests/data/test.json \
bin/tee-vault-admin/tests/data/test.json.asc 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.919941Z INFO vault_admin: Quote verified! Connection secure!
2023-08-04T10:51:14.920430Z INFO tee_client: Getting attestation report 2023-08-04T10:51:14.920430Z INFO tee_client: Getting attestation report

View file

@ -12,16 +12,18 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use teepot::{ use teepot::{
log::{setup_logging, LogLevelParser},
sgx::sign::Signature,
};
use teepot_vault::{
client::{AttestationArgs, TeeConnection}, client::{AttestationArgs, TeeConnection},
json::http::{ json::http::{
SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands, SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands,
VaultCommandsResponse, DIGEST_URL, VaultCommandsResponse, DIGEST_URL,
}, },
log::{setup_logging, LogLevelParser},
server::signatures::verify_sig, server::signatures::verify_sig,
sgx::sign::Signature,
}; };
use tracing::{error, info, level_filters::LevelFilter}; use tracing::{error, level_filters::LevelFilter};
#[derive(Args, Debug)] #[derive(Args, Debug)]
struct SendArgs { struct SendArgs {

View file

@ -13,7 +13,7 @@ anyhow.workspace = true
base64.workspace = true base64.workspace = true
clap.workspace = true clap.workspace = true
serde_json.workspace = true serde_json.workspace = true
teepot.workspace = true teepot-vault.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-log.workspace = true tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true

View file

@ -1,18 +1,18 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023-2024 Matter Labs // Copyright (c) 2023-2025 Matter Labs
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use base64::{engine::general_purpose, Engine as _}; use base64::{engine::general_purpose, Engine as _};
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use serde_json::Value; use serde_json::Value;
use std::fs::File; use std::{fs::File, io::Read};
use std::io::Read; use teepot_vault::{
use teepot::client::{AttestationArgs, TeeConnection}; client::{AttestationArgs, TeeConnection},
use teepot::json::http::{Init, InitResponse, Unseal}; json::http::{Init, InitResponse, Unseal},
};
use tracing::{error, info, trace, warn}; use tracing::{error, info, trace, warn};
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::Registry; use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[derive(Args, Debug)] #[derive(Args, Debug)]
pub struct InitArgs { pub struct InitArgs {

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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. //! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs.
@ -8,15 +8,7 @@
pub mod vault; pub mod vault;
use crate::{ use crate::server::pki::{RaTlsCollateralExtension, RaTlsQuoteExtension};
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 actix_web::http::header;
use anyhow::Result; use anyhow::Result;
use awc::{Client, Connector}; use awc::{Client, Connector};
@ -33,6 +25,11 @@ use rustls::{
}; };
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{sync::Arc, time, time::Duration}; 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 tracing::{debug, error, info, trace, warn};
use x509_cert::{ use x509_cert::{
der::{Decode as _, Encode as _}, der::{Decode as _, Encode as _},

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // 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. //! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs.
@ -9,15 +9,8 @@
use super::{AttestationArgs, TeeConnection}; use super::{AttestationArgs, TeeConnection};
use crate::{ use crate::{
json::http::{AuthRequest, AuthResponse}, json::http::{AuthRequest, AuthResponse},
quote::error::QuoteContext,
server::{pki::make_self_signed_cert, AnyHowResponseError, HttpResponseError, Status}, 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_http::error::PayloadError;
use actix_web::{http::header, ResponseError}; use actix_web::{http::header, ResponseError};
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
@ -35,6 +28,13 @@ use std::{
sync::Arc, sync::Arc,
time, 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}; use tracing::{debug, error, info, trace};
const VAULT_TOKEN_HEADER: &str = "X-Vault-Token"; const VAULT_TOKEN_HEADER: &str = "X-Vault-Token";

View file

@ -1,15 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! Common types for the teepot http JSON API
use crate::sgx::Collateral;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use serde_with::base64::Base64; use serde_with::{base64::Base64, serde_as};
use serde_with::serde_as;
use std::fmt::Display; use std::fmt::Display;
use std::sync::Arc;
/// The unseal request data /// The unseal request data
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -23,15 +20,6 @@ impl Unseal {
pub const URL: &'static str = "/v1/sys/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<Collateral>,
}
/// The init request data /// The init request data
#[serde_as] #[serde_as]
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]

View file

@ -1,12 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // 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 //! Common types for the teepot secrets JSON API
use crate::sgx::sign::Zeroizing;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::base64::Base64; use serde_with::base64::Base64;
use serde_with::serde_as; use serde_with::serde_as;
use teepot::sgx::sign::Zeroizing;
/// Configuration for the admin tee /// Configuration for the admin tee
#[serde_as] #[serde_as]

View file

@ -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<const T: usize>(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
}

View file

@ -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<String>,
/// hex encoded SGX mrenclave of the enclave to attest
#[arg(long, env = "VAULT_SGX_MRENCLAVE")]
pub vault_sgx_mrenclave: Option<String>,
/// 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<EnumSet<TcbLevel>>,
}
impl From<VaultAttestationArgs> 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,
}
}
}

View file

@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023-2024 Matter Labs // Copyright (c) 2023-2025 Matter Labs
//! # tee-server //! # tee-server
@ -7,18 +7,19 @@
#![deny(clippy::all)] #![deny(clippy::all)]
pub mod attestation; pub mod attestation;
pub mod pki;
pub mod signatures; pub mod signatures;
use actix_web::http::StatusCode; use actix_web::{
use actix_web::web::Bytes; error, http::StatusCode, web::Bytes, HttpMessage, HttpRequest, HttpResponse, ResponseError,
use actix_web::{error, HttpRequest, HttpResponse}; };
use actix_web::{HttpMessage, ResponseError};
use anyhow::anyhow; use anyhow::anyhow;
use awc::error::{PayloadError, SendRequestError}; use awc::{
use awc::ClientResponse; error::{PayloadError, SendRequestError},
ClientResponse,
};
use futures_core::Stream; use futures_core::Stream;
use std::fmt::{Debug, Display, Formatter}; use std::fmt::{Debug, Display, Formatter};
pub use teepot::pki;
use tracing::error; use tracing::error;
/// Anyhow error with an HTTP status code /// Anyhow error with an HTTP status code

View file

@ -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<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())
}
}

View file

@ -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<u8>,
}
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<u8> = 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<TdxRtmrEvent> for Vec<u8> {
fn from(val: TdxRtmrEvent) -> Self {
let event_ptr = &val as *const TdxRtmrEvent as *const u8;
let event_data_size = std::mem::size_of::<u8>() * val.event_data_size as usize;
let res_size = std::mem::size_of::<u32>() * 3
+ std::mem::size_of::<u64>()
+ 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
}
}

View file

@ -1,6 +1,6 @@
[package] [package]
name = "teepot" name = "teepot"
description = "TEE secret manager" description = "TEE utilities"
# no MIT license, because of copied code from: # no MIT license, because of copied code from:
# * https://github.com/enarx/enarx # * https://github.com/enarx/enarx
# * https://github.com/enarx/sgx # * https://github.com/enarx/sgx
@ -11,18 +11,13 @@ authors.workspace = true
repository.workspace = true repository.workspace = true
[dependencies] [dependencies]
actix-http.workspace = true
actix-web.workspace = true
anyhow.workspace = true anyhow.workspace = true
async-trait.workspace = true async-trait.workspace = true
awc.workspace = true
bytemuck.workspace = true bytemuck.workspace = true
bytes.workspace = true
clap.workspace = true clap.workspace = true
config.workspace = true config.workspace = true
const-oid.workspace = true const-oid.workspace = true
enumset.workspace = true enumset.workspace = true
futures-core.workspace = true
getrandom.workspace = true getrandom.workspace = true
hex.workspace = true hex.workspace = true
intel-tee-quote-verification-rs.workspace = true intel-tee-quote-verification-rs.workspace = true
@ -34,7 +29,6 @@ opentelemetry-otlp.workspace = true
opentelemetry-semantic-conventions.workspace = true opentelemetry-semantic-conventions.workspace = true
opentelemetry_sdk.workspace = true opentelemetry_sdk.workspace = true
p256.workspace = true p256.workspace = true
pgp.workspace = true
pkcs8.workspace = true pkcs8.workspace = true
reqwest.workspace = true reqwest.workspace = true
rsa.workspace = true rsa.workspace = true
@ -42,7 +36,6 @@ rustls.workspace = true
secp256k1 = { workspace = true, features = ["recovery"] } secp256k1 = { workspace = true, features = ["recovery"] }
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
serde_with.workspace = true
sha2.workspace = true sha2.workspace = true
sha3.workspace = true sha3.workspace = true
signature.workspace = true signature.workspace = true
@ -52,7 +45,6 @@ tracing.workspace = true
tracing-futures.workspace = true tracing-futures.workspace = true
tracing-log.workspace = true tracing-log.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true
webpki-roots.workspace = true
x509-cert.workspace = true x509-cert.workspace = true
zeroize.workspace = true zeroize.workspace = true
@ -61,4 +53,3 @@ base64.workspace = true
testaso.workspace = true testaso.workspace = true
tokio.workspace = true tokio.workspace = true
tracing-test.workspace = true tracing-test.workspace = true
zksync_basic_types.workspace = true

View file

@ -37,7 +37,6 @@ pub fn public_key_to_ethereum_address(public: &PublicKey) -> [u8; 20] {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use secp256k1::{Secp256k1, SecretKey}; use secp256k1::{Secp256k1, SecretKey};
use zksync_basic_types::H256;
use super::*; use super::*;
@ -71,10 +70,10 @@ mod tests {
assert_eq!(address, expected_address.as_slice()); 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 // the secret key
let root_hash = H256::random(); let root_hash = b"12345678901234567890123456789012";
let root_hash_bytes = root_hash.as_bytes(); let root_hash_bytes = root_hash.as_slice();
let msg_to_sign = Message::from_digest(root_hash_bytes.try_into().unwrap()); let msg_to_sign = Message::from_digest(root_hash_bytes.try_into().unwrap());
let signature = sign_message(&secret_key, msg_to_sign).unwrap(); let signature = sign_message(&secret_key, msg_to_sign).unwrap();

View file

@ -6,14 +6,12 @@
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(clippy::all)] #![deny(clippy::all)]
pub mod client;
pub mod config; pub mod config;
pub mod ethereum; pub mod ethereum;
pub mod json;
pub mod log; pub mod log;
pub mod pki;
pub mod prover; pub mod prover;
pub mod quote; pub mod quote;
pub mod server;
pub mod sgx; pub mod sgx;
pub mod tdx; pub mod tdx;

View file

@ -1,18 +1,15 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2023-2024 Matter Labs // Copyright (c) 2023-2025 Matter Labs
//! Common attestation API for all TEEs //! Common attestation API for all TEEs
use crate::{ use crate::{
client::AttestationArgs,
json::http::AttestationResponse,
quote::{ quote::{
error::QuoteContext, get_quote, verify_quote_with_collateral, QuoteVerificationResult, 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 anyhow::{bail, Context, Result};
use clap::Args;
use intel_tee_quote_verification_rs::tee_qv_get_collateral; use intel_tee_quote_verification_rs::tee_qv_get_collateral;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
@ -28,6 +25,15 @@ struct Attestation {
earliest_expiration_date: i64, 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<Collateral>,
}
/// Returns the quote and collateral for the current TEE. /// Returns the quote and collateral for the current TEE.
/// ///
/// if `allowed_tcb_levels` is `None`, then any TCB level is accepted. /// 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 }) 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<String>,
/// hex encoded SGX mrenclave of the enclave to attest
#[arg(long, env = "VAULT_SGX_MRENCLAVE")]
pub vault_sgx_mrenclave: Option<String>,
/// 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<EnumSet<TcbLevel>>,
}
impl From<VaultAttestationArgs> 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,
}
}
}

View file

@ -1,10 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // 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 // Parts of it are Copyright (c) 2024 Phala Network
// and copied from https://github.com/Phala-Network/dcap-qvl // and copied from https://github.com/Phala-Network/dcap-qvl
//! Get a quote from a TEE //! Get a quote from a TEE
pub mod attestation;
pub mod error; pub mod error;
use crate::{ use crate::{

View file

@ -11,13 +11,13 @@ $ docker compose up
```bash ```bash
cd teepot cd teepot
gpg --export username@example.com | base64 > gpgkey.pub gpg --export username@example.com | base64 > assets/gpgkey.pub
export GPG_TTY="$(tty)" export GPG_TTY="$(tty)"
gpg-connect-agent updatestartuptty /bye 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 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: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.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 2023-08-23T14:47:57.741599Z INFO tee_client: Verifying attestation report
@ -155,9 +155,9 @@ container.
--server https://127.0.0.1:8443 \ --server https://127.0.0.1:8443 \
init \ init \
--unseal-threshold 1 \ --unseal-threshold 1 \
--unseal-pgp-key-file ./tests/data/gpgkey.pub \ --unseal-pgp-key-file ./assets/gpgkey.pub \
--admin-threshold 1 \ --admin-threshold 1 \
--admin-pgp-key-file ./tests/data/gpgkey.pub \ --admin-pgp-key-file ./assets/gpgkey.pub \
--admin-tee-mrenclave 98a540dd7056584e2009c7cf7374f932fbb8e30a4c66cc815c9809620653f751 --admin-tee-mrenclave 98a540dd7056584e2009c7cf7374f932fbb8e30a4c66cc815c9809620653f751
``` ```

View file

@ -37,11 +37,12 @@ let
fileset = unions [ fileset = unions [
# Default files from crane (Rust and cargo files) # Default files from crane (Rust and cargo files)
(craneLib.fileset.commonCargoSources inputs.src) (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 # deny.toml and friends
(fileFilter (file: file.hasExt "toml") inputs.src) (fileFilter (file: file.hasExt "toml") inputs.src)
# Custom test data files # Custom test data files
(maybeMissing (inputs.src + "/crates/teepot/tests/data")) (maybeMissing (inputs.src + "/crates/teepot/tests/data"))
(maybeMissing (inputs.src + "/crates/teepot-vault/tests/data"))
]; ];
}; };