Merge pull request #323 from matter-labs/intel-dcap-api-impr

feat(intel-dcap-api): add automatic retry logic for 429 rate limiting
This commit is contained in:
Harald Hoyer 2025-05-30 08:41:24 +02:00 committed by GitHub
commit 37e7f7f8e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 4294 additions and 15 deletions

View file

@ -34,5 +34,5 @@ jobs:
# FIXME: this prevents it from running on macos # FIXME: this prevents it from running on macos
# https://github.com/NixOS/nix/pull/12570 # https://github.com/NixOS/nix/pull/12570
# run: nix run github:nixos/nixpkgs/nixos-24.11#nixci -- build # run: nix run github:nixos/nixpkgs/nixos-24.11#nixci -- build
run: nix build -L .#teepot run: nix build -L .#teepot --no-sandbox

51
Cargo.lock generated
View file

@ -372,6 +372,16 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247"
[[package]]
name = "assert-json-diff"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.6" version = "0.3.6"
@ -1000,6 +1010,15 @@ dependencies = [
"x509-cert", "x509-cert",
] ]
[[package]]
name = "colored"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.7" version = "4.6.7"
@ -2607,7 +2626,9 @@ dependencies = [
name = "intel-dcap-api" name = "intel-dcap-api"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"base64",
"hex", "hex",
"mockito",
"percent-encoding", "percent-encoding",
"reqwest", "reqwest",
"serde", "serde",
@ -3044,6 +3065,30 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "mockito"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7760e0e418d9b7e5777c0374009ca4c93861b9066f18cb334a20ce50ab63aa48"
dependencies = [
"assert-json-diff",
"bytes",
"colored",
"futures-util",
"http 1.2.0",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"log",
"rand 0.9.0",
"regex",
"serde_json",
"serde_urlencoded",
"similar",
"tokio",
]
[[package]] [[package]]
name = "mutually_exclusive_features" name = "mutually_exclusive_features"
version = "0.1.0" version = "0.1.0"
@ -4616,6 +4661,12 @@ dependencies = [
"rand_core 0.6.4", "rand_core 0.6.4",
] ]
[[package]]
name = "similar"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
[[package]] [[package]]
name = "simple-bytes" name = "simple-bytes"
version = "0.2.14" version = "0.2.14"

View file

@ -0,0 +1,143 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
This crate (`intel-dcap-api`) is a Rust client library for Intel's Data Center Attestation Primitives (DCAP) API. It
provides access to Intel's Trusted Services API for SGX and TDX attestation, including TCB info, PCK certificates, CRLs,
and enclave identity verification.
## Features
- Support for both API v3 and v4
- Async/await API using tokio
- Comprehensive error handling with Intel-specific error codes
- Type-safe request/response structures
- Support for SGX and TDX platforms
- Real data integration tests
- **Automatic rate limit handling with configurable retries**
## Development Commands
```bash
# Build
cargo build
cargo build --no-default-features --features rustls # Use rustls instead of default TLS
# Test
cargo test
# Lint
cargo clippy
# Examples
cargo run --example example # Basic usage example
cargo run --example get_pck_crl # Fetch certificate revocation lists
cargo run --example common_usage # Common attestation verification patterns
cargo run --example integration_test # Comprehensive test of most API endpoints
cargo run --example fetch_test_data # Fetch real data from Intel API for tests
cargo run --example handle_rate_limit # Demonstrate automatic rate limiting handling
```
## Architecture
### Client Structure
- **ApiClient** (`src/client/mod.rs`): Main entry point supporting API v3/v4
- Base URL: https://api.trustedservices.intel.com
- Manages HTTP client and API version selection
- Automatic retry logic for 429 (Too Many Requests) responses
- Default: 3 retries, configurable via `set_max_retries()`
### Key Modules
- **client/**: API endpoint implementations
- `tcb_info`: SGX/TDX TCB information retrieval
- `get_sgx_tcb_info()`, `get_tdx_tcb_info()`
- `pck_cert`: PCK certificate operations
- `get_pck_certificate_by_ppid()`, `get_pck_certificate_by_manifest()`
- `get_pck_certificates_by_ppid()`, `get_pck_certificates_by_manifest()`
- `get_pck_certificates_config_by_ppid()`, `get_pck_certificates_config_by_manifest()`
- `pck_crl`: Certificate revocation lists
- `get_pck_crl()` - supports PEM and DER encoding
- `enclave_identity`: SGX QE/QVE/QAE/TDQE identity
- `get_sgx_qe_identity()`, `get_sgx_qve_identity()`, `get_sgx_qae_identity()`, `get_tdx_qe_identity()`
- `fmspc`: FMSPC-related operations (V4 only)
- `get_fmspcs()` - with optional platform filter
- `get_sgx_tcb_evaluation_data_numbers()`, `get_tdx_tcb_evaluation_data_numbers()`
- `registration`: Platform registration
- `register_platform()`, `add_package()`
### Core Types
- **error.rs**: `IntelApiError` for comprehensive error handling
- Extracts error details from Error-Code and Error-Message headers
- **`TooManyRequests` variant for rate limiting (429) after retry exhaustion**
- **types.rs**: Enums (CaType, ApiVersion, UpdateType, etc.)
- **requests.rs**: Request structures
- **responses.rs**: Response structures with JSON and certificate data
### API Pattern
All client methods follow this pattern:
1. Build request with query parameters
2. Send HTTP request with proper headers (with automatic retry on 429)
3. Parse response (JSON + certificate chains)
4. Return typed response or error
### Rate Limiting & Retry Logic
- **Automatic Retries**: All HTTP requests automatically retry on 429 (Too Many Requests) responses
- **Retry Configuration**: Default 3 retries, configurable via `ApiClient::set_max_retries()`
- **Retry-After Handling**: Waits for duration specified in Retry-After header before retrying
- **Error Handling**: `IntelApiError::TooManyRequests` returned only after all retries exhausted
- **Implementation**: `execute_with_retry()` in `src/client/helpers.rs` handles retry logic
### Testing Strategy
- **Mock Tests**: Two test suites using mockito for HTTP mocking
- `tests/mock_api_tests.rs`: Basic API functionality tests with simple data (11 tests)
- `tests/real_data_mock_tests.rs`: Tests using real Intel API responses (25 tests)
- **Test Data**: Real responses stored in `tests/test_data/` (JSON format)
- Fetched using `cargo run --example fetch_test_data`
- Includes TCB info, CRLs, enclave identities for both SGX and TDX
- Covers V3 and V4 API variations, different update types, and evaluation data numbers
- **Key Testing Considerations**:
- Headers with newlines must be URL-encoded for mockito (use `percent_encode` with `NON_ALPHANUMERIC`)
- V3 vs V4 API use different header names:
- V3: `SGX-TCB-Info-Issuer-Chain`
- V4: `TCB-Info-Issuer-Chain`
- Error responses include Error-Code and Error-Message headers
- Examples use real Intel API endpoints
- Test data (FMSPC, PPID) from Intel documentation
- Async tests require tokio runtime
## API Version Differences
### V4-Only Features
- FMSPC listing (`get_fmspcs()`)
- TCB Evaluation Data Numbers endpoints
- PPID encryption key type parameter
- TDX QE identity endpoint
## Common Pitfalls
1. **Mockito Header Encoding**: Always URL-encode headers containing newlines/special characters
2. **API Version Selection**: Some endpoints are V4-only and will return errors on V3
3. **Rate Limiting**: Client automatically retries 429 responses; disable with `set_max_retries(0)` if manual handling
needed
4. **Platform Filters**: Only certain values are valid (All, Client, E3, E5)
5. **Test Data**: PCK certificate endpoints require valid platform data and often need subscription keys
6. **Issuer Chain Validation**: Always check that `issuer_chain` is non-empty - it's critical for signature verification
## Security Considerations
- **Certificate Chain Verification**: The `issuer_chain` field contains the certificates needed to verify the signature
of the response data
- **Signature Validation**: All JSON responses (TCB info, enclave identities) should have their signatures verified
using the issuer chain
- **CRL Verification**: PCK CRLs must be signature-verified before being used for certificate revocation checking
- **Empty Issuer Chains**: Always validate that issuer chains are present and non-empty before trusting response data

View file

@ -11,6 +11,7 @@ keywords = ["sgx", "tdx", "intel", "attestation", "confidential"]
categories = ["api-bindings", "cryptography", "authentication"] categories = ["api-bindings", "cryptography", "authentication"]
[dependencies] [dependencies]
base64.workspace = true
percent-encoding = "2.3.1" percent-encoding = "2.3.1"
reqwest = { workspace = true, features = ["json"] } reqwest = { workspace = true, features = ["json"] }
serde.workspace = true serde.workspace = true
@ -20,9 +21,15 @@ tokio.workspace = true
url.workspace = true url.workspace = true
[dev-dependencies] [dev-dependencies]
base64.workspace = true
hex.workspace = true hex.workspace = true
mockito = "1.4"
x509-cert.workspace = true x509-cert.workspace = true
[[example]]
name = "integration_test"
required-features = ["default"]
[features] [features]
default = ["reqwest/default-tls"] default = ["reqwest/default-tls"]
rustls = ["reqwest/rustls-tls"] rustls = ["reqwest/rustls-tls"]

View file

@ -0,0 +1,182 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use intel_dcap_api::{ApiClient, CaType, IntelApiError, UpdateType};
/// Common usage patterns for the Intel DCAP API client
///
/// This example demonstrates typical use cases for attestation verification.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a client (defaults to V4 API)
let client = ApiClient::new()?;
// Example 1: Get TCB info for quote verification
println!("Example 1: Getting TCB info for SGX quote verification");
println!("======================================================");
let fmspc = "00906ED50000"; // From SGX quote
match client.get_sgx_tcb_info(fmspc, None, None).await {
Ok(response) => {
// Critical: Check that issuer chain is present for signature verification
if response.issuer_chain.is_empty() {
println!("✗ Error: Empty issuer chain - cannot verify TCB info signature!");
return Ok(());
}
println!("✓ Retrieved TCB info for FMSPC: {}", fmspc);
// Parse the TCB info
let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?;
// Extract useful information
if let Some(tcb_levels) = tcb_info["tcbInfo"]["tcbLevels"].as_array() {
println!(" Found {} TCB levels", tcb_levels.len());
// Show the latest TCB level
if let Some(latest) = tcb_levels.first() {
println!(" Latest TCB level:");
if let Some(status) = latest["tcbStatus"].as_str() {
println!(" Status: {}", status);
}
if let Some(date) = latest["tcbDate"].as_str() {
println!(" Date: {}", date);
}
}
}
// The issuer chain is needed to verify the signature
println!(
" Issuer chain length: {} bytes",
response.issuer_chain.len()
);
// Verify we have certificate chain for signature verification
let cert_count = response.issuer_chain.matches("BEGIN CERTIFICATE").count();
println!(" Certificate chain contains {} certificates", cert_count);
}
Err(IntelApiError::ApiError {
status,
error_message,
..
}) => {
println!(
"✗ API Error {}: {}",
status,
error_message.unwrap_or_default()
);
}
Err(e) => {
println!("✗ Error: {:?}", e);
}
}
println!();
// Example 2: Get QE identity for enclave verification
println!("Example 2: Getting QE identity for enclave verification");
println!("======================================================");
match client.get_sgx_qe_identity(None, None).await {
Ok(response) => {
// Critical: Check that issuer chain is present for signature verification
if response.issuer_chain.is_empty() {
println!("✗ Error: Empty issuer chain - cannot verify QE identity signature!");
return Ok(());
}
println!("✓ Retrieved QE identity");
println!(
" Issuer chain length: {} bytes",
response.issuer_chain.len()
);
let identity: serde_json::Value =
serde_json::from_str(&response.enclave_identity_json)?;
if let Some(enclave_id) = identity["enclaveIdentity"]["id"].as_str() {
println!(" Enclave ID: {}", enclave_id);
}
if let Some(version) = identity["enclaveIdentity"]["version"].as_u64() {
println!(" Version: {}", version);
}
if let Some(mrsigner) = identity["enclaveIdentity"]["mrsigner"].as_str() {
println!(" MRSIGNER: {}...", &mrsigner[..16]);
}
}
Err(e) => {
println!("✗ Failed to get QE identity: {:?}", e);
}
}
println!();
// Example 3: Check certificate revocation
println!("Example 3: Checking certificate revocation status");
println!("================================================");
match client.get_pck_crl(CaType::Processor, None).await {
Ok(response) => {
// Critical: Check that issuer chain is present for CRL verification
if response.issuer_chain.is_empty() {
println!("✗ Error: Empty issuer chain - cannot verify CRL signature!");
return Ok(());
}
println!("✓ Retrieved PCK CRL");
println!(
" Issuer chain length: {} bytes",
response.issuer_chain.len()
);
let crl_pem = String::from_utf8_lossy(&response.crl_data);
// In real usage, you would parse this CRL and check if a certificate is revoked
if crl_pem.contains("BEGIN X509 CRL") {
println!(" CRL format: PEM");
println!(" CRL size: {} bytes", crl_pem.len());
// Count the revoked certificates (naive approach)
let revoked_count = crl_pem.matches("Serial Number:").count();
println!(" Approximate revoked certificates: {}", revoked_count);
}
}
Err(e) => {
println!("✗ Failed to get CRL: {:?}", e);
}
}
println!();
// Example 4: Early update for testing
println!("Example 4: Getting early TCB update (for testing)");
println!("================================================");
match client
.get_sgx_tcb_info(fmspc, Some(UpdateType::Early), None)
.await
{
Ok(response) => {
println!("✓ Retrieved early TCB update");
let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?;
if let Some(next_update) = tcb_info["tcbInfo"]["nextUpdate"].as_str() {
println!(" Next update: {}", next_update);
}
}
Err(IntelApiError::ApiError { status, .. }) if status.as_u16() == 404 => {
println!(" No early update available (this is normal)");
}
Err(e) => {
println!("✗ Error: {:?}", e);
}
}
println!();
println!("Done! These examples show common patterns for attestation verification.");
Ok(())
}

View file

@ -0,0 +1,515 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use base64::{engine::general_purpose, Engine as _};
use intel_dcap_api::{ApiClient, ApiVersion, CaType, CrlEncoding, PlatformFilter, UpdateType};
use std::{fs, path::Path};
/// Fetch real data from Intel API and save it as JSON files
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create test data directory
let test_data_dir = Path::new("tests/test_data");
fs::create_dir_all(test_data_dir)?;
let client = ApiClient::new()?;
println!("Fetching real test data from Intel API...");
// Keep track of successful fetches
let mut successes: Vec<String> = Vec::new();
let mut failures: Vec<String> = Vec::new();
// 1. Fetch SGX TCB info
println!("\n1. Fetching SGX TCB info...");
match client
.get_sgx_tcb_info("00606A6A0000", Some(UpdateType::Standard), None)
.await
{
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_tcb_info.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX TCB info".to_string());
}
Err(e) => {
failures.push(format!("SGX TCB info: {}", e));
}
}
// 2. Fetch TDX TCB info
println!("\n2. Fetching TDX TCB info...");
match client
.get_tdx_tcb_info("00806F050000", Some(UpdateType::Standard), None)
.await
{
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("tdx_tcb_info.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("TDX TCB info".to_string());
}
Err(e) => {
failures.push(format!("TDX TCB info: {}", e));
}
}
// 3. Fetch PCK CRL for processor
println!("\n3. Fetching PCK CRL (processor)...");
match client.get_pck_crl(CaType::Processor, None).await {
Ok(response) => {
let crl_string = String::from_utf8_lossy(&response.crl_data);
let data = serde_json::json!({
"crl_data": crl_string,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("pck_crl_processor.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("PCK CRL (processor)".to_string());
}
Err(e) => {
failures.push(format!("PCK CRL (processor): {}", e));
}
}
// 4. Fetch PCK CRL for platform
println!("\n4. Fetching PCK CRL (platform)...");
match client.get_pck_crl(CaType::Platform, None).await {
Ok(response) => {
let crl_string = String::from_utf8_lossy(&response.crl_data);
let data = serde_json::json!({
"crl_data": crl_string,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("pck_crl_platform.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("PCK CRL (platform)".to_string());
}
Err(e) => {
failures.push(format!("PCK CRL (platform): {}", e));
}
}
// 5. Fetch SGX QE identity
println!("\n5. Fetching SGX QE identity...");
match client.get_sgx_qe_identity(None, None).await {
Ok(response) => {
let data = serde_json::json!({
"enclave_identity_json": response.enclave_identity_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_qe_identity.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX QE identity".to_string());
}
Err(e) => {
failures.push(format!("SGX QE identity: {}", e));
}
}
// 6. Fetch SGX QVE identity
println!("\n6. Fetching SGX QVE identity...");
match client.get_sgx_qve_identity(None, None).await {
Ok(response) => {
let data = serde_json::json!({
"enclave_identity_json": response.enclave_identity_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_qve_identity.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX QVE identity".to_string());
}
Err(e) => {
failures.push(format!("SGX QVE identity: {}", e));
}
}
// 7. Fetch TDX QE identity
println!("\n7. Fetching TDX QE identity...");
match client.get_tdx_qe_identity(None, None).await {
Ok(response) => {
let data = serde_json::json!({
"enclave_identity_json": response.enclave_identity_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("tdx_qe_identity.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("TDX QE identity".to_string());
}
Err(e) => {
failures.push(format!("TDX QE identity: {}", e));
}
}
// 8. Try an alternative FMSPC
println!("\n8. Fetching alternative SGX TCB info...");
match client.get_sgx_tcb_info("00906ED50000", None, None).await {
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_tcb_info_alt.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("Alternative SGX TCB info".to_string());
}
Err(e) => {
failures.push(format!("Alternative SGX TCB info: {}", e));
}
}
// 9. Fetch PCK certificate
println!("\n9. Attempting to fetch PCK certificate...");
let ppid = "3d6dd97e96f84536a2267e727dd860e4fdd3ffa3e319db41e8f69c9a43399e7b7ce97d7eb3bd05b0a58bdb5b90a0e218";
let cpusvn = "0606060606060606060606060606060606060606060606060606060606060606";
let pcesvn = "0a00";
let pceid = "0000";
match client
.get_pck_certificate_by_ppid(ppid, cpusvn, pcesvn, pceid, None, None)
.await
{
Ok(response) => {
let data = serde_json::json!({
"pck_cert_pem": response.pck_cert_pem,
"issuer_chain": response.issuer_chain,
"tcbm": response.tcbm,
"fmspc": response.fmspc,
});
fs::write(
test_data_dir.join("pck_cert.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("PCK certificate".to_string());
}
Err(e) => {
failures.push(format!("PCK certificate: {}", e));
}
}
// 10. Fetch SGX QAE identity
println!("\n10. Fetching SGX QAE identity...");
match client.get_sgx_qae_identity(None, None).await {
Ok(response) => {
let data = serde_json::json!({
"enclave_identity_json": response.enclave_identity_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_qae_identity.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX QAE identity".to_string());
}
Err(e) => {
failures.push(format!("SGX QAE identity: {}", e));
}
}
// 11. Fetch FMSPCs
println!("\n11. Fetching FMSPCs...");
match client.get_fmspcs(Some(PlatformFilter::All)).await {
Ok(fmspcs_json) => {
let data = serde_json::json!({
"fmspcs_json": fmspcs_json,
});
fs::write(
test_data_dir.join("fmspcs.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("FMSPCs".to_string());
}
Err(e) => {
failures.push(format!("FMSPCs: {}", e));
}
}
// 12. Fetch SGX TCB evaluation data numbers
println!("\n12. Fetching SGX TCB evaluation data numbers...");
match client.get_sgx_tcb_evaluation_data_numbers().await {
Ok(response) => {
let data = serde_json::json!({
"tcb_evaluation_data_numbers_json": response.tcb_evaluation_data_numbers_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_tcb_eval_nums.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX TCB evaluation data numbers".to_string());
}
Err(e) => {
failures.push(format!("SGX TCB evaluation data numbers: {}", e));
}
}
// 13. Fetch TDX TCB evaluation data numbers
println!("\n13. Fetching TDX TCB evaluation data numbers...");
match client.get_tdx_tcb_evaluation_data_numbers().await {
Ok(response) => {
let data = serde_json::json!({
"tcb_evaluation_data_numbers_json": response.tcb_evaluation_data_numbers_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("tdx_tcb_eval_nums.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("TDX TCB evaluation data numbers".to_string());
}
Err(e) => {
failures.push(format!("TDX TCB evaluation data numbers: {}", e));
}
}
// 14. Fetch PCK CRL with DER encoding
println!("\n14. Fetching PCK CRL (processor, DER encoding)...");
match client
.get_pck_crl(CaType::Processor, Some(CrlEncoding::Der))
.await
{
Ok(response) => {
// For DER, save as base64
let crl_base64 = general_purpose::STANDARD.encode(&response.crl_data);
let data = serde_json::json!({
"crl_data_base64": crl_base64,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("pck_crl_processor_der.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("PCK CRL (processor, DER)".to_string());
}
Err(e) => {
failures.push(format!("PCK CRL (processor, DER): {}", e));
}
}
// 15. Try different update types
println!("\n15. Fetching SGX TCB info with Early update...");
match client
.get_sgx_tcb_info("00906ED50000", Some(UpdateType::Early), None)
.await
{
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_tcb_info_early.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX TCB info (Early update)".to_string());
}
Err(e) => {
failures.push(format!("SGX TCB info (Early update): {}", e));
}
}
// 16. Try with specific TCB evaluation data number
println!("\n16. Fetching TDX TCB info with specific evaluation number...");
match client
.get_tdx_tcb_info("00806F050000", None, Some(17))
.await
{
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("tdx_tcb_info_eval17.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("TDX TCB info (eval number 17)".to_string());
}
Err(e) => {
failures.push(format!("TDX TCB info (eval number 17): {}", e));
}
}
// 17. Try different FMSPCs
println!("\n17. Fetching more SGX TCB info variations...");
let test_fmspcs = vec!["00906ED50000", "00906C0F0000", "00A06F050000"];
for fmspc in test_fmspcs {
match client.get_sgx_tcb_info(fmspc, None, None).await {
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join(format!("sgx_tcb_info_{}.json", fmspc)),
serde_json::to_string_pretty(&data)?,
)?;
successes.push(format!("SGX TCB info (FMSPC: {})", fmspc));
}
Err(e) => {
failures.push(format!("SGX TCB info (FMSPC: {}): {}", fmspc, e));
}
}
}
// 18. Try FMSPCs with different platform filters
println!("\n18. Fetching FMSPCs with different platform filters...");
match client.get_fmspcs(None).await {
Ok(fmspcs_json) => {
let data = serde_json::json!({
"fmspcs_json": fmspcs_json,
});
fs::write(
test_data_dir.join("fmspcs_no_filter.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("FMSPCs (no filter)".to_string());
}
Err(e) => {
failures.push(format!("FMSPCs (no filter): {}", e));
}
}
match client.get_fmspcs(Some(PlatformFilter::All)).await {
Ok(fmspcs_json) => {
let data = serde_json::json!({
"fmspcs_json": fmspcs_json,
});
fs::write(
test_data_dir.join("fmspcs_all_platforms.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("FMSPCs (all platforms)".to_string());
}
Err(e) => {
failures.push(format!("FMSPCs (all platforms): {}", e));
}
}
// 19. Try PCK certificates with different parameters (encrypted PPID)
println!("\n19. Attempting to fetch PCK certificates with different params...");
// Try with a different encrypted PPID format
let encrypted_ppid = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
let pceid = "0000";
match client
.get_pck_certificates_by_ppid(encrypted_ppid, pceid, None, None)
.await
{
Ok(response) => {
let data = serde_json::json!({
"pck_certificates_json": response.pck_certs_json,
"issuer_chain": response.issuer_chain,
"fmspc": response.fmspc,
});
fs::write(
test_data_dir.join("pck_certificates.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("PCK certificates (by PPID)".to_string());
}
Err(e) => {
failures.push(format!("PCK certificates (by PPID): {}", e));
}
}
// 20. Try TDX TCB info with different FMSPCs
println!("\n20. Fetching TDX TCB info variations...");
let tdx_fmspcs = vec!["00806F050000", "00A06F050000", "00606A0000000"];
for fmspc in tdx_fmspcs {
match client.get_tdx_tcb_info(fmspc, None, None).await {
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join(format!("tdx_tcb_info_{}.json", fmspc)),
serde_json::to_string_pretty(&data)?,
)?;
successes.push(format!("TDX TCB info (FMSPC: {})", fmspc));
}
Err(e) => {
failures.push(format!("TDX TCB info (FMSPC: {}): {}", fmspc, e));
}
}
}
// 21. Try with V3 API for some endpoints
println!("\n21. Testing V3 API endpoints...");
let v3_client =
ApiClient::new_with_options("https://api.trustedservices.intel.com", ApiVersion::V3)?;
match v3_client.get_sgx_tcb_info("00906ED50000", None, None).await {
Ok(response) => {
let data = serde_json::json!({
"tcb_info_json": response.tcb_info_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_tcb_info_v3.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX TCB info (V3 API)".to_string());
}
Err(e) => {
failures.push(format!("SGX TCB info (V3 API): {}", e));
}
}
match v3_client.get_sgx_qe_identity(None, None).await {
Ok(response) => {
let data = serde_json::json!({
"enclave_identity_json": response.enclave_identity_json,
"issuer_chain": response.issuer_chain,
});
fs::write(
test_data_dir.join("sgx_qe_identity_v3.json"),
serde_json::to_string_pretty(&data)?,
)?;
successes.push("SGX QE identity (V3 API)".to_string());
}
Err(e) => {
failures.push(format!("SGX QE identity (V3 API): {}", e));
}
}
println!("\n\nTest data fetching complete!");
println!("\nSuccessful fetches:");
for s in &successes {
println!("{}", s);
}
if !failures.is_empty() {
println!("\nFailed fetches:");
for f in &failures {
println!("{}", f);
}
}
println!("\nData saved in: {}", test_data_dir.display());
Ok(())
}

View file

@ -0,0 +1,91 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
//! Example demonstrating automatic rate limit handling
//!
//! The Intel DCAP API client now automatically handles 429 Too Many Requests responses
//! by retrying up to 3 times by default. This example shows how to configure the retry
//! behavior and handle cases where all retries are exhausted.
use intel_dcap_api::{ApiClient, IntelApiError};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create API client with default settings (3 retries)
let mut client = ApiClient::new()?;
println!("Example 1: Default behavior (automatic retries)");
println!("================================================");
// Example FMSPC value
let fmspc = "00606A000000";
// The client will automatically retry up to 3 times if rate limited
match client.get_sgx_tcb_info(fmspc, None, None).await {
Ok(tcb_info) => {
println!("✓ Successfully retrieved TCB info");
println!(
" TCB Info JSON length: {} bytes",
tcb_info.tcb_info_json.len()
);
println!(
" Issuer Chain length: {} bytes",
tcb_info.issuer_chain.len()
);
}
Err(IntelApiError::TooManyRequests {
request_id,
retry_after,
}) => {
println!("✗ Rate limited even after 3 automatic retries");
println!(" Request ID: {}", request_id);
println!(" Last retry-after was: {} seconds", retry_after);
}
Err(e) => {
eprintln!("✗ Other error: {}", e);
}
}
println!("\nExample 2: Custom retry configuration");
println!("=====================================");
// Configure client to retry up to 5 times
client.set_max_retries(5);
println!("Set max retries to 5");
match client.get_sgx_tcb_info(fmspc, None, None).await {
Ok(_) => println!("✓ Request succeeded"),
Err(IntelApiError::TooManyRequests { .. }) => {
println!("✗ Still rate limited after 5 retries")
}
Err(e) => eprintln!("✗ Error: {}", e),
}
println!("\nExample 3: Disable automatic retries");
println!("====================================");
// Disable automatic retries
client.set_max_retries(0);
println!("Disabled automatic retries");
match client.get_sgx_tcb_info(fmspc, None, None).await {
Ok(_) => println!("✓ Request succeeded on first attempt"),
Err(IntelApiError::TooManyRequests {
request_id,
retry_after,
}) => {
println!("✗ Rate limited (no automatic retry)");
println!(" Request ID: {}", request_id);
println!(" Retry after: {} seconds", retry_after);
println!(" You would need to implement manual retry logic here");
}
Err(e) => eprintln!("✗ Error: {}", e),
}
println!("\nNote: The client handles rate limiting automatically!");
println!("You only need to handle TooManyRequests errors if:");
println!("- You disable automatic retries (set_max_retries(0))");
println!("- All automatic retries are exhausted");
Ok(())
}

View file

@ -0,0 +1,495 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use intel_dcap_api::{
ApiClient, ApiVersion, CaType, CrlEncoding, IntelApiError, PlatformFilter, UpdateType,
};
use std::time::Duration;
use tokio::time::sleep;
/// Comprehensive integration test example demonstrating most Intel DCAP API client functions
///
/// This example shows how to use various endpoints of the Intel Trusted Services API.
/// Note: Some operations may fail with 404 or 400 errors if the data doesn't exist on Intel's servers.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Intel DCAP API Integration Test Example ===\n");
// Create clients for both V3 and V4 APIs
let v4_client = ApiClient::new()?;
let v3_client =
ApiClient::new_with_options("https://api.trustedservices.intel.com", ApiVersion::V3)?;
// Track successes and failures
let mut results = Vec::new();
// Test FMSPC - commonly used for TCB lookups
let test_fmspc = "00906ED50000";
let test_fmspc_tdx = "00806F050000";
println!("1. Testing TCB Info Endpoints...");
println!("================================");
// 1.1 SGX TCB Info (V4)
print!(" - SGX TCB Info (V4): ");
match v4_client.get_sgx_tcb_info(test_fmspc, None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX TCB Info (V4)", false));
} else {
println!("✓ Success");
println!(" FMSPC: {}", test_fmspc);
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?;
if let Some(version) = tcb_info["tcbInfo"]["version"].as_u64() {
println!(" TCB Info Version: {}", version);
}
results.push(("SGX TCB Info (V4)", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX TCB Info (V4)", false));
}
}
// Add small delay between requests to be nice to the API
sleep(Duration::from_millis(100)).await;
// 1.2 SGX TCB Info (V3)
print!(" - SGX TCB Info (V3): ");
match v3_client.get_sgx_tcb_info(test_fmspc, None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX TCB Info (V3)", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
results.push(("SGX TCB Info (V3)", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX TCB Info (V3)", false));
}
}
sleep(Duration::from_millis(100)).await;
// 1.3 TDX TCB Info
print!(" - TDX TCB Info: ");
match v4_client.get_tdx_tcb_info(test_fmspc_tdx, None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("TDX TCB Info", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
let tcb_info: serde_json::Value = serde_json::from_str(&response.tcb_info_json)?;
if let Some(id) = tcb_info["tcbInfo"]["id"].as_str() {
println!(" Platform: {}", id);
}
results.push(("TDX TCB Info", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("TDX TCB Info", false));
}
}
sleep(Duration::from_millis(100)).await;
// 1.4 SGX TCB Info with Early Update
print!(" - SGX TCB Info (Early Update): ");
match v4_client
.get_sgx_tcb_info(test_fmspc, Some(UpdateType::Early), None)
.await
{
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX TCB Info (Early)", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
results.push(("SGX TCB Info (Early)", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX TCB Info (Early)", false));
}
}
sleep(Duration::from_millis(100)).await;
println!("\n2. Testing Enclave Identity Endpoints...");
println!("========================================");
// 2.1 SGX QE Identity
print!(" - SGX QE Identity: ");
match v4_client.get_sgx_qe_identity(None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX QE Identity", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
let identity: serde_json::Value =
serde_json::from_str(&response.enclave_identity_json)?;
if let Some(id) = identity["enclaveIdentity"]["id"].as_str() {
println!(" Enclave ID: {}", id);
}
results.push(("SGX QE Identity", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX QE Identity", false));
}
}
sleep(Duration::from_millis(100)).await;
// 2.2 SGX QVE Identity
print!(" - SGX QVE Identity: ");
match v4_client.get_sgx_qve_identity(None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX QVE Identity", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
results.push(("SGX QVE Identity", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX QVE Identity", false));
}
}
sleep(Duration::from_millis(100)).await;
// 2.3 SGX QAE Identity
print!(" - SGX QAE Identity: ");
match v4_client.get_sgx_qae_identity(None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX QAE Identity", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
results.push(("SGX QAE Identity", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX QAE Identity", false));
}
}
sleep(Duration::from_millis(100)).await;
// 2.4 TDX QE Identity (V4 only)
print!(" - TDX QE Identity: ");
match v4_client.get_tdx_qe_identity(None, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("TDX QE Identity", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
results.push(("TDX QE Identity", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("TDX QE Identity", false));
}
}
sleep(Duration::from_millis(100)).await;
println!("\n3. Testing PCK CRL Endpoints...");
println!("================================");
// 3.1 PCK CRL - Processor (PEM)
print!(" - PCK CRL (Processor, PEM): ");
match v4_client.get_pck_crl(CaType::Processor, None).await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("PCK CRL (Processor)", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
let crl_str = String::from_utf8_lossy(&response.crl_data);
if crl_str.contains("BEGIN X509 CRL") {
println!(" Format: PEM");
}
results.push(("PCK CRL (Processor)", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("PCK CRL (Processor)", false));
}
}
sleep(Duration::from_millis(100)).await;
// 3.2 PCK CRL - Platform (DER)
print!(" - PCK CRL (Platform, DER): ");
match v4_client
.get_pck_crl(CaType::Platform, Some(CrlEncoding::Der))
.await
{
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("PCK CRL (Platform, DER)", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
println!(" CRL size: {} bytes", response.crl_data.len());
results.push(("PCK CRL (Platform, DER)", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("PCK CRL (Platform, DER)", false));
}
}
sleep(Duration::from_millis(100)).await;
println!("\n4. Testing FMSPC Endpoints (V4 only)...");
println!("=======================================");
// 4.1 Get FMSPCs (no filter)
print!(" - Get FMSPCs (no filter): ");
match v4_client.get_fmspcs(None).await {
Ok(fmspcs_json) => {
println!("✓ Success");
let fmspcs: serde_json::Value = serde_json::from_str(&fmspcs_json)?;
if let Some(arr) = fmspcs.as_array() {
println!(" Total FMSPCs: {}", arr.len());
// Show first few FMSPCs
for (i, fmspc) in arr.iter().take(3).enumerate() {
if let (Some(fmspc_val), Some(platform)) =
(fmspc["fmspc"].as_str(), fmspc["platform"].as_str())
{
println!(" [{}] {} - {}", i + 1, fmspc_val, platform);
}
}
if arr.len() > 3 {
println!(" ... and {} more", arr.len() - 3);
}
}
results.push(("Get FMSPCs", true));
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("Get FMSPCs", false));
}
}
sleep(Duration::from_millis(100)).await;
// 4.2 Get FMSPCs with platform filter
print!(" - Get FMSPCs (All platforms): ");
match v4_client.get_fmspcs(Some(PlatformFilter::All)).await {
Ok(_) => {
println!("✓ Success");
results.push(("Get FMSPCs (filtered)", true));
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("Get FMSPCs (filtered)", false));
}
}
sleep(Duration::from_millis(100)).await;
println!("\n5. Testing TCB Evaluation Data Numbers (V4 only)...");
println!("===================================================");
// 5.1 SGX TCB Evaluation Data Numbers
print!(" - SGX TCB Evaluation Data Numbers: ");
match v4_client.get_sgx_tcb_evaluation_data_numbers().await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("SGX TCB Eval Numbers", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
let data: serde_json::Value =
serde_json::from_str(&response.tcb_evaluation_data_numbers_json)?;
if let Some(sgx_data) = data.get("sgx") {
println!(
" SGX entries: {}",
sgx_data.as_array().map(|a| a.len()).unwrap_or(0)
);
}
results.push(("SGX TCB Eval Numbers", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("SGX TCB Eval Numbers", false));
}
}
sleep(Duration::from_millis(100)).await;
// 5.2 TDX TCB Evaluation Data Numbers
print!(" - TDX TCB Evaluation Data Numbers: ");
match v4_client.get_tdx_tcb_evaluation_data_numbers().await {
Ok(response) => {
if response.issuer_chain.is_empty() {
println!("✗ Failed: Empty issuer chain");
results.push(("TDX TCB Eval Numbers", false));
} else {
println!("✓ Success");
println!(" Issuer chain: {} bytes", response.issuer_chain.len());
let data: serde_json::Value =
serde_json::from_str(&response.tcb_evaluation_data_numbers_json)?;
if let Some(tdx_data) = data.get("tdx") {
println!(
" TDX entries: {}",
tdx_data.as_array().map(|a| a.len()).unwrap_or(0)
);
}
results.push(("TDX TCB Eval Numbers", true));
}
}
Err(e) => {
println!("✗ Failed: {:?}", e);
results.push(("TDX TCB Eval Numbers", false));
}
}
sleep(Duration::from_millis(100)).await;
println!("\n6. Testing PCK Certificate Endpoints...");
println!("=======================================");
/* // 6.1 PCK Certificate by PPID (usually requires valid data)
print!(" - PCK Certificate by PPID: ");
let test_ppid = "0000000000000000000000000000000000000000000000000000000000000000";
let test_cpusvn = "00000000000000000000000000000000";
let test_pcesvn = "0000";
let test_pceid = "0000";
match v4_client
.get_pck_certificate_by_ppid(test_ppid, test_cpusvn, test_pcesvn, test_pceid, None, None)
.await
{
Ok(_) => {
println!("✓ Success");
results.push(("PCK Certificate", true));
}
Err(e) => {
// Expected to fail with test data
match &e {
IntelApiError::ApiError { status, .. } => {
println!("✗ Failed (Expected): HTTP {}", status);
}
_ => println!("✗ Failed: {:?}", e),
}
results.push(("PCK Certificate", false));
}
}
sleep(Duration::from_millis(100)).await;
*/
println!("\n7. Testing API Version Compatibility...");
println!("=======================================");
// 7.1 Try V4-only endpoint on V3
print!(" - V4-only endpoint on V3 (should fail): ");
match v3_client.get_fmspcs(None).await {
Ok(_) => {
println!("✗ Unexpected success!");
results.push(("V3/V4 compatibility check", false));
}
Err(IntelApiError::UnsupportedApiVersion(_)) => {
println!("✓ Correctly rejected");
results.push(("V3/V4 compatibility check", true));
}
Err(e) => {
println!("✗ Wrong error: {:?}", e);
results.push(("V3/V4 compatibility check", false));
}
}
println!("\n8. Testing Error Handling...");
println!("============================");
// 8.1 Invalid FMSPC
print!(" - Invalid FMSPC format: ");
match v4_client.get_sgx_tcb_info("invalid", None, None).await {
Ok(_) => {
println!("✗ Unexpected success!");
results.push(("Error handling", false));
}
Err(IntelApiError::ApiError {
status,
error_code,
error_message,
..
}) => {
println!("✓ Correctly handled");
println!(" Status: {}", status);
if let Some(code) = error_code {
println!(" Error Code: {}", code);
}
if let Some(msg) = error_message {
println!(" Error Message: {}", msg);
}
results.push(("Error handling", true));
}
Err(e) => {
println!("✗ Unexpected error: {:?}", e);
results.push(("Error handling", false));
}
}
// Summary
println!("\n\n=== Summary ===");
println!("===============");
let total = results.len();
let successful = results.iter().filter(|(_, success)| *success).count();
let failed = total - successful;
println!("Total tests: {}", total);
println!(
"Successful: {} ({}%)",
successful,
(successful * 100) / total
);
println!("Failed: {} ({}%)", failed, (failed * 100) / total);
println!("\nDetailed Results:");
for (test, success) in &results {
println!(" {} {}", if *success { "" } else { "" }, test);
}
println!("\nNote: Some failures are expected due to:");
println!("- Test data not existing on Intel servers");
println!("- PCK operations requiring valid platform data");
println!("- Subscription key requirements for certain endpoints");
Ok(())
}

View file

@ -0,0 +1,694 @@
# Intel® SGX and Intel® TDX services - V3 API Documentation
## Intel® SGX and Intel® TDX Registration Service for Scalable Platforms
The API exposed by the Intel SGX registration service allows registering an Intel® SGX platform with multiple processor
packages as a single platform instance, which can be remotely attested as a single entity later on[cite: 1]. The minimum
version of the TLS protocol supported by the service is 1.2; any connection attempts with previous versions of TLS/SSL
will be dropped by the server[cite: 2].
### Register Platform
This API allows registering a multi-package SGX platform, covering initial registration and TCB Recovery[cite: 2].
During registration, the platform manifest is authenticated by the Registration Service to verify it originates from a
genuine, non-revoked SGX platform[cite: 2]. If the platform configuration is successfully verified, platform
provisioning root keys are stored in the backend[cite: 2].
Stored platform provisioning root keys are later used to derive the public parts of Provisioning Certification Keys (
PCKs)[cite: 2]. These PCKs are distributed as x.509 certificates by the Provisioning Certification Service for Intel SGX
and are used during the remote attestation of the platform[cite: 3].
#### POST `https://api.trustedservices.intel.com/sgx/registration/v1/platform`
**Request**
**Headers**
Besides the headers explicitly mentioned below, the HTTP request may contain standard HTTP headers (e.g.,
Content-Length)[cite: 3].
| Name | Required | Value | Description |
|:-------------|:---------|:---------------------------|:----------------------------------------|
| Content-Type | True | `application/octet-stream` | MIME type of the request body[cite: 4]. |
**Body**
The body is a binary representation of the Platform Manifest structure an opaque blob representing a registration
manifest for a multi-package platform[cite: 5]. It contains platform provisioning root keys established by the platform
instance and data required to authenticate the platform as genuine and non-revoked[cite: 5].
**Example Request**
```bash
curl -H "Content-Type: application/octet-stream" --data-binary @platform_manifest POST "[https://api.trustedservices.intel.com/sgx/registration/v1/platform](https://api.trustedservices.intel.com/sgx/registration/v1/platform)"
````
**Response**
**Model**
The response is a Hex-encoded representation of the PPID for the registered platform instance (only if the HTTP Status
Code is 201; otherwise, the body is empty).
**Example Response**
```
001122334455667788AABBCCDDEEFF
```
**Status Codes**
| Code | Headers | Body | Description |
|:-----|:--------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 201 | Request-ID: Randomly generated identifier for each request (for troubleshooting purposes). | Hex-encoded representation of PPID. | Operation successful (new platform instance registered). A new platform instance has been registered[cite: 5]. |
| 400 | Request-ID: Randomly generated identifier[cite: 6]. \<br\> Error-Code and Error-Message: Additional details about the error[cite: 9]. | | Invalid Platform Manifest[cite: 8]. The request might be malformed[cite: 6], intended for a different server[cite: 7], contain an invalid/revoked package[cite: 7], an unrecognized package[cite: 7], an incompatible package[cite: 7], an invalid manifest[cite: 7], or violate a key caching policy[cite: 8]. The client should not repeat the request without modifications[cite: 9]. |
| 415 | Request-ID: Randomly generated identifier[cite: 10]. | | MIME type specified in the request is not supported[cite: 10]. |
| 500 | Request-ID: Randomly generated identifier[cite: 10]. | | Internal server error occurred[cite: 10]. |
| 503 | Request-ID: Randomly generated identifier[cite: 10]. | | Server is currently unable to process the request. The client should try again later[cite: 11]. |
-----
### Add Package
This API adds new package(s) to an already registered platform instance[cite: 11]. A subscription is required[cite: 11].
If successful, a Platform Membership Certificate is generated for each processor package in the Add Request[cite: 12].
#### POST `https://api.trustedservices.intel.com/sgx/registration/v1/package`
**Request**
**Headers**
| Name | Required | Value | Description |
|:--------------------------|:---------|:---------------------------|:--------------------------------------------------------------------------------|
| Ocp-Apim-Subscription-Key | True | | Subscription key providing access to this API, found in your Profile[cite: 14]. |
| Content-Type | True | `application/octet-stream` | MIME type of the request body[cite: 14]. |
**Body**
Binary representation of the Add Request structure an opaque blob for adding new processor packages to an existing
platform instance.
**Example Request**
```bash
curl -H "Content-Type: application/octet-stream" --data-binary @add_package POST "[https://api.trustedservices.intel.com/sgx/registration/v1/package](https://api.trustedservices.intel.com/sgx/registration/v1/package)" -H "Ocp-Apim-Subscription-Key: {subscription_key}"
```
**Response**
**Model**
For a 200 HTTP Status Code, the response is a fixed-size array (8 elements) containing binary representations of
Platform Membership Certificate structures[cite: 15]. Certificates are populated sequentially, starting at index 0, with
the rest of the elements zeroed[cite: 15].
**Example Response (hex-encoded)**
```
E4B0E8B80F8B49184488F77273550840984816854488B7CFRP...
```
**Status Codes**
| Code | Headers | Body | Description |
|:-----|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 200 | Content-Type: `application/octet-stream`[cite: 17]. \<br\> Request-ID: Random identifier[cite: 17]. \<br\> CertificateCount: Number of certificates returned[cite: 17]. | Fixed-size array of Platform Membership Certificates[cite: 17]. | Operation successful. Packages added[cite: 17]. |
| 400 | Request-ID: Random identifier[cite: 17]. \<br\> Error-Code and Error-Message: Details on the error[cite: 17]. | | Invalid Add Request Payload[cite: 17]. Can be due to malformed syntax, platform not found, invalid/revoked/unrecognized package, or invalid AddRequest[cite: 17]. |
| 401 | Request-ID: Random identifier[cite: 17]. | | Failed to authenticate or authorize the request[cite: 17]. |
| 415 | Request-ID: Random identifier[cite: 17]. | | MIME type specified is not supported[cite: 17]. |
| 500 | Request-ID: Random identifier[cite: 17]. | | Internal server error occurred[cite: 17]. |
| 503 | Request-ID: Random identifier[cite: 17]. | | Server is currently unable to process the request[cite: 17]. |
-----
## Intel® SGX Provisioning Certification Service for ECDSA Attestation
Download the Provisioning Certification Root CA Certificate (API v3) here:
* [DER](https://www.google.com/search?q=https://certificates.trustedservices.intel.com/Intel_SGX_Provisioning_Certification_RootCA.cer) [cite: 18]
* [PEM](https://www.google.com/search?q=https://certificates.trustedservices.intel.com/intel_SGX_Provisioning_Certification_RootCA.perm) [cite: 18]
### Get PCK Certificate V3
This API allows requesting a single PCK certificate by specifying PPID and SVNs or Platform Manifest and SVNs[cite: 18].
A subscription is required[cite: 18].
* **Using PPID and SVNs**:
* Single-socket platforms: No prerequisites[cite: 18].
* Multi-socket platforms: Requires previous registration via `Register Platform` API[cite: 18]. Platform root keys
must be persistently stored[cite: 19], and the `Keys Caching Policy` must be set to `true`[cite: 21]. The service
uses a PCK public key derived from stored keys[cite: 20].
* **Using Platform Manifest and SVNs**:
* Multi-socket platforms: Does not require previous registration[cite: 21]. It doesn't require keys to be
persistently stored[cite: 22]. The service uses a PCK public key derived from the provided manifest[cite: 23].
Depending on the `Keys Caching Policy`, keys might be stored[cite: 24].
* **Direct Registration** (`Register Platform` first): Sets policy to always store keys[cite: 25]. Keys are
stored when the manifest is sent[cite: 26]. `CachedKeys` flag in PCK Certificates is set to `true`[cite: 27].
* **Indirect Registration** (`Get PCK Certificate(s)` first): Sets policy to never store keys[cite: 27]. Keys
are discarded after use[cite: 28]. Standard metadata is stored, but `Register Platform` cannot be used
anymore[cite: 29]. `CachedKeys` flag is set to `false`[cite: 30].
The PCS returns the PCK Certificate representing the TCB level with the highest security posture based on CPUSVN and PCE
ISVSVN[cite: 30].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcert`
**Request**
| Name | Type | Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------|:---------|:--------------------|:-----------------------------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 32]. |
| PPID-Encryption-Key | String | Header | False | | Type of key for PPID encryption (Default: `RSA-3072`)[cite: 32]. |
| encrypted\_ppid | String | Query | True | `[0-9a-fA-F]{768}$` | Base16-encoded PPID (encrypted with PPIDEK)[cite: 32]. |
| cpusvn | String | Query | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN (16 bytes)[cite: 32]. |
| pcesvn | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCESVN (2 bytes, little endian)[cite: 32]. |
| pceid | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID (2 bytes, little endian)[cite: 32]. |
**Example Request**
```bash
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcert?encrypted_ppid=...&cpusvn=...&pcesvn=...&pceid=](https://api.trustedservices.intel.com/sgx/certification/v3/pckcert?encrypted_ppid=...&cpusvn=...&pcesvn=...&pceid=)..." -H "Ocp-Apim-Subscription-Key: {subscription_key}"
```
**Response**: Response description can be
found [here](https://www.google.com/search?q=%23response-get-and-post-1)[cite: 34].
#### POST `https://api.trustedservices.intel.com/sgx/certification/v3/pckcert`
**Request**
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:-----------------------------|:---------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 35]. |
| Content-Type | String | Header | True | | Content Type (`application/json`)[cite: 35]. |
| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16882,112884}$` | Base16-encoded Platform Manifest[cite: 35]. |
| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN[cite: 35]. |
| pcesvn | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCESVN[cite: 35]. |
| pceid | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 35]. |
**Body**
```json
{
"platformManifest": "...",
"cpusvn": "...",
"pcesvn": "...",
"pceid": "..."
}
```
**Example Request**
```bash
curl -X POST -d '{"platformManifest": "...", "cpusvn": "...", "pcesvn": "...", "pceid": "..."}' -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription_key}" "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcert](https://api.trustedservices.intel.com/sgx/certification/v3/pckcert)"
```
**Response (GET and POST)**
**Model**: PckCert (X-PEM-FILE) - PEM-encoded SGX PCK Certificate[cite: 36].
**Example Response**
```pem
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
```
**Status Codes**
| Code | Model | Headers | Description |
|:-----|:--------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------|
| 200 | PckCert | Content-Type: `application/x-pem-file`[cite: 36]. \<br\> Request-ID[cite: 36]. \<br\> SGX-PCK-Certificate-Issuer-Chain: URL-encoded issuer chain[cite: 36]. \<br\> SGX-TCBm: Hex-encoded CPUSVN and PCESVN[cite: 37]. \<br\> SGX-FMSPC: Hex-encoded FMSPC[cite: 37]. \<br\> SGX-PCK-Certificate-CA-Type: 'processor' or 'platform'[cite: 39]. \<br\> Warning: Optional message[cite: 39]. | Operation successful[cite: 36]. |
| 400 | | Request-ID[cite: 39]. \<br\> Warning[cite: 39]. | Invalid request parameters[cite: 39]. |
| 401 | | Request-ID[cite: 40]. \<br\> Warning[cite: 40]. | Failed to authenticate or authorize the request[cite: 40]. |
| 404 | | Request-ID[cite: 40]. \<br\> Warning[cite: 40]. | PCK Certificate not found[cite: 40]. Reasons: unsupported PPID/PCE-ID, TCB level too low, or Platform Manifest not registered/updated[cite: 41]. |
| 500 | | Request-ID[cite: 41]. \<br\> Warning[cite: 41]. | Internal server error occurred[cite: 41]. |
| 503 | | Request-ID[cite: 42]. \<br\> Warning[cite: 42]. | Server is currently unable to process the request[cite: 42]. |
-----
### Get PCK Certificates V3
This API retrieves PCK certificates for all configured TCB levels using PPID or Platform Manifest[cite: 42].
Subscription required[cite: 42].
* **Using PPID**:
* Single-socket platforms: No prerequisites[cite: 43].
* Multi-socket platforms: Requires prior registration via `Register Platform` API[cite: 44]. Keys must be
persistently stored[cite: 45], and `Keys Caching Policy` must be `true`[cite: 47]. PCS uses stored keys[cite: 46].
* **Using Platform Manifest**:
* Multi-socket platforms: Does not require prior registration[cite: 47]. Does not require persistent
storage[cite: 48]. PCS uses manifest keys[cite: 49]. Caching policy determines storage[cite: 50].
* **Direct Registration**: Always stores keys; `CachedKeys` is `true`[cite: 51, 52].
* **Indirect Registration**: Never stores keys; `CachedKeys` is `false`[cite: 53].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts`
Retrieves certificates based on encrypted PPID and PCE-ID[cite: 53].
**Request**
| Name | Type | Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------|:---------|:--------------------|:--------------------------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 54]. |
| PPID-Encryption-Key | String | Header | False | | Key type for PPID encryption (Default: `RSA-3072`)[cite: 54]. |
| encrypted\_ppid | String | Query | True | `[0-9a-fA-F]{768}$` | Base16-encoded PPID[cite: 54]. |
| pceid | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 54]. |
**Example Request**
```bash
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts?encrypted_ppid=...&pceid=](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts?encrypted_ppid=...&pceid=)..." -H "Ocp-Apim-Subscription-Key: {subscription_key}"
```
**Response**: Response description can be
found [here](https://www.google.com/search?q=%23response-get-and-post-2)[cite: 55].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config`
Retrieves certificates for a specific CPUSVN (multi-package only)[cite: 55].
**Request**
| Name | Type | Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------|:---------|:--------------------|:----------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 56]. |
| PPID-Encryption-Key | String | Header | False | | Key type for PPID encryption[cite: 56]. |
| encrypted\_ppid | String | Query | True | `[0-9a-fA-F]{768}$` | Base16-encoded PPID[cite: 56]. |
| pceid | String | Query | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 56]. |
| cpusvn | String | Query | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN[cite: 56]. |
**Example Request**
```bash
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config?encrypted_ppid=...&pceid=...&cpusvn=](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config?encrypted_ppid=...&pceid=...&cpusvn=)..." -H "Ocp-Apim-Subscription-Key: {subscription_key}"
```
**Response**: Response description can be
found [here](https://www.google.com/search?q=%23response-get-and-post-2)[cite: 57].
#### POST `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts`
Retrieves certificates based on Platform Manifest and PCE-ID (multi-package only)[cite: 57].
**Request**
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:-----------------------------|:--------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 58]. |
| Content-Type | String | Header | True | `application/json` | Content Type[cite: 58]. |
| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16882,112884}$` | Base16-encoded Platform Manifest[cite: 58]. |
| pceid | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 58]. |
**Body**
```json
{
"platformManifest": "...",
"pceid": "..."
}
```
**Example Request**
```bash
curl -X POST -d '{"platformManifest": "...", "pceid": "..."}' -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription_key}" "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts)"
```
**Response**: Response description can be
found [here](https://www.google.com/search?q=%23response-get-and-post-2)[cite: 59].
#### POST `https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config`
Retrieves certificates for a specific CPUSVN using Platform Manifest (multi-package only)[cite: 59].
**Request**
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:-----------------------------|:--------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | True | | Subscription key[cite: 61]. |
| Content-Type | String | Header | True | `application/json` | Content Type[cite: 61]. |
| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16882,112884}$` | Base16-encoded Platform Manifest[cite: 61]. |
| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}$` | Base16-encoded CPUSVN[cite: 61]. |
| pceid | String | Body Field | True | `[0-9a-fA-F]{4}$` | Base16-encoded PCE-ID[cite: 61]. |
**Body**
```json
{
"platformManifest": "...",
"cpusvn": "...",
"pceid": "..."
}
```
**Example Request**
```bash
curl -X POST -d '{"platformManifest": "...", "cpusvn": "...", "pceid": "..."}' -H "Content-Type: application/json" -H "Ocp-Apim-Subscription-Key: {subscription_key}" "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config](https://api.trustedservices.intel.com/sgx/certification/v3/pckcerts/config)"
```
**Response (GET and POST)**
**Model**: PckCerts (JSON) - Array of data structures with `tcb`, `tcm`, and `certificate`[cite: 62].
**PckCerts Structure**
```json
[
{
"tcb": {
"sgxtcbcomp01svn": 0,
// Integer
"sgxtcbcomp02svn": 0,
// Integer
// ... (03 to 16)
"pcesvn": 0
// Integer
},
"tcm": "...",
// String, Hex-encoded TCBm [cite: 63, 64]
"cert": "..."
// String, PEM-encoded certificate or "Not available" [cite: 64]
}
]
```
**Example Response**
```json
[
{
"tcb": {
"sgxtcbcomp01svn": 0,
"sgxtcbcomp02svn": 0,
"sgxtcbcomp03svn": 0,
"sgxtcbcomp04svn": 0,
"sgxtcbcomp05svn": 0,
"sgxtcbcomp06svn": 0,
"sgxtcbcomp07svn": 0,
"sgxtcbcomp08svn": 0,
"sgxtcbcomp09svn": 0,
"sgxtcbcomp10svn": 0,
"sgxtcbcomp11svn": 0,
"sgxtcbcomp12svn": 0,
"sgxtcbcomp13svn": 0,
"sgxtcbcomp14svn": 0,
"sgxtcbcomp15svn": 0,
"sgxtcbcomp16svn": 0,
"pcesvn": 0
},
"tcm": "...",
"cert": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
}
]
```
**Status Codes**
| Code | Model | Headers | Description |
|:-----|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------|
| 200 | PckCerts | Content-Type: `application/json`[cite: 65]. \<br\> Request-ID[cite: 65]. \<br\> SGX-PCK-Certificate-Issuer-Chain: Issuer chain[cite: 66]. \<br\> SGX-FMSPC[cite: 66]. \<br\> SGX-PCK-Certificate-CA-Type[cite: 66]. \<br\> Warning[cite: 66]. | Operation successful[cite: 65]. |
| 400 | | Request-ID[cite: 67]. \<br\> Warning[cite: 67]. | Invalid request parameters[cite: 67]. |
| 401 | | Request-ID[cite: 68]. \<br\> Warning[cite: 68]. | Failed to authenticate or authorize the request[cite: 68]. |
| 404 | | Request-ID[cite: 69]. \<br\> Warning[cite: 69]. | PCK Certificate not found[cite: 69]. Reasons: PPID/PCE-ID not supported or Platform Manifest not registered[cite: 70]. |
| 500 | | Request-ID[cite: 70]. \<br\> Warning[cite: 70]. | Internal server error occurred[cite: 70]. |
| 503 | | Request-ID[cite: 70]. \<br\> Warning[cite: 70]. | Server is currently unable to process the request[cite: 70]. |
-----
### Get Revocation List V3
Retrieves the X.509 Certificate Revocation List (CRL) for revoked SGX PCK Certificates[cite: 71]. CRLs are issued by
Intel SGX Processor CA or Platform CA[cite: 71].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/pckcrl`
**Request**
| Name | Type | Request Type | Required | Pattern | Description |
|:---------|:-------|:-------------|:---------|:------------|:------------|
| ca | String | Query | True | `(processor | platform)` | CA that issued the CRL[cite: 71]. |
| encoding | String | Query | False | `(pem | der)` | Encoding (Default: PEM)[cite: 71]. |
**Example Request**
```bash
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/pckcrl?ca=platform&encoding=der](https://api.trustedservices.intel.com/sgx/certification/v3/pckcrl?ca=platform&encoding=der)"
```
**Response**
**Model**: PckCrl (X-PEM-FILE or PKIX-CRL) - PEM or DER-encoded CRL[cite: 71].
**Example Response**
```
-----BEGIN X509 CRL-----
...
-----END X509 CRL-----
```
**Status Codes**
| Code | Model | Headers | Description |
|:-----|:-------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------|
| 200 | PckCrl | Content-Type: `application/x-pem-file` (PEM) or `application/pkix-crl` (DER)[cite: 72]. \<br\> Request-ID[cite: 72]. \<br\> SGX-PCK-CRL-Issuer-Chain: Issuer chain[cite: 72]. \<br\> Warning[cite: 72]. | Operation successful[cite: 72]. |
| 400 | | Request-ID[cite: 72]. \<br\> Warning[cite: 73]. | Invalid request parameters[cite: 72]. |
| 401 | | Request-ID[cite: 73]. \<br\> Warning[cite: 73]. | Failed to authenticate or authorize[cite: 73]. |
| 500 | | Request-ID[cite: 73]. \<br\> Warning[cite: 73]. | Internal server error occurred[cite: 73]. |
| 503 | | Request-ID[cite: 73]. \<br\> Warning[cite: 73]. | Server is currently unable to process[cite: 73]. |
-----
### Get TCB Info V3
Retrieves SGX TCB information for a given FMSPC[cite: 74].
**Algorithm for TCB Status:**
1. Retrieve FMSPC from the SGX PCK Certificate[cite: 74].
2. Retrieve TCB Info matching the FMSPC[cite: 75].
3. Iterate through the sorted TCB Levels[cite: 75]:
* Compare all SGX TCB Comp SVNs (01-16) from the certificate with TCB Level values[cite: 76]. If all are \>=,
proceed[cite: 76]. Otherwise, move to the next item[cite: 76].
* Compare PCESVN from the certificate with the TCB Level value[cite: 77]. If \>=, read the status[cite: 77].
Otherwise, move to the next item[cite: 78].
4. If no match is found, the TCB Level is not supported[cite: 78].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/tcb`
**Request**
| Name | Type | Request Type | Required | Pattern | Description |
|:------------------------|:-------|:-------------|:---------|:-------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| fmspc | String | Query | True | `[0-9a-fA-F]{12}$` | Base16-encoded FMSPC (6 bytes)[cite: 81]. |
| update | String | Query | False | `(early | standard)` | Update type (Default: standard). 'early' provides early access, 'standard' provides standard access[cite: 81]. Cannot be used with `tcbEvaluationDataNumber`[cite: 81]. |
| tcbEvaluationDataNumber | Number | Query | False | `\d+$` | Specifies a TCB Evaluation Data Number. Allows fetching specific versions; returns 410 if \< M, 404 if \> N[cite: 81]. Cannot be used with `update`[cite: 81]. |
**Example Requests**
```bash
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&update=early](https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&update=early)"
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&tcbEvaluationDataNumber=](https://api.trustedservices.intel.com/sgx/certification/v3/tcb?fmspc=...&tcbEvaluationDataNumber=)..."
```
**Response**
**Model**: TcbInfoV2 (JSON) - SGX TCB Info[cite: 82].
**TcbInfoV2 Structure**
* `version`: Integer[cite: 83].
* `issueDate`: String (date-time, ISO 8601 UTC)[cite: 84].
* `nextUpdate`: String (date-time, ISO 8601 UTC)[cite: 85].
* `fmspc`: String (Base16-encoded FMSPC)[cite: 85].
* `pceId`: String (Base16-encoded PCE-ID)[cite: 85].
* `tcbType`: Integer[cite: 85].
* `tcbEvaluationDataNumber`: Integer, monotonically increasing sequence number for TCB evaluation data set
updates[cite: 86]. Synchronized across TCB Info and Identities[cite: 86]. Helps determine which data supersedes
another[cite: 87].
* `tcbLevels`: Array of TCB level objects[cite: 87].
* `tcb`: Object with `sgxtcbcompXXsvn` (Integer) and `pcesvn` (Integer)[cite: 87].
* `tcbDate`: String (date-time, ISO 8601 UTC)[cite: 89]. If advisories exist after this date with enforced
mitigations, status won't be `UpToDate`[cite: 88].
* `tcbStatus`: String (`UpToDate`, `HardeningNeeded`, `ConfigurationNeeded`, `ConfigurationAndHardeningNeeded`,
`OutOfDate`, `OutOfDateConfigurationNeeded`, `Revoked`)[cite: 90, 91, 92].
* `advisoryIDs`: Array of strings (e.g., `INTEL-SA-XXXXX`, `INTEL-DOC-XXXXX`)[cite: 93, 94].
* `signature`: String (Base16 encoded)[cite: 94].
**Example Response**
```json
{
"tcbInfo": {
"version": 2,
"issueDate": "2018-07-30T12:00:00Z",
"nextUpdate": "2018-08-30T12:00:00Z",
"fmspc": "...",
"pceId": "0000",
"tcbType": 1,
"tcbEvaluationDataNumber": 7,
"tcbLevels": [
{
"tcb": {
"sgxtcbcomp01svn": 0,
/* ... */
"pcesvn": 0
},
"tcbDate": "2018-07-11T12:00:00Z",
"tcbStatus": "UpToDate",
"advisoryIDs": [
"INTEL-SA-00070",
"INTEL-SA-00076"
]
}
]
},
"signature": "..."
}
```
**Status Codes**
| Code | Model | Headers | Description |
|:-----|:----------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------|
| 200 | TcbInfoV2 | Content-Type: `application/json`[cite: 96]. \<br\> Request-ID[cite: 96]. \<br\> SGX-TCB-Info-Issuer-Chain: Issuer chain[cite: 96]. \<br\> Warning[cite: 96]. | Operation successful[cite: 96]. |
| 400 | | Request-ID[cite: 96]. \<br\> Warning[cite: 96]. | Invalid request (bad FMSPC or conflicting `update`/`tcbEvaluationDataNumber`)[cite: 96]. |
| 401 | | Request-ID[cite: 96]. \<br\> Warning[cite: 96]. | Failed to authenticate or authorize[cite: 96]. |
| 404 | | Request-ID[cite: 96]. \<br\> Warning[cite: 96]. | TCB info not found for FMSPC or `tcbEvaluationDataNumber`[cite: 96]. |
| 410 | | Request-ID[cite: 98]. \<br\> Warning[cite: 98]. | TCB Information for `tcbEvaluationDataNumber` no longer available[cite: 98]. |
| 500 | | Request-ID[cite: 98]. \<br\> Warning[cite: 98]. | Internal server error[cite: 98]. |
| 503 | | Request-ID[cite: 98]. \<br\> Warning[cite: 98]. | Server unable to process[cite: 98]. |
-----
### Get Quoting Enclave Identity V3
Verifies if an SGX Enclave Report matches a valid Quoting Enclave (QE) identity[cite: 99].
**Algorithm:**
1. Retrieve and validate QE Identity[cite: 99].
2. Compare SGX Enclave Report against QE Identity:
* Verify `MRSIGNER` equals `mrsigner`[cite: 100].
* Verify `ISVPRODID` equals `isvprodid`[cite: 101].
* Verify `(miscselectMask & MISCSELECT)` equals `miscselect`[cite: 102].
* Verify `(attributesMask & ATTRIBUTES)` equals `attributes`[cite: 103, 104].
3. If any check fails, identity doesn't match[cite: 105].
4. Determine TCB status:
* Retrieve TCB Levels[cite: 106].
* Find TCB Level with ISVSVN \<= Enclave Report ISVSVN (descending)[cite: 107].
* Read `tcbStatus`; if not found, it's unsupported[cite: 108].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity`
**Request**
| Name | Type | Type | Required | Pattern | Description |
|:------------------------|:-------|:------|:---------|:--------|:------------------------------------------------------------------------------------------|
| update | String | Query | False | `(early | standard)` | Update type (Default: standard)[cite: 110]. Cannot be used with `tcbEvaluationDataNumber`[cite: 110]. |
| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Specifies TCB Evaluation Data Number[cite: 110]. Cannot be used with `update`[cite: 110]. |
**Example Requests**
```bash
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?update=early](https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?update=early)"
curl -X GET "[https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?tcbEvaluationDataNumber=](https://api.trustedservices.intel.com/sgx/certification/v3/qe/identity?tcbEvaluationDataNumber=)..."
```
**Response**
**Model**: QEIdentityV2 (JSON) - QE Identity data[cite: 111].
**QEIdentityV2 Structure**
* `enclaveIdentity`:
* `id`: String (`QE`, `QVE`, or `QAE`)[cite: 113].
* `version`: Integer[cite: 113].
* `issueDate`, `nextUpdate`: String (date-time, ISO 8601 UTC)[cite: 114].
* `tcbEvaluationDataNumber`: Integer[cite: 115].
* `miscselect`, `miscselectMask`: String (Base16-encoded)[cite: 115, 116].
* `attributes`, `attributesMask`: String (Base16-encoded)[cite: 116].
* `mrsigner`: String (Base16-encoded)[cite: 116].
* `isvprodid`: Integer[cite: 116].
* `tcbLevels`: Array of TCB level objects[cite: 116].
* `tcb`: Object with `isvsvn` (Integer)[cite: 117].
* `tcbDate`: String (date-time, ISO 8601 UTC)[cite: 117].
* `tcbStatus`: String (`UpToDate`, `OutOfDate`, `Revoked`)[cite: 119].
* `advisoryIDs`: Array of strings[cite: 119].
* `signature`: String (Hex-encoded)[cite: 119].
**Status Codes**
| Code | Model | Headers | Description |
|:-----|:-------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------|
| 200 | QEIdentityV2 | Content-Type: `application/json`[cite: 122]. \<br\> Request-ID[cite: 122]. \<br\> SGX-Enclave-Identity-Issuer-Chain: Issuer chain[cite: 122]. \<br\> Warning[cite: 122]. | Operation successful[cite: 122]. |
| 400 | | Request-ID[cite: 122]. \<br\> Warning[cite: 123]. | Invalid request (bad params or conflicting `update`/`tcbEvaluationDataNumber`)[cite: 122, 124]. |
| 401 | | Request-ID[cite: 123]. \<br\> Warning[cite: 123]. | Failed to authenticate or authorize[cite: 123]. |
| 404 | | Request-ID[cite: 123]. \<br\> Warning[cite: 123]. | QE identity not found for `tcbEvaluationDataNumber`[cite: 124]. |
| 410 | | Request-ID[cite: 124]. \<br\> Warning[cite: 124]. | QEIdentity for `tcbEvaluationDataNumber` no longer available[cite: 124]. |
| 500 | | Request-ID[cite: 125]. \<br\> Warning[cite: 125]. | Internal server error[cite: 125]. |
| 503 | | Request-ID[cite: 125]. \<br\> Warning[cite: 125]. | Server unable to process[cite: 125]. |
-----
### Get Quote Verification Enclave Identity V3
Verifies if an SGX Enclave Report matches a valid QVE identity[cite: 126].
**Algorithm:**
1. Retrieve and validate QVE Identity[cite: 126].
2. Compare Enclave Report: `MRSIGNER`[cite: 127], `ISVPRODID`[cite: 128], `MISCSELECT` (with mask)[cite: 128],
`ATTRIBUTES` (with mask)[cite: 128].
3. If any fails, no match[cite: 129].
4. Determine TCB status via ISVSVN comparison[cite: 129, 130].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/qve/identity`
**Request**: Same parameters as `Get Quoting Enclave Identity V3` (`update` and `tcbEvaluationDataNumber`)[cite: 132].
**Response**: QVEIdentityV2 (JSON) - QVE Identity data[cite: 133]. Structure similar to QE
Identity[cite: 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144].
**Status Codes**: Similar to `Get Quoting Enclave Identity V3`[cite: 145].
-----
### Get Quote Appraisal Enclave Identity V3
Verifies if an SGX Enclave Report matches a valid QAE identity[cite: 149].
**Algorithm:**
1. Retrieve and validate QAE Identity[cite: 149].
2. Compare Enclave Report: `MRSIGNER`[cite: 151], `ISVPRODID`[cite: 151], `MISCSELECT` (with mask)[cite: 152, 153],
`ATTRIBUTES` (with mask)[cite: 154, 155].
3. If any fails, no match[cite: 155].
4. Determine TCB status via ISVSVN comparison[cite: 157, 158].
#### GET `https://api.trustedservices.intel.com/sgx/certification/v3/qae/identity`
**Request**: Same parameters as `Get Quoting Enclave Identity V3` (`update` and `tcbEvaluationDataNumber`)[cite: 160].
**Response**: QAEIdentityV2 (JSON) - QAE Identity data[cite: 161]. Structure similar to QE
Identity[cite: 162, 163, 164, 165, 166, 167, 168, 169, 170].
**Status Codes**: Similar to `Get Quoting Enclave Identity V3`[cite: 171, 174].
-----
### PCK Certificate and CRL Specification
This document specifies the hierarchy and format of X.509 v3 certificates and v2 CRLs for Provisioning Certification
Keys[cite: 175].
Enforcement of a mitigation means the attestation process can detect its presence and the result will differ[cite: 175].
Intel offers `standard` (default) and `early` update parameters, affecting when enforcement occurs[cite: 176]. The
attestation result is an objective assessment[cite: 177]. Relying parties can use additional factors [cite: 178] and may
choose to trust an 'OutOfDate' platform, accepting risks[cite: 180]. Intel will strive to communicate schedule
deviations[cite: 181].

View file

@ -0,0 +1,664 @@
This document outlines the API for Intel® SGX and Intel® TDX services, focusing on platform registration and
provisioning certification using ECDSA attestation.
## Intel® SGX and Intel® TDX Registration Service for Scalable Platforms [cite: 1]
The Intel® SGX and Intel® TDX Registration Service API enables the registration of Intel® SGX platforms with multiple
processor packages as a unified platform instance[cite: 2]. This allows these platforms to be remotely attested as a
single entity[cite: 2]. It is important to note that the service enforces a minimum TLS protocol version of 1.2; any
attempts to connect with older TLS/SSL versions will be rejected[cite: 3].
### Register Platform
This API facilitates the registration of multi-package SGX platforms, encompassing both initial registration and TCB (
Trusted Computing Base) recovery[cite: 4]. During this process, the Registration Service authenticates the platform
manifest to confirm it originates from a genuine, non-revoked SGX platform[cite: 4]. If the platform configuration
passes verification, its provisioning root keys are securely stored[cite: 4]. These stored keys are subsequently used to
derive the public components of Provisioning Certification Keys (PCKs), which are then distributed as X.509 certificates
by the Provisioning Certification Service[cite: 5]. These PCK certificates are integral to the remote attestation
process for the platform[cite: 5].
**POST** `https://api.trustedservices.intel.com/sgx/registration/v1/platform`
**Request**
* **Headers**: In addition to standard HTTP headers (like `Content-Length`), the following is required[cite: 1]:
| Name | Required | Value | Description |
|:-------------|:---------|:-------------------------|:----------------------------------------|
| Content-Type | True | application/octet-stream | MIME type of the request body[cite: 1]. |
* **Body**: The request body must be a binary representation of the Platform Manifest structure[cite: 6]. This is an
opaque blob containing the registration manifest for a multi-package platform[cite: 6]. It includes the platform
provisioning root keys established by the platform instance and the necessary data to authenticate it as a genuine,
non-revoked SGX platform[cite: 6].
* **Example Request**:
```bash
curl -v -X POST "Content-Type: application/octet-stream" --data-binary @platform_manifest.bin "https://api.trustedservices.intel.com/sgx/registration/v1/platform" [cite: 1]
```
**Response**
* **Model**: The response body will contain the hex-encoded representation of the PPID (Platform Provisioning ID) for
the registered platform instance, but only if the HTTP Status Code is 201[cite: 1]. Otherwise, the body will be
empty[cite: 1].
* **Example Response**:
```
00112233445566778899AABBCCDDEEFF [cite: 1]
```
* **Status Codes**:
| Code | Headers | Body | Description |
|:-----|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------|:--------------------------------------------------------------------------------------------------|
| 201 | `Request-ID`: Randomly generated identifier for troubleshooting[cite: 7]. | Hex-encoded PPID | Operation successful; a new platform instance has been registered[cite: 7]. |
| 400 | `Request-ID`: Randomly generated identifier[cite: 8]. `Error-Code` & `Error-Message`: Details on the error (e.g., `InvalidRequestSyntax`, `InvalidRegistrationServer`, `InvalidOrRevokedPackage`, `PackageNotFound`, `IncompatiblePackage`, `InvalidPlatformManifest`, `CachedKeysPolicyViolation`)[cite: 8]. | | Invalid Platform Manifest[cite: 10]. The client should not retry without modifications[cite: 10]. |
| 415 | `Request-ID`: Randomly generated identifier[cite: 8]. | | The MIME type specified in the request is not supported[cite: 8]. |
| 500 | `Request-ID`: Randomly generated identifier[cite: 8]. | | An internal server error occurred[cite: 8]. |
| 503 | `Request-ID`: Randomly generated identifier[cite: 8]. | | The server is currently unable to process the request; try again later[cite: 8]. |
### Add Package
This API allows for adding new processor packages to an already registered platform instance[cite: 11]. Upon successful
execution, a Platform Membership Certificate is generated for each processor package included in the Add
Request[cite: 11]. This requires a subscription for registration[cite: 11].
**POST** `https://api.trustedservices.intel.com/sgx/registration/v1/package`
**Request**
* **Headers**: Besides standard headers like `Content-Length`[cite: 12], the following are needed:
| Name | Required | Value | Description |
|:--------------------------|:---------|:-------------------------|:------------------------------------------------------------------|
| Ocp-Apim-Subscription-Key | True | *Your Subscription Key* | Subscription key for API access, found in your profile[cite: 12]. |
| Content-Type | True | application/octet-stream | MIME type of the request body[cite: 12]. |
* **Body**: A binary representation of the Add Request structure, an opaque blob for adding new packages to an existing
platform[cite: 13].
* **Example Request**:
```bash
curl -v -X POST "Content-Type: application/octet-stream" --data-binary @add_package_request.bin "https://api.trustedservices.intel.com/sgx/registration/v1/package" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 14]
```
**Response**
* **Model**: For a 200 HTTP Status Code, the response is a fixed-size array (8 elements) containing binary Platform
Membership Certificate structures appended together[cite: 14]. Certificates fill the array sequentially, starting from
index 0, with remaining elements zeroed out[cite: 14].
* **Example Response (hex-encoded)**:
```
E8BDBECFEF9040184488777267355084...00000000 [cite: 15]
```
* **Status Codes**:
| Code | Headers | Body | Description |
|:-----|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------|
| 200 | `Content-Type`: application/octet-stream[cite: 18]. `Request-ID`: Randomly generated identifier[cite: 18]. `Certificate-Count`: Number of certificates returned[cite: 18]. | Fixed-size array (8 elements) with binary Platform Membership Certificates[cite: 18, 19]. | Operation successful; packages added to the platform[cite: 18]. |
| 400 | `Request-ID`: Randomly generated identifier[cite: 18]. `Error-Code` & `Error-Message`: Details on the error (e.g., `InvalidRequestSyntax`, `PlatformNotFound`, `InvalidOrRevokedPackage`, `PackageNotFound`[cite: 17], `InvalidAddRequest`)[cite: 18]. | | Invalid Add Request Payload[cite: 20]. Do not retry without modifications[cite: 20]. |
| 401 | `Request-ID`: Randomly generated identifier[cite: 18]. | | Failed to authenticate or authorize the request[cite: 18]. |
| 415 | `Request-ID`: Randomly generated identifier[cite: 18]. | | The MIME type specified is not supported[cite: 18]. |
| 500 | `Request-ID`: Randomly generated identifier[cite: 18]. | | Internal server error occurred[cite: 18]. |
| 503 | `Request-ID`: Randomly generated identifier[cite: 18]. | | Server is currently unable to process the request[cite: 18]. |
## Intel® SGX and Intel® TDX Provisioning Certification Service for ECDSA Attestation [cite: 21]
This service provides PCK certificates. You can download the Provisioning Certification Root CA Certificate (v4) in both
DER and PEM formats[cite: 21].
### Get/Post PCK Certificate V4
This API allows requesting a single PCK certificate. It offers two primary methods:
1. **Using PPID and SVNs**:
* **Single-socket platforms**: No prerequisites[cite: 22].
* **Multi-socket platforms**: Requires prior platform registration via the Register Platform API[cite: 22]. This
flow necessitates that platform root keys are persistently stored in the backend[cite: 23], and the Keys Caching
Policy must be `true`[cite: 23].
2. **Using Platform Manifest and SVNs**:
* **Multi-socket platforms**: Does *not* require prior registration[cite: 24]. Platform root keys are *not* required
to be persistently stored[cite: 24]. The Keys Caching Policy determines whether keys are stored or not[cite: 25].
* **Direct Registration (via Register Platform API)**: Keys are always stored; `CachedKeys` flag in PCK
certificates is `true`[cite: 26, 27].
* **Indirect Registration (via Get PCK Certificate(s) API)**: Keys are never stored; `CachedKeys` flag is
`false`[cite: 28, 30]. Register Platform API cannot be used afterward[cite: 29].
**Note**: The PCS returns the PCK Certificate representing the highest TCB security level based on the CPUSVN and PCE
ISVSVN inputs[cite: 31].
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcert`
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:-------------------|:--------------------------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 32]. |
| PPID-Encryption-Key | String | Header | False | | Key type for PPID encryption (default: "RSA-3072")[cite: 32]. |
| encrypted_ppid | String | Query | True | `[0-9a-fA-F]{768}` | Base16-encoded encrypted PPID[cite: 32]. |
| cpusvn | String | Query | True | `[0-9a-fA-F]{32}` | Base16-encoded CPUSVN[cite: 32]. |
| pcesvn | String | Query | True | `[0-9a-fA-F]{4}` | Base16-encoded PCESVN (little endian)[cite: 32]. |
| pceid | String | Query | True | `[0-9a-fA-F]{4}` | Base16-encoded PCE-ID (little endian)[cite: 32]. |
* **Example Request**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcert?encrypted_ppid={encrypted_ppid}&cpusvn={cpusvn}&pcesvn={pcesvn}&pceid={pceid}" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 33]
```
**POST** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcert`
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:----------------------------|:-------------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 33]. |
| Content-Type | String | Header | True | `application/json` | Content type[cite: 35]. |
| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16862,112884}` | Base16-encoded Platform Manifest[cite: 35]. |
| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}` | Base16-encoded CPUSVN[cite: 35]. |
| pcesvn | String | Body Field | True | `[0-9a-fA-F]{4}` | Base16-encoded PCESVN (little endian)[cite: 35]. |
| pceid | String | Body Field | True | `[0-9a-fA-F]{4}` | Base16-encoded PCE-ID (little endian)[cite: 35]. |
* **Body**:
```json
{
"platformManifest": "...", [cite: 36]
"cpusvn": "...", [cite: 36]
"pcesvn": "...", [cite: 36]
"pceid": "..." [cite: 36]
}
```
* **Example Request**:
```bash
curl -v -X POST --data '{"platformManifest":"...","cpusvn":"...","pcesvn":"...","pceid":"..."}' "https://api.trustedservices.intel.com/sgx/certification/v4/pckcert" -H "Ocp-Apim-Subscription-Key: {subscription_key}" -H "Content-Type: application/json" [cite: 36]
```
**Response (Both GET & POST)**
* **Model**: `PckCert (X-PEM-FILE)` - PEM-encoded SGX PCK Certificate[cite: 36].
* **Example Response**:
```pem
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE----- [cite: 36]
```
* **Status Codes**:
| Code | Model | Headers | Description |
|:-----|:--------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------|
| 200 | PckCert | `Content-Type`: application/x-pem-file[cite: 37]. `Request-ID`: Identifier[cite: 37]. `SGX-PCK-Certificate-Issuer-Chain`: PEM-encoded Issuer Chain[cite: 37]. `SGX-TCBm`: Hex-encoded CPUSVN & PCESVN[cite: 37]. `SGX-FMSPC`: Hex-encoded FMSPC[cite: 37]. `SGX-PCK-Certificate-CA-Type`: "processor" or "platform"[cite: 37]. `Warning` (Optional)[cite: 37]. | Operation successful[cite: 37]. |
| 400 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. `Error-Code` & `Error-Message` (e.g., `InvalidRequestSyntax`, `InvalidRegistrationServer`, `InvalidOrRevokedPackage`, `PackageNotFound`, `IncompatiblePackage`, `InvalidPlatformManifest`)[cite: 37]. | Invalid request parameters[cite: 37]. |
| 401 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. | Failed to authenticate or authorize[cite: 37]. |
| 404 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. | PCK Certificate not found (e.g., unsupported PPID/PCE-ID, TCB below minimum, Platform Manifest not registered/updated)[cite: 37]. |
| 429 | | `Retry-After`: Wait time in seconds[cite: 37]. `Warning` (Optional)[cite: 37]. | Too many requests[cite: 37]. |
| 500 | | `Request-ID`: Identifier[cite: 37]. `Warning` (Optional)[cite: 37]. | Internal server error[cite: 37]. |
| 503 | | `Request-ID`: Identifier[cite: 39]. `Warning` (Optional)[cite: 39]. | Server is currently unable to process[cite: 39]. |
### Get PCK Certificates V4
This API retrieves PCK certificates for *all* configured TCB levels for a platform. The usage conditions (single-socket
vs. multi-socket, PPID vs. Platform Manifest, key caching) are similar to the single PCK certificate
API[cite: 40, 41, 42, 43, 44, 45, 46, 47, 48].
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts` (Using PPID & PCE-ID)
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:-------------------|:------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 49]. |
| PPID-Encryption-Key | String | Header | False | | Key type (default: "RSA-3072")[cite: 49]. |
| encrypted_ppid | String | Query | True | `[0-9a-fA-F]{768}` | Encrypted PPID[cite: 49]. |
| pceid | String | Query | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 49]. |
* **Example Request**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts?encrypted_ppid={...}&pceid={...}" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 50]
```
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config` (Using PPID, PCE-ID &
CPUSVN) [cite: 51]
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:-------------------|:------------------------------------------|
| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 52]. |
| PPID-Encryption-Key | String | Header | False | | Key type (default: "RSA-3072")[cite: 52]. |
| encrypted_ppid | String | Query | True | `[0-9a-fA-F]{768}` | Encrypted PPID[cite: 52]. |
| pceid | String | Query | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 52]. |
| cpusvn | String | Query | True | `[0-9a-fA-F]{32}` | CPUSVN[cite: 52]. |
* **Example Request**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config?encrypted_ppid={...}&pceid={...}&cpusvn={...}" -H "Ocp-Apim-Subscription-Key: {subscription_key}" [cite: 53]
```
**POST** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts` (Using Platform Manifest & PCE-ID)
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:----------------------------|:-----------------------------|
| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 54]. |
| Content-Type | String | Header | True | `application/json` | Content type[cite: 54]. |
| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16862,112884}` | Platform Manifest[cite: 54]. |
| pceid | String | Body Field | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 54]. |
* **Body**:
```json
{
"platformManifest": "...", [cite: 55]
"pceid": "..." [cite: 55]
}
```
* **Example Request**:
```bash
curl -v -X POST --data '{"platformManifest":"...","pceid":"..."}' "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts" -H "Ocp-Apim-Subscription-Key: {subscription_key}" -H "Content-Type: application/json" [cite: 55]
```
**POST** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config` (Using Platform Manifest, PCE-ID &
CPUSVN)
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:--------------------------|:-------|:-------------|:---------|:----------------------------|:-----------------------------|
| Ocp-Apim-Subscription-Key | String | Header | False | | Subscription key[cite: 56]. |
| Content-Type | String | Header | True | `application/json` | Content type[cite: 57]. |
| platformManifest | String | Body Field | True | `[0-9a-fA-F]{16862,112884}` | Platform Manifest[cite: 56]. |
| cpusvn | String | Body Field | True | `[0-9a-fA-F]{32}` | CPUSVN[cite: 56]. |
| pceid | String | Body Field | True | `[0-9a-fA-F]{4}` | PCE-ID[cite: 56]. |
* **Body**:
```json
{
"platformManifest": "...", [cite: 57]
"cpusvn": "...", [cite: 57]
"pceid": "..." [cite: 57]
}
```
* **Example Request**:
```bash
curl -v -X POST --data '{"platformManifest":"...","cpusvn":"...","pceid":"..."}' "https://api.trustedservices.intel.com/sgx/certification/v4/pckcerts/config" -H "Ocp-Apim-Subscription-Key: {subscription_key}" -H "Content-Type: application/json" [cite: 57]
```
**Response (All GET & POST for multiple certs)**
* **Model**: `PckCerts` (JSONArray of objects, each containing `tcb`, `tcbm`, and `cert`)[cite: 56].
* `tcb`: Object with 16 `sgxtcbcompXXsvn` fields (integer 0-255) and `pcesvn` (integer 0-65535)[cite: 59].
* `tcbm`: Hex-encoded string of CPUSVN (16 bytes) and PCESVN (2 bytes)[cite: 7].
* `cert`: URL-encoded PEM PCK Certificate, or "Not available" string[cite: 60].
* **Example Response**:
```json
[
{
"tcb": {
"sgxtcbcomp01svn": 3,
"sgxtcbcomp02svn": 1,
...
"pcesvn": 11
},
"tcbm": "...",
"cert": "-----BEGIN%20CERTIFICATE-----%0A...%0A-----END%20CERTIFICATE-----" [cite: 61]
},
...
]
```
* **Status Codes**:
| Code | Model | Headers | Description |
|:-----|:---------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------|
| 200 | PckCerts | `Content-Type`: application/json[cite: 8]. `Request-ID`: Identifier[cite: 8]. `SGX-PCK-Certificate-Issuer-Chain`: Issuer Chain[cite: 62]. `SGX-FMSPC`: FMSPC[cite: 8]. `SGX-PCK-Certificate-CA-Type`: "processor" or "platform"[cite: 63]. `Warning` (Optional)[cite: 8]. | Operation successful[cite: 8]. |
| 400 | | `Request-ID`: Identifier[cite: 8]. `Warning` (Optional)[cite: 8]. `Error-Code` & `Error-Message` (e.g., `InvalidRequestSyntax`[cite: 65], `InvalidRegistrationServer`[cite: 65], `InvalidOrRevokedPackage`[cite: 65], `PackageNotFound`[cite: 65], `IncompatiblePackage`[cite: 65], `InvalidPlatformManifest` [cite: 66]) | Invalid request parameters[cite: 8]. |
| 401 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | Failed to authenticate or authorize[cite: 68]. |
| 404 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | PCK Certificate not found (e.g., unsupported PPID/PCE-ID, Platform Manifest not registered)[cite: 68]. |
| 429 | | `Retry-After`: Wait time[cite: 68]. `Warning` (Optional)[cite: 68]. | Too many requests[cite: 68]. |
| 500 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | Internal server error[cite: 68]. |
| 503 | | `Request-ID`: Identifier[cite: 68]. `Warning` (Optional)[cite: 68]. | Server is currently unable to process[cite: 68]. |
### Get Revocation List V4
This API retrieves the X.509 Certificate Revocation List (CRL) for revoked SGX PCK Certificates, issued by either the
Intel SGX Processor CA or Platform CA[cite: 69, 70].
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl` [cite: 71]
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:---------|:-------|:-------------|:---------|:------------|:------------|
| ca | String | Query | True | `(processor | platform)` | CA identifier ("processor" or "platform")[cite: 71, 72]. |
| encoding | String | Query | False | `(pem | der)` | CRL encoding (default: PEM)[cite: 71]. |
* **Example Request**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform&encoding=pem" [cite: 71]
```
**Response**
* **Model**: `PckCrl` (X-PEM-FILE or PKIX-CRL) - PEM or DER encoded CRL[cite: 71].
* **Example Response**:
```pem
-----BEGIN X509 CRL-----
...
-----END X509 CRL----- [cite: 71]
```
* **Status Codes**:
| Code | Model | Headers | Description |
|:-----|:-------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------|
| 200 | PckCrl | `Content-Type`: "application/x-pem-file" or "application/pkix-crl"[cite: 71]. `Request-ID`: Identifier[cite: 71]. `SGX-PCK-CRL-Issuer-Chain`: Issuer Chain[cite: 73]. `Warning` (Optional)[cite: 71]. | Operation successful[cite: 71]. |
| 400 | | `Request-ID`: Identifier[cite: 71]. `Warning` (Optional)[cite: 71]. | Invalid request parameters[cite: 71]. |
| 401 | | `Request-ID`: Identifier[cite: 74]. `Warning` (Optional)[cite: 74]. | Failed to authenticate or authorize[cite: 74]. |
| 500 | | `Request-ID`: Identifier[cite: 74]. `Warning` (Optional)[cite: 74]. | Internal server error[cite: 74]. |
| 503 | | `Request-ID`: Identifier[cite: 74]. `Warning` (Optional)[cite: 74]. | Server is currently unable to process[cite: 74]. |
### Get SGX TCB Info V4
This API retrieves SGX TCB information for a specific FMSPC, which is crucial for determining the TCB status of a
platform[cite: 75]. The process involves:
1. Retrieving the FMSPC from the SGX PCK Certificate[cite: 75].
2. Fetching the corresponding SGX TCB info[cite: 76].
3. Iterating through the TCB Levels:
* Comparing all 16 SGX TCB Comp SVNs from the certificate against the TCB Level; they must be >=[cite: 77, 78].
* Comparing the PCESVN from the certificate against the TCB Level; it must be >=[cite: 79, 80]. If both match, the
TCB level's status is found[cite: 80].
4. If no match is found, the TCB level is unsupported[cite: 82].
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/tcb` [cite: 82]
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:------------------------|:-------|:-------------|:---------|:------------------|:-------------------------------------------------------------------------------------------------------|
| fmspc | String | Query | True | `[0-9a-fA-F]{12}` | Base16-encoded FMSPC[cite: 83]. |
| update | String | Query | False | `(early | standard)` | TCB Info update type (default: standard). `early` provides access sooner than `standard`[cite: 83]. Cannot be used with `tcbEvaluationDataNumber`[cite: 83]. |
| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Retrieves TCB info for a specific evaluation number[cite: 83]. Cannot be used with `update`[cite: 83]. |
* **Example Requests**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc={fmspc_value}&update=early" [cite: 84]
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc={fmspc_value}&tcbEvaluationDataNumber={number}" [cite: 84]
```
**Response**
* **Model**: `Appendix A: TCB info V3`[cite: 86]. (See Appendix A below).
* **Example Response**: (JSON structure as shown in the document)[cite: 85].
* **Status Codes**:
| Code | Model | Headers | Description |
|:-----|:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------|
| 200 | TcbInfoV3 | `Content-Type`: application/json[cite: 86]. `Request-ID`: Identifier[cite: 86]. `TCB-Info-Issuer-Chain`: Issuer Chain[cite: 86]. `Warning` (Optional)[cite: 86]. | Operation successful[cite: 86]. |
| 400 | | `Request-ID`: Identifier[cite: 86]. `Warning` (Optional)[cite: 86]. | Invalid request (bad `fmspc`, invalid params, or `update` & `tcbEvaluationDataNumber` used together)[cite: 86]. |
| 401 | | `Request-ID`: Identifier[cite: 86]. `Warning` (Optional)[cite: 87]. | Failed to authenticate or authorize[cite: 86]. |
| 404 | | `Request-ID`: Identifier[cite: 86]. `Warning` (Optional)[cite: 87]. | TCB info not found for the given `fmspc` or `tcbEvaluationDataNumber`[cite: 86]. |
| 410 | | `Request-ID`: Identifier[cite: 88]. `Warning` (Optional)[cite: 88]. | TCB info for the provided `tcbEvaluationDataNumber` is no longer available[cite: 88]. |
| 500 | | `Request-ID`: Identifier[cite: 88]. `Warning` (Optional)[cite: 88]. | Internal server error[cite: 88]. |
| 503 | | `Request-ID`: Identifier[cite: 88]. `Warning` (Optional)[cite: 88]. | Server currently unable to process[cite: 88]. |
### Get TDX TCB Info V4
This API retrieves TDX TCB information[cite: 89]. The TCB status determination follows a similar process to SGX but
includes additional steps for TDX TEE TCB SVNs and TDX Module
Identity[cite: 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102].
**GET** `https://api.trustedservices.intel.com/tdx/certification/v4/tcb` [cite: 102]
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:------------------------|:-------|:-------------|:---------|:------------------|:---------------------------------------------------------------------------------------------------------|
| fmspc | String | Query | True | `[0-9a-fA-F]{12}` | Base16-encoded FMSPC[cite: 103]. |
| update | String | Query | False | `(early | standard)` | TCB Info update type (default: standard)[cite: 103]. Cannot be used with `tcbEvaluationDataNumber`[cite: 103]. |
| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Retrieves TCB info for a specific evaluation number[cite: 103]. Cannot be used with `update`[cite: 103]. |
* **Example Requests**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc={fmspc_value}&update=early" [cite: 104]
curl -v -X GET "https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc={fmspc_value}&tcbEvaluationDataNumber={number}" [cite: 104]
```
**Response**
* **Model**: `Appendix A: TCB info V3`[cite: 107]. (See Appendix A below).
* **Example Response**: (JSON structure including `tdxModule` and `tdxtcbcomponents` as shown in the
document)[cite: 105, 106].
* **Status Codes**: Similar to Get SGX TCB Info V4[cite: 108].
### Enclave Identity V4
This set of APIs allows for determining if an SGX Enclave's identity matches Intel's published identity[cite: 109]. The
process involves:
1. Retrieving the Enclave Identity (SGX QE, TDX QE, QVE, or QAE)[cite: 109].
2. Comparing `MRSIGNER` and `ISVPRODID` fields[cite: 109].
3. Applying `miscselectMask` and `attributesMask` and comparing the results[cite: 111, 112, 113, 114].
4. If checks pass, determining the TCB status by finding the highest TCB Level (sorted by ISVSVN) whose ISVSVN is <= the
Enclave Report's ISVSVN[cite: 116, 117].
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/qe/identity` [cite: 118]
**GET** `https://api.trustedservices.intel.com/tdx/certification/v4/qe/identity` [cite: 128]
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/qve/identity` [cite: 133]
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/qae/identity` [cite: 138]
* **Request**:
| Name | Type | Request Type | Required | Pattern | Description |
|:------------------------|:-------|:-------------|:---------|:--------|:--------------------------------------------------------------------------------------------------------------------------------------------|
| update | String | Query | False | `(early | standard)` | Identity update type (default: standard)[cite: 118, 127, 132, 137]. Cannot be used with `tcbEvaluationDataNumber`[cite: 118, 121, 127, 132, 137]. |
| tcbEvaluationDataNumber | Number | Query | False | `\d+` | Retrieves Identity for a specific evaluation number[cite: 119, 120, 127, 132, 137]. Cannot be used with `update`[cite: 121, 127, 132, 137]. |
* **Example Requests** (SGX QE shown):
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/qe/identity?update=early" [cite: 122]
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/qe/identity?tcbEvaluationDataNumber={number}" [cite: 122]
```
**Response**
* **Model**: `Appendix B: Enclave Identity V2`[cite: 122, 128, 134, 139]. (See Appendix B below).
* **Example Response**: (JSON structure as shown in the document for QE[cite: 125], TDX QE[cite: 131], QVE[cite: 136],
and QAE [cite: 141]).
* **Status Codes** (SGX QE shown, others are similar):
| Code | Model | Headers | Description |
|:-----|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------|
| 200 | EIdentityV2 | `Content-Type`: application/json[cite: 122]. `Request-ID`: Identifier[cite: 122]. `SGX-Enclave-Identity-Issuer-Chain`: Issuer Chain[cite: 122]. `Warning` (Optional)[cite: 122]. | Operation successful[cite: 122]. |
| 400 | | `Request-ID`: Identifier[cite: 122]. `Warning` (Optional)[cite: 122]. | Invalid request (params or `update` & `tcbEvaluationDataNumber` conflict)[cite: 122]. |
| 401 | | `Request-ID`: Identifier[cite: 123]. `Warning` (Optional)[cite: 123]. | Failed to authenticate or authorize[cite: 122]. |
| 404 | | `Request-ID`: Identifier[cite: 123]. `Warning` (Optional)[cite: 123]. | Identity info not found[cite: 122]. |
| 410 | | `Request-ID`: Identifier[cite: 124]. `Warning` (Optional)[cite: 124]. | Identity info no longer available[cite: 124]. |
| 500 | | `Request-ID`: Identifier[cite: 124]. `Warning` (Optional)[cite: 124]. | Internal server error[cite: 124]. |
| 503 | | `Request-ID`: Identifier[cite: 124]. `Warning` (Optional)[cite: 124]. | Server currently unable to process[cite: 124]. |
### Retrieve FMSPCs V4
Retrieves a list of FMSPC values for SGX and TDX platforms that support DCAP attestation[cite: 141].
**GET** `https://api.trustedservices.intel.com/sgx/certification/v4/fmspcs` [cite: 141]
* **Request**:
| Name | Type | Request Type | Required | Description |
|:---------|:-------|:-------------|:---------|:----------------------------------------------------------------------------|
| platform | String | Query | False | Optional platform filter: `all` (default), `client`, `E3`, `E5`[cite: 141]. |
* **Example Request**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/fmspcs?platform=E5" [cite: 141]
```
**Response**
* **Example Response**:
```json
[
{"platform": "E3", "fmspc": "123456789000"}, [cite: 142]
{"platform": "E5", "fmspc": "987654321000"}, [cite: 142]
{"platform": "client", "fmspc": "ABCDEF123456"} [cite: 142]
]
```
* **Status Codes**:
| Code | Headers | Description |
|:-----|:-------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------|
| 200 | `Content-Type`: application/json[cite: 142]. `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 142]. | Operation successful[cite: 142]. |
| 400 | `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 143]. | Invalid request parameters[cite: 142]. |
| 500 | `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 142]. | Internal server error[cite: 142]. |
| 503 | `Request-ID`: Identifier[cite: 142]. `Warning` (Optional)[cite: 142]. | Server currently unable to process[cite: 142]. |
### Retrieve TCB Evaluation Data Numbers V4
Retrieves the list of currently supported TCB Evaluation Data Numbers and their associated TCB-R event
states[cite: 142].
**GET** `https://api.trustedservices.intel.com/{sgx|tdx}/certification/v4/tcbevaluationdatanumbers` [cite: 142]
* **Example Requests**:
```bash
curl -v -X GET "https://api.trustedservices.intel.com/sgx/certification/v4/tcbevaluationdatanumbers" [cite: 142]
curl -v -X GET "https://api.trustedservices.intel.com/tdx/certification/v4/tcbevaluationdatanumbers" [cite: 142]
```
**Response**
* **Model**: `Appendix C: TCB Evaluation Data Numbers V1`[cite: 144]. (See Appendix C below).
* **Example Response**:
```json
{
"tcbEvaluationDataNumbers": {
"version": 1,
"issueDate": "2023-04-13T09:38:17Z",
"nextUpdate": "2023-05-13T09:38:17Z",
"tcbNumbers": [
{"tcbEvaluationDataNumber": 12, "tcbRecoveryEventDate": "2023-04-13T00:00:00Z", "tcbDate": "2023-04-13T00:00:00Z"},
{"tcbEvaluationDataNumber": 11, "tcbRecoveryEventDate": "2023-01-14T00:00:00Z", "tcbDate": "2023-01-14T00:00:00Z"}
],
"signature": "..." [cite: 142]
}
}
```
* **Status Codes**:
| Code | Headers | Description |
|:-----|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------|
| 200 | `Content-Type`: application/json[cite: 144]. `Request-ID`: Identifier[cite: 144]. `TCB-Evaluation-Data-Numbers-Issuer-Chain`: Issuer Chain[cite: 145]. `Warning` (Optional)[cite: 144]. | Operation successful[cite: 144]. |
| 500 | `Request-ID`: Identifier[cite: 144]. `Warning` (Optional)[cite: 144]. | Internal server error[cite: 144]. |
| 503 | `Request-ID`: Identifier[cite: 144]. `Warning` (Optional)[cite: 144]. | Server currently unable to process[cite: 146]. |
---
## Appendix A: TCB Info V3 [cite: 147]
This defines the structure of the TCB Info V3 JSON response[cite: 147].
* `tcbInfo`: (Object)
* `id`: (String) Identifier (e.g., "SGX", "TDX")[cite: 148].
* `version`: (Integer) Structure version[cite: 148].
* `issueDate`: (String - datetime) Creation timestamp (ISO 8601 UTC)[cite: 148].
* `nextUpdate`: (String - datetime) Next update timestamp (ISO 8601 UTC)[cite: 149].
* `fmspc`: (String) Base16-encoded FMSPC[cite: 149].
* `pceId`: (String) Base16-encoded PCE ID[cite: 149].
* `tcbType`: (Integer) TCB level composition type[cite: 149].
* `tcbEvaluationDataNumber`: (Integer) Monotonically increasing sequence number, synchronized across TCB Info and
Enclave Identities, indicating updates[cite: 150, 151, 152].
* `tdxModule`: (Object - Optional, only for TDX TCB Info)[cite: 153].
* `mrsigner`: (String) Base16-encoded TDX SEAM module's signer measurement[cite: 154].
* `attributes`: (String) Base16-encoded "golden" attributes[cite: 154].
* `attributesMask`: (String) Base16-encoded attributes mask[cite: 154].
* `tdxModuleIdentities`: (Array - Optional, for multiple TDX SEAM Modules)[cite: 154].
* `id`: (String) Module identifier[cite: 154].
* `mrsigner`: (String) Base16-encoded signer measurement[cite: 155].
* `attributes`: (String) Base16-encoded "golden" attributes[cite: 155].
* `attributesMask`: (String) Base16-encoded attributes mask[cite: 156].
* `tcbLevels`: (Array) Sorted list of TCB levels for this module[cite: 157].
* `tcb`: (Object)
* `isvsvn`: (Integer) ISV SVN[cite: 157].
* `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 158].
* `tcbStatus`: (String) "UpToDate", "OutOfDate", or "Revoked"[cite: 158].
* `advisoryIDs`: (Array - Optional) List of relevant `INTEL-SA-XXXXX` or `INTEL-DOC-XXXXX`
identifiers[cite: 159, 160].
* `tcbLevels`: (Array) Sorted list of TCB levels for the FMSPC[cite: 160].
* `tcb`: (Object)
* `sgxtcbcomponents`: (Array - Optional) 16 SGX TCB Components (SVN, Category, Type)[cite: 161].
* `tdxtcbcomponents`: (Array - Optional, only for TDX TCB Info) 16 TDX TCB Components (SVN, Category,
Type)[cite: 161, 162, 164].
* `pcesvn`: (Integer) PCE SVN[cite: 161].
* `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 165].
* `tcbStatus`: (String) "UpToDate", "HardeningNeeded", "ConfigurationNeeded", "
ConfigurationAndHardeningNeeded", "OutOfDate", "OutOfDateConfigurationNeeded", "Revoked"[cite: 165, 166].
* `advisoryIDs`: (Array - Optional) List of relevant `INTEL-SA-XXXXX` or `INTEL-DOC-XXXXX`
identifiers[cite: 167, 168].
* `signature`: (String) Base16-encoded signature over the `tcbInfo` body[cite: 163].
---
## Appendix B: Enclave Identity V2 [cite: 168]
This defines the structure of the Enclave Identity V2 JSON response[cite: 168].
* `enclaveIdentity`: (Object)
* `id`: (String) Identifier ("QE", "QVE", "QAE", "TD_QE")[cite: 169].
* `version`: (Integer) Structure version[cite: 169].
* `issueDate`: (String - datetime) Creation timestamp (ISO 8601 UTC)[cite: 170].
* `nextUpdate`: (String - datetime) Next update timestamp (ISO 8601 UTC)[cite: 170].
* `tcbEvaluationDataNumber`: (Integer) Monotonically increasing sequence number, synchronized across TCB Info and
Enclave Identities[cite: 171, 172].
* `miscselect`: (String) Base16-encoded "golden" miscselect value[cite: 172].
* `miscselectMask`: (String) Base16-encoded miscselect mask[cite: 172].
* `attributes`: (String) Base16-encoded "golden" attributes value[cite: 172].
* `attributesMask`: (String) Base16-encoded attributes mask[cite: 173].
* `mrsigner`: (String) Base16-encoded mrsigner hash[cite: 173].
* `isvprodid`: (Integer) Enclave Product ID[cite: 173].
* `tcbLevels`: (Array) Sorted list of Enclave TCB levels[cite: 173].
* `tcb`: (Object)
* `isvsvn`: (Integer) Enclave's ISV SVN[cite: 173].
* `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 174].
* `tcbStatus`: (String) "UpToDate", "OutOfDate", or "Revoked"[cite: 174, 176].
* `advisoryIDs`: (Array - Optional) List of relevant `INTEL-SA-XXXXX` or `INTEL-DOC-XXXXX`
identifiers[cite: 177].
* `signature`: (String) Base16-encoded signature over the `enclaveIdentity` body[cite: 175].
---
## Appendix C: TCB Evaluation Data Numbers V1 [cite: 177]
This defines the structure of the TCB Evaluation Data Numbers V1 JSON response[cite: 177].
* `tcbEvaluationDataNumbers`: (Object)
* `id`: (String) Identifier ("SGX" or "TDX")[cite: 178].
* `version`: (Integer) Structure version[cite: 178].
* `issueDate`: (String - datetime) Creation timestamp (ISO 8601 UTC)[cite: 178].
* `nextUpdate`: (String - datetime) Suggested next call timestamp (ISO 8601 UTC)[cite: 179].
* `tcbNumbers`: (Array) List of TCB Evaluation Data Number objects[cite: 179].
* `tcbEvaluationDataNumber`: (Integer) The number itself[cite: 179].
* `tcbRecoveryEventDate`: (String - datetime) The date Intel first publishes related collateral (ISO 8601
UTC)[cite: 179].
* `tcbDate`: (String - datetime) TCB date (ISO 8601 UTC)[cite: 180, 181].
* `signature`: (String) Base16-encoded signature over the structure's body[cite: 181].
---
## Appendix D: PCK Certificate and CRL Specification
This section refers to an external document that specifies the hierarchy and format of X.509 v3 certificates and X.509
v2 CRLs issued by Intel for Provisioning Certification Keys[cite: 181].
---
**Notes on TCB Status and Enforcement:**
* **Enforcement Grace Periods**: Intel provides "early" and "standard" update parameters, offering different enforcement
grace periods[cite: 182]. The attestation result depends on which parameter is used[cite: 182].
* **Relying Party Trust Decisions**: Relying parties can use additional factors beyond the attestation result to make
trust decisions[cite: 183]. They might accept risks even if a platform is technically "OutOfDate" due to low-severity
issues[cite: 184].
* **Communication**: Intel aims to communicate planned deviations via email to registered API subscribers[cite: 185].

View file

@ -46,7 +46,7 @@ impl ApiClient {
} }
let request_builder = self.client.get(url); let request_builder = self.client.get(url);
let response = request_builder.send().await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::OK]).await?; let response = check_status(response, &[StatusCode::OK]).await?;
let fmspcs_json = response.text().await?; let fmspcs_json = response.text().await?;

View file

@ -12,6 +12,8 @@ use crate::{
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use reqwest::{RequestBuilder, Response, StatusCode}; use reqwest::{RequestBuilder, Response, StatusCode};
use std::io; use std::io;
use std::time::Duration;
use tokio::time::sleep;
impl ApiClient { impl ApiClient {
/// Helper to construct API paths dynamically based on version and technology (SGX/TDX). /// Helper to construct API paths dynamically based on version and technology (SGX/TDX).
@ -84,7 +86,7 @@ impl ApiClient {
&self, &self,
request_builder: RequestBuilder, request_builder: RequestBuilder,
) -> Result<PckCertificateResponse, IntelApiError> { ) -> Result<PckCertificateResponse, IntelApiError> {
let response = request_builder.send().await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::OK]).await?; let response = check_status(response, &[StatusCode::OK]).await?;
let issuer_chain = self.get_required_header( let issuer_chain = self.get_required_header(
@ -109,7 +111,7 @@ impl ApiClient {
&self, &self,
request_builder: RequestBuilder, request_builder: RequestBuilder,
) -> Result<PckCertificatesResponse, IntelApiError> { ) -> Result<PckCertificatesResponse, IntelApiError> {
let response = request_builder.send().await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::OK]).await?; let response = check_status(response, &[StatusCode::OK]).await?;
let issuer_chain = self.get_required_header( let issuer_chain = self.get_required_header(
@ -134,7 +136,7 @@ impl ApiClient {
v4_issuer_chain_header: &'static str, v4_issuer_chain_header: &'static str,
v3_issuer_chain_header: Option<&'static str>, v3_issuer_chain_header: Option<&'static str>,
) -> Result<(String, String), IntelApiError> { ) -> Result<(String, String), IntelApiError> {
let response = request_builder.send().await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::OK]).await?; let response = check_status(response, &[StatusCode::OK]).await?;
let issuer_chain = let issuer_chain =
@ -158,7 +160,7 @@ impl ApiClient {
)) ))
})?; })?;
let response = builder_clone.send().await?; let response = self.execute_with_retry(builder_clone).await?;
let status = response.status(); let status = response.status();
if status == StatusCode::NOT_FOUND || status == StatusCode::GONE { if status == StatusCode::NOT_FOUND || status == StatusCode::GONE {
@ -224,4 +226,69 @@ impl ApiClient {
Ok(()) Ok(())
} }
} }
/// Executes a request with automatic retry logic for rate limiting (429 responses).
///
/// This method will automatically retry the request up to `max_retries` times
/// when receiving a 429 Too Many Requests response, waiting for the duration
/// specified in the Retry-After header.
pub(super) async fn execute_with_retry(
&self,
request_builder: RequestBuilder,
) -> Result<Response, IntelApiError> {
let mut retries = 0;
loop {
// Clone the request builder for retry attempts
let builder = request_builder.try_clone().ok_or_else(|| {
IntelApiError::Io(io::Error::new(
io::ErrorKind::Other,
"Failed to clone request builder for retry",
))
})?;
let response = builder.send().await?;
let status = response.status();
if status != StatusCode::TOO_MANY_REQUESTS {
// Not a rate limit error, return the response
return Ok(response);
}
// Handle 429 Too Many Requests
if retries >= self.max_retries {
// No more retries, return the error
let request_id = response
.headers()
.get("Request-ID")
.and_then(|v| v.to_str().ok())
.unwrap_or("Unknown")
.to_string();
let retry_after = response
.headers()
.get("Retry-After")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u64>().ok())
.unwrap_or(60);
return Err(IntelApiError::TooManyRequests {
request_id,
retry_after,
});
}
// Parse Retry-After header
let retry_after_secs = response
.headers()
.get("Retry-After")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u64>().ok())
.unwrap_or(60); // Default to 60 seconds
// Wait before retrying
sleep(Duration::from_secs(retry_after_secs)).await;
retries += 1;
}
}
} }

View file

@ -45,6 +45,8 @@ pub struct ApiClient {
client: Client, client: Client,
base_url: Url, base_url: Url,
api_version: ApiVersion, api_version: ApiVersion,
/// Maximum number of automatic retries for rate-limited requests (429 responses)
max_retries: u32,
} }
impl ApiClient { impl ApiClient {
@ -114,6 +116,20 @@ impl ApiClient {
.build()?, .build()?,
base_url: base_url.into_url()?, base_url: base_url.into_url()?,
api_version, api_version,
max_retries: 3, // Default to 3 retries
}) })
} }
/// Sets the maximum number of automatic retries for rate-limited requests.
///
/// When the API returns a 429 (Too Many Requests) response, the client will
/// automatically wait for the duration specified in the Retry-After header
/// and retry the request up to this many times.
///
/// # Arguments
///
/// * `max_retries` - Maximum number of retries (0 disables automatic retries)
pub fn set_max_retries(&mut self, max_retries: u32) {
self.max_retries = max_retries;
}
} }

View file

@ -49,7 +49,7 @@ impl ApiClient {
} }
let request_builder = self.client.get(url); let request_builder = self.client.get(url);
let response = request_builder.send().await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::OK]).await?; let response = check_status(response, &[StatusCode::OK]).await?;
let issuer_chain = self.get_required_header( let issuer_chain = self.get_required_header(

View file

@ -36,13 +36,13 @@ impl ApiClient {
let path = self.build_api_path("sgx", "registration", "platform")?; let path = self.build_api_path("sgx", "registration", "platform")?;
let url = self.base_url.join(&path)?; let url = self.base_url.join(&path)?;
let response = self let request_builder = self
.client .client
.post(url) .post(url)
.header(header::CONTENT_TYPE, "application/octet-stream") .header(header::CONTENT_TYPE, "application/octet-stream")
.body(platform_manifest) .body(platform_manifest);
.send()
.await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::CREATED]).await?; let response = check_status(response, &[StatusCode::CREATED]).await?;
@ -81,14 +81,14 @@ impl ApiClient {
let path = self.build_api_path("sgx", "registration", "package")?; let path = self.build_api_path("sgx", "registration", "package")?;
let url = self.base_url.join(&path)?; let url = self.base_url.join(&path)?;
let response = self let request_builder = self
.client .client
.post(url) .post(url)
.header("Ocp-Apim-Subscription-Key", subscription_key) .header("Ocp-Apim-Subscription-Key", subscription_key)
.header(header::CONTENT_TYPE, "application/octet-stream") .header(header::CONTENT_TYPE, "application/octet-stream")
.body(add_package_request) .body(add_package_request);
.send()
.await?; let response = self.execute_with_retry(request_builder).await?;
let response = check_status(response, &[StatusCode::OK]).await?; let response = check_status(response, &[StatusCode::OK]).await?;

View file

@ -59,6 +59,40 @@ pub enum IntelApiError {
/// Indicates an invalid parameter was provided. /// Indicates an invalid parameter was provided.
#[error("Invalid parameter value: {0}")] #[error("Invalid parameter value: {0}")]
InvalidParameter(&'static str), InvalidParameter(&'static str),
/// Indicates that the API rate limit has been exceeded (HTTP 429).
///
/// This error is returned after the client has exhausted all automatic retry attempts
/// for a rate-limited request. The `retry_after` field contains the number of seconds
/// that was specified in the last Retry-After header. By default, the client automatically
/// retries rate-limited requests up to 3 times.
///
/// # Example
///
/// ```rust,no_run
/// use intel_dcap_api::{ApiClient, IntelApiError};
///
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let mut client = ApiClient::new()?;
/// client.set_max_retries(0); // Disable automatic retries
///
/// match client.get_sgx_tcb_info("00606A000000", None, None).await {
/// Ok(tcb_info) => println!("Success"),
/// Err(IntelApiError::TooManyRequests { request_id, retry_after }) => {
/// println!("Rate limited after all retries. Last retry-after was {} seconds.", retry_after);
/// }
/// Err(e) => eprintln!("Other error: {}", e),
/// }
/// # Ok(())
/// # }
/// ```
#[error("Too many requests. Retry after {retry_after} seconds")]
TooManyRequests {
/// The unique request identifier for tracing.
request_id: String,
/// Number of seconds to wait before retrying, from Retry-After header.
retry_after: u64,
},
} }
/// Extracts common API error details from response headers. /// Extracts common API error details from response headers.
@ -92,6 +126,27 @@ pub(crate) async fn check_status(
let status = response.status(); let status = response.status();
if expected_statuses.contains(&status) { if expected_statuses.contains(&status) {
Ok(response) Ok(response)
} else if status == StatusCode::TOO_MANY_REQUESTS {
// Handle 429 Too Many Requests with Retry-After header
let request_id = response
.headers()
.get("Request-ID")
.and_then(|v| v.to_str().ok())
.unwrap_or("Unknown")
.to_string();
// Parse Retry-After header (can be in seconds or HTTP date format)
let retry_after = response
.headers()
.get("Retry-After")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u64>().ok())
.unwrap_or(60); // Default to 60 seconds if header is missing or invalid
Err(IntelApiError::TooManyRequests {
request_id,
retry_after,
})
} else { } else {
let (request_id, error_code, error_message) = extract_api_error_details(&response); let (request_id, error_code, error_message) = extract_api_error_details(&response);
Err(IntelApiError::ApiError { Err(IntelApiError::ApiError {

View file

@ -8,6 +8,14 @@
//! //!
//! Create an [`ApiClient`] to interface with the Intel API. //! Create an [`ApiClient`] to interface with the Intel API.
//! //!
//! # Rate Limiting
//!
//! The Intel API implements rate limiting and may return HTTP 429 (Too Many Requests) responses.
//! This client automatically handles rate limiting by retrying requests up to 3 times by default,
//! waiting for the duration specified in the `Retry-After` header. You can configure the retry
//! behavior using [`ApiClient::set_max_retries`]. If all retries are exhausted, the client
//! returns an [`IntelApiError::TooManyRequests`] error.
//!
//! Example //! Example
//! ```rust,no_run //! ```rust,no_run
//! use intel_dcap_api::{ApiClient, IntelApiError, TcbInfoResponse}; //! use intel_dcap_api::{ApiClient, IntelApiError, TcbInfoResponse};

View file

@ -0,0 +1,312 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use intel_dcap_api::{ApiClient, ApiVersion, CaType, IntelApiError, UpdateType};
use mockito::Server;
use reqwest::Client;
// Create a test client without TLS requirements
async fn create_test_client(base_url: &str) -> ApiClient {
// Create a custom client without TLS requirements for testing
ApiClient::new_with_base_url(base_url).expect("Failed to create client")
}
#[tokio::test]
async fn test_simple_request() {
let mut server = Server::new_async().await;
// First, test with plain reqwest to ensure mock works
let _m = server
.mock("GET", "/test")
.with_status(200)
.with_body("test")
.create_async()
.await;
let client = Client::new();
let resp = client
.get(format!("{}/test", server.url()))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 200);
assert_eq!(resp.text().await.unwrap(), "test");
}
#[tokio::test]
async fn test_tdx_tcb_minimal() {
let mut server = Server::new_async().await;
// Use minimal response
let _m = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"test123".into(),
))
.with_status(200)
.with_header("TCB-Info-Issuer-Chain", "test-cert")
.with_body("{}")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_tdx_tcb_info("test123", None, None).await;
match &result {
Ok(resp) => {
assert_eq!(resp.tcb_info_json, "{}");
assert_eq!(resp.issuer_chain, "test-cert");
}
Err(e) => {
eprintln!("Error: {:?}", e);
panic!("Request failed");
}
}
}
#[tokio::test]
async fn test_sgx_qe_identity_minimal() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/sgx/certification/v4/qe/identity")
.with_status(200)
.with_header("SGX-Enclave-Identity-Issuer-Chain", "test-cert")
.with_body("{}")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_sgx_qe_identity(None, None).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert_eq!(resp.enclave_identity_json, "{}");
assert_eq!(resp.issuer_chain, "test-cert");
}
#[tokio::test]
async fn test_pck_crl_minimal() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/sgx/certification/v4/pckcrl")
.match_query(mockito::Matcher::UrlEncoded(
"ca".into(),
"processor".into(),
))
.with_status(200)
.with_header("SGX-PCK-CRL-Issuer-Chain", "test-cert")
.with_body("test-crl")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_pck_crl(CaType::Processor, None).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert_eq!(String::from_utf8_lossy(&resp.crl_data), "test-crl");
assert_eq!(resp.issuer_chain, "test-cert");
}
#[tokio::test]
async fn test_error_handling() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/sgx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded("fmspc".into(), "bad".into()))
.with_status(404)
.with_header("Request-ID", "test-123")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_sgx_tcb_info("bad", None, None).await;
assert!(result.is_err());
match result.unwrap_err() {
IntelApiError::ApiError {
status, request_id, ..
} => {
assert_eq!(status.as_u16(), 404);
assert_eq!(request_id, "test-123");
}
_ => panic!("Wrong error type"),
}
}
#[tokio::test]
async fn test_update_types() {
let mut server = Server::new_async().await;
// Test Early update type
let _m1 = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::AllOf(vec![
mockito::Matcher::UrlEncoded("fmspc".into(), "test".into()),
mockito::Matcher::UrlEncoded("update".into(), "early".into()),
]))
.with_status(200)
.with_header("TCB-Info-Issuer-Chain", "cert")
.with_body("{\"early\":true}")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client
.get_tdx_tcb_info("test", Some(UpdateType::Early), None)
.await;
assert!(result.is_ok());
assert_eq!(result.unwrap().tcb_info_json, "{\"early\":true}");
// Test Standard update type
let _m2 = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::AllOf(vec![
mockito::Matcher::UrlEncoded("fmspc".into(), "test".into()),
mockito::Matcher::UrlEncoded("update".into(), "standard".into()),
]))
.with_status(200)
.with_header("TCB-Info-Issuer-Chain", "cert")
.with_body("{\"standard\":true}")
.create_async()
.await;
let result2 = client
.get_tdx_tcb_info("test", Some(UpdateType::Standard), None)
.await;
assert!(result2.is_ok());
assert_eq!(result2.unwrap().tcb_info_json, "{\"standard\":true}");
}
#[tokio::test]
async fn test_v3_api_headers() {
let mut server = Server::new_async().await;
// V3 uses different header names for CRL
let _m = server
.mock("GET", "/sgx/certification/v3/pckcrl")
.match_query(mockito::Matcher::UrlEncoded("ca".into(), "platform".into()))
.with_status(200)
.with_header("SGX-PCK-CRL-Issuer-Chain", "v3-cert")
.with_body("v3-crl-data")
.create_async()
.await;
let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap();
let result = client.get_pck_crl(CaType::Platform, None).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert_eq!(String::from_utf8_lossy(&resp.crl_data), "v3-crl-data");
assert_eq!(resp.issuer_chain, "v3-cert");
}
#[tokio::test]
async fn test_sgx_qve_identity() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/sgx/certification/v4/qve/identity")
.with_status(200)
.with_header("SGX-Enclave-Identity-Issuer-Chain", "qve-cert")
.with_body("{\"id\":\"QVE\"}")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_sgx_qve_identity(None, None).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert_eq!(resp.enclave_identity_json, "{\"id\":\"QVE\"}");
assert_eq!(resp.issuer_chain, "qve-cert");
}
#[tokio::test]
async fn test_tdx_qe_identity() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/tdx/certification/v4/qe/identity")
.with_status(200)
.with_header("SGX-Enclave-Identity-Issuer-Chain", "tdx-qe-cert")
.with_body("{\"id\":\"TDX-QE\"}")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_tdx_qe_identity(None, None).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert_eq!(resp.enclave_identity_json, "{\"id\":\"TDX-QE\"}");
assert_eq!(resp.issuer_chain, "tdx-qe-cert");
}
#[tokio::test]
async fn test_error_with_details() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/sgx/certification/v4/pckcert")
.match_query(mockito::Matcher::Any)
.with_status(400)
.with_header("Request-ID", "error-req-123")
.with_header("Error-Code", "InvalidParameter")
.with_header("Error-Message", "PPID format is invalid")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client
.get_pck_certificate_by_ppid("bad", "bad", "bad", "bad", None, None)
.await;
assert!(result.is_err());
match result.unwrap_err() {
IntelApiError::ApiError {
status,
request_id,
error_code,
error_message,
} => {
assert_eq!(status.as_u16(), 400);
assert_eq!(request_id, "error-req-123");
assert_eq!(error_code.as_deref(), Some("InvalidParameter"));
assert_eq!(error_message.as_deref(), Some("PPID format is invalid"));
}
_ => panic!("Wrong error type"),
}
}
#[tokio::test]
async fn test_sgx_tcb_info() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/sgx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"00606A6A0000".into(),
))
.with_status(200)
.with_header("TCB-Info-Issuer-Chain", "sgx-tcb-cert")
.with_body("{\"tcbInfo\":{\"fmspc\":\"00606A6A0000\"}}")
.create_async()
.await;
let client = create_test_client(&server.url()).await;
let result = client.get_sgx_tcb_info("00606A6A0000", None, None).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert_eq!(
resp.tcb_info_json,
"{\"tcbInfo\":{\"fmspc\":\"00606A6A0000\"}}"
);
assert_eq!(resp.issuer_chain, "sgx-tcb-cert");
}

View file

@ -0,0 +1,901 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use intel_dcap_api::{
ApiClient, ApiVersion, CaType, CrlEncoding, IntelApiError, PlatformFilter, UpdateType,
};
use mockito::Server;
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
use serde_json::Value;
// Include real test data
const TDX_TCB_INFO_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_info.json");
const PCK_CRL_PROCESSOR_DATA: &[u8] = include_bytes!("test_data/pck_crl_processor.json");
const PCK_CRL_PLATFORM_DATA: &[u8] = include_bytes!("test_data/pck_crl_platform.json");
const SGX_QE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/sgx_qe_identity.json");
const SGX_QVE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/sgx_qve_identity.json");
const TDX_QE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/tdx_qe_identity.json");
const SGX_TCB_INFO_ALT_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_info_alt.json");
const SGX_QAE_IDENTITY_DATA: &[u8] = include_bytes!("test_data/sgx_qae_identity.json");
const FMSPCS_DATA: &[u8] = include_bytes!("test_data/fmspcs.json");
const SGX_TCB_EVAL_NUMS_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_eval_nums.json");
const TDX_TCB_EVAL_NUMS_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_eval_nums.json");
const PCK_CRL_PROCESSOR_DER_DATA: &[u8] = include_bytes!("test_data/pck_crl_processor_der.json");
const SGX_TCB_INFO_EARLY_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_info_early.json");
const TDX_TCB_INFO_EVAL17_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_info_eval17.json");
const FMSPCS_NO_FILTER_DATA: &[u8] = include_bytes!("test_data/fmspcs_no_filter.json");
// const FMSPCS_ALL_PLATFORMS_DATA: &[u8] = include_bytes!("test_data/fmspcs_all_platforms.json"); // Reserved for future use
const SGX_QE_IDENTITY_V3_DATA: &[u8] = include_bytes!("test_data/sgx_qe_identity_v3.json");
const SGX_TCB_INFO_V3_DATA: &[u8] = include_bytes!("test_data/sgx_tcb_info_v3.json");
const TDX_TCB_INFO_ALT_DATA: &[u8] = include_bytes!("test_data/tdx_tcb_info_00806F050000.json");
fn parse_test_data(data: &[u8]) -> Value {
serde_json::from_slice(data).expect("Failed to parse test data")
}
#[tokio::test]
async fn test_tdx_tcb_info_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(TDX_TCB_INFO_DATA);
// URL encode the issuer chain header value
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"00806F050000".into(),
))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_tdx_tcb_info("00806F050000", None, None).await;
if let Err(e) = &result {
eprintln!("Error: {:?}", e);
eprintln!("Server URL: {}", server.url());
}
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.tcb_info_json,
test_data["tcb_info_json"].as_str().unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
// Verify the JSON can be parsed
let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap();
assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00806F050000");
assert_eq!(tcb_info["tcbInfo"]["id"], "TDX");
}
#[tokio::test]
async fn test_sgx_qe_identity_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_QE_IDENTITY_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/qe/identity")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["enclave_identity_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_qe_identity(None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.enclave_identity_json,
test_data["enclave_identity_json"].as_str().unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
// Verify the JSON structure
let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap();
assert_eq!(identity["enclaveIdentity"]["id"], "QE");
}
#[tokio::test]
async fn test_sgx_qve_identity_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_QVE_IDENTITY_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/qve/identity")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["enclave_identity_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_qve_identity(None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify the JSON structure
let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap();
assert_eq!(identity["enclaveIdentity"]["id"], "QVE");
}
#[tokio::test]
async fn test_tdx_qe_identity_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(TDX_QE_IDENTITY_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/tdx/certification/v4/qe/identity")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["enclave_identity_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_tdx_qe_identity(None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify the JSON structure
let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap();
assert_eq!(identity["enclaveIdentity"]["id"], "TD_QE");
}
#[tokio::test]
async fn test_pck_crl_processor_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(PCK_CRL_PROCESSOR_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/pckcrl")
.match_query(mockito::Matcher::UrlEncoded(
"ca".into(),
"processor".into(),
))
.with_status(200)
.with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["crl_data"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_pck_crl(CaType::Processor, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
String::from_utf8_lossy(&response.crl_data),
test_data["crl_data"].as_str().unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
// Verify it's a valid CRL format
let crl_str = String::from_utf8_lossy(&response.crl_data);
assert!(crl_str.contains("BEGIN X509 CRL"));
assert!(crl_str.contains("END X509 CRL"));
}
#[tokio::test]
async fn test_pck_crl_platform_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(PCK_CRL_PLATFORM_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/pckcrl")
.match_query(mockito::Matcher::UrlEncoded("ca".into(), "platform".into()))
.with_status(200)
.with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["crl_data"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_pck_crl(CaType::Platform, None).await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify issuer chain contains multiple certificates
assert!(response.issuer_chain.contains("BEGIN CERTIFICATE"));
assert!(response.issuer_chain.contains("END CERTIFICATE"));
}
#[tokio::test]
async fn test_sgx_tcb_info_alt_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_TCB_INFO_ALT_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"00906ED50000".into(),
))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_tcb_info("00906ED50000", None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify the JSON structure
let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap();
assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00906ED50000");
assert_eq!(tcb_info["tcbInfo"]["id"], "SGX");
}
#[tokio::test]
async fn test_tdx_tcb_with_update_type() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(TDX_TCB_INFO_DATA);
// Test with Early update type
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m1 = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::AllOf(vec![
mockito::Matcher::UrlEncoded("fmspc".into(), "00806F050000".into()),
mockito::Matcher::UrlEncoded("update".into(), "early".into()),
]))
.with_status(200)
.with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client
.get_tdx_tcb_info("00806F050000", Some(UpdateType::Early), None)
.await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_error_handling_with_intel_headers() {
let mut server = Server::new_async().await;
// Real error response from Intel API
let _m = server
.mock("GET", "/sgx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"invalid".into(),
))
.with_status(404)
.with_header("Request-ID", "abc123def456")
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_tcb_info("invalid", None, None).await;
assert!(result.is_err());
match result.unwrap_err() {
IntelApiError::ApiError {
status, request_id, ..
} => {
assert_eq!(status.as_u16(), 404);
assert_eq!(request_id, "abc123def456");
}
_ => panic!("Expected ApiError"),
}
}
#[tokio::test]
async fn test_v3_api_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(PCK_CRL_PROCESSOR_DATA);
// V3 uses different header names
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v3/pckcrl")
.match_query(mockito::Matcher::UrlEncoded(
"ca".into(),
"processor".into(),
))
.with_status(200)
.with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["crl_data"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap();
let result = client.get_pck_crl(CaType::Processor, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
String::from_utf8_lossy(&response.crl_data),
test_data["crl_data"].as_str().unwrap()
);
}
#[tokio::test]
async fn test_sgx_qae_identity_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_QAE_IDENTITY_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/qae/identity")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["enclave_identity_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_qae_identity(None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.enclave_identity_json,
test_data["enclave_identity_json"].as_str().unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
// Verify the JSON structure
let identity: Value = serde_json::from_str(&response.enclave_identity_json).unwrap();
assert_eq!(identity["enclaveIdentity"]["id"], "QAE");
}
#[tokio::test]
async fn test_get_fmspcs_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(FMSPCS_DATA);
let _m = server
.mock("GET", "/sgx/certification/v4/fmspcs")
.match_query(mockito::Matcher::UrlEncoded(
"platform".into(),
"all".into(),
))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_body(test_data["fmspcs_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_fmspcs(Some(PlatformFilter::All)).await;
assert!(result.is_ok());
let fmspcs_json = result.unwrap();
assert_eq!(fmspcs_json, test_data["fmspcs_json"].as_str().unwrap());
// Verify the JSON structure
let fmspcs: Value = serde_json::from_str(&fmspcs_json).unwrap();
assert!(fmspcs.is_array());
assert!(!fmspcs.as_array().unwrap().is_empty());
}
#[tokio::test]
async fn test_sgx_tcb_evaluation_data_numbers_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_TCB_EVAL_NUMS_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/tcbevaluationdatanumbers")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header(
"TCB-Evaluation-Data-Numbers-Issuer-Chain",
&encoded_issuer_chain,
)
.with_body(
test_data["tcb_evaluation_data_numbers_json"]
.as_str()
.unwrap(),
)
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_tcb_evaluation_data_numbers().await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.tcb_evaluation_data_numbers_json,
test_data["tcb_evaluation_data_numbers_json"]
.as_str()
.unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
// Verify the JSON structure
let eval_nums: Value =
serde_json::from_str(&response.tcb_evaluation_data_numbers_json).unwrap();
assert!(eval_nums.is_object());
}
#[tokio::test]
async fn test_tdx_tcb_evaluation_data_numbers_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(TDX_TCB_EVAL_NUMS_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/tdx/certification/v4/tcbevaluationdatanumbers")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header(
"TCB-Evaluation-Data-Numbers-Issuer-Chain",
&encoded_issuer_chain,
)
.with_body(
test_data["tcb_evaluation_data_numbers_json"]
.as_str()
.unwrap(),
)
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_tdx_tcb_evaluation_data_numbers().await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.tcb_evaluation_data_numbers_json,
test_data["tcb_evaluation_data_numbers_json"]
.as_str()
.unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
}
#[tokio::test]
async fn test_pck_crl_der_encoding_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(PCK_CRL_PROCESSOR_DER_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
// The DER data is stored as base64 in our test data
let crl_base64 = test_data["crl_data_base64"].as_str().unwrap();
use base64::{engine::general_purpose, Engine as _};
let crl_der = general_purpose::STANDARD.decode(crl_base64).unwrap();
let _m = server
.mock("GET", "/sgx/certification/v4/pckcrl")
.match_query(mockito::Matcher::AllOf(vec![
mockito::Matcher::UrlEncoded("ca".into(), "processor".into()),
mockito::Matcher::UrlEncoded("encoding".into(), "der".into()),
]))
.with_status(200)
.with_header("SGX-PCK-CRL-Issuer-Chain", &encoded_issuer_chain)
.with_body(crl_der)
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client
.get_pck_crl(CaType::Processor, Some(CrlEncoding::Der))
.await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify the response data matches
let response_base64 = general_purpose::STANDARD.encode(&response.crl_data);
assert_eq!(response_base64, crl_base64);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
}
#[tokio::test]
async fn test_sgx_tcb_info_early_update_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_TCB_INFO_EARLY_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/sgx/certification/v4/tcb")
.match_query(mockito::Matcher::AllOf(vec![
mockito::Matcher::UrlEncoded("fmspc".into(), "00906ED50000".into()),
mockito::Matcher::UrlEncoded("update".into(), "early".into()),
]))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client
.get_sgx_tcb_info("00906ED50000", Some(UpdateType::Early), None)
.await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.tcb_info_json,
test_data["tcb_info_json"].as_str().unwrap()
);
// Verify the JSON structure
let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap();
assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00906ED50000");
}
#[tokio::test]
async fn test_tdx_tcb_info_with_eval_number_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(TDX_TCB_INFO_EVAL17_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::AllOf(vec![
mockito::Matcher::UrlEncoded("fmspc".into(), "00806F050000".into()),
mockito::Matcher::UrlEncoded("tcbEvaluationDataNumber".into(), "17".into()),
]))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client
.get_tdx_tcb_info("00806F050000", None, Some(17))
.await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify the response
let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap();
assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00806F050000");
assert_eq!(tcb_info["tcbInfo"]["id"], "TDX");
}
#[tokio::test]
async fn test_get_fmspcs_v3_should_fail() {
let server = Server::new_async().await;
// FMSPCs is V4 only
let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap();
let result = client.get_fmspcs(None).await;
assert!(result.is_err());
match result.unwrap_err() {
IntelApiError::UnsupportedApiVersion(msg) => {
assert!(msg.contains("API v4 only"));
}
_ => panic!("Expected UnsupportedApiVersion error"),
}
}
#[tokio::test]
async fn test_tcb_evaluation_data_numbers_v3_should_fail() {
let server = Server::new_async().await;
// TCB evaluation data numbers is V4 only
let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap();
let sgx_result = client.get_sgx_tcb_evaluation_data_numbers().await;
assert!(sgx_result.is_err());
match sgx_result.unwrap_err() {
IntelApiError::UnsupportedApiVersion(msg) => {
assert!(msg.contains("requires API v4"));
}
_ => panic!("Expected UnsupportedApiVersion error"),
}
let tdx_result = client.get_tdx_tcb_evaluation_data_numbers().await;
assert!(tdx_result.is_err());
match tdx_result.unwrap_err() {
IntelApiError::UnsupportedApiVersion(msg) => {
assert!(msg.contains("requires API v4"));
}
_ => panic!("Expected UnsupportedApiVersion error"),
}
}
#[tokio::test]
async fn test_get_fmspcs_no_filter_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(FMSPCS_NO_FILTER_DATA);
let _m = server
.mock("GET", "/sgx/certification/v4/fmspcs")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_body(test_data["fmspcs_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_fmspcs(None).await;
assert!(result.is_ok());
let fmspcs_json = result.unwrap();
assert_eq!(fmspcs_json, test_data["fmspcs_json"].as_str().unwrap());
}
#[tokio::test]
async fn test_sgx_qe_identity_v3_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_QE_IDENTITY_V3_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
// V3 uses different header names
let _m = server
.mock("GET", "/sgx/certification/v3/qe/identity")
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("SGX-Enclave-Identity-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["enclave_identity_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap();
let result = client.get_sgx_qe_identity(None, None).await;
if let Err(e) = &result {
eprintln!("Error in V3 test: {:?}", e);
}
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.enclave_identity_json,
test_data["enclave_identity_json"].as_str().unwrap()
);
assert_eq!(
response.issuer_chain,
test_data["issuer_chain"].as_str().unwrap()
);
}
#[tokio::test]
async fn test_sgx_tcb_info_v3_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(SGX_TCB_INFO_V3_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
// V3 uses different header names
let _m = server
.mock("GET", "/sgx/certification/v3/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"00906ED50000".into(),
))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("SGX-TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_options(server.url(), ApiVersion::V3).unwrap();
let result = client.get_sgx_tcb_info("00906ED50000", None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(
response.tcb_info_json,
test_data["tcb_info_json"].as_str().unwrap()
);
// Verify the JSON structure
let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap();
assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00906ED50000");
}
#[tokio::test]
async fn test_tdx_tcb_info_alternate_fmspc_with_real_data() {
let mut server = Server::new_async().await;
let test_data = parse_test_data(TDX_TCB_INFO_ALT_DATA);
let issuer_chain = test_data["issuer_chain"].as_str().unwrap();
let encoded_issuer_chain =
percent_encode(issuer_chain.as_bytes(), NON_ALPHANUMERIC).to_string();
let _m = server
.mock("GET", "/tdx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"00806F050000".into(),
))
.with_status(200)
.with_header("Content-Type", "application/json")
.with_header("TCB-Info-Issuer-Chain", &encoded_issuer_chain)
.with_body(test_data["tcb_info_json"].as_str().unwrap())
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_tdx_tcb_info("00806F050000", None, None).await;
assert!(result.is_ok());
let response = result.unwrap();
// Verify we got the same data as the first TDX TCB info test
let tcb_info: Value = serde_json::from_str(&response.tcb_info_json).unwrap();
assert_eq!(tcb_info["tcbInfo"]["fmspc"], "00806F050000");
assert_eq!(tcb_info["tcbInfo"]["id"], "TDX");
}
#[tokio::test]
async fn test_platform_filter_combinations() {
let mut server = Server::new_async().await;
// Test with different platform filters
let filters = vec![
(Some(PlatformFilter::All), "all"),
(Some(PlatformFilter::Client), "client"),
(Some(PlatformFilter::E3), "E3"),
(Some(PlatformFilter::E5), "E5"),
(None, ""),
];
for (filter, query_value) in filters {
let mock_response = r#"[{"fmspc": "00906ED50000", "platform": "SGX"}]"#;
let mut mock = server.mock("GET", "/sgx/certification/v4/fmspcs");
if !query_value.is_empty() {
mock = mock.match_query(mockito::Matcher::UrlEncoded(
"platform".into(),
query_value.into(),
));
}
let _m = mock
.with_status(200)
.with_header("Content-Type", "application/json")
.with_body(mock_response)
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_fmspcs(filter).await;
assert!(result.is_ok());
let response = result.unwrap();
assert!(response.contains("00906ED50000"));
}
}
#[tokio::test]
async fn test_error_scenarios() {
let mut server = Server::new_async().await;
// Test 404 with Error headers
let _m = server
.mock("GET", "/sgx/certification/v4/tcb")
.match_query(mockito::Matcher::UrlEncoded(
"fmspc".into(),
"invalid".into(),
))
.with_status(404)
.with_header("Request-ID", "test123")
.with_header("Error-Code", "InvalidParameter")
.with_header("Error-Message", "Invalid FMSPC format")
.create_async()
.await;
let client = ApiClient::new_with_base_url(server.url()).unwrap();
let result = client.get_sgx_tcb_info("invalid", None, None).await;
assert!(result.is_err());
match result.unwrap_err() {
IntelApiError::ApiError {
status,
request_id,
error_code,
error_message,
} => {
assert_eq!(status.as_u16(), 404);
assert_eq!(request_id, "test123");
assert_eq!(error_code.as_deref(), Some("InvalidParameter"));
assert_eq!(error_message.as_deref(), Some("Invalid FMSPC format"));
}
_ => panic!("Expected ApiError"),
}
}

View file

@ -0,0 +1,3 @@
{
"fmspcs_json": "[{\"fmspc\":\"00A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"70A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"00A06E050000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EA50000\",\"platform\":\"client\"},{\"fmspc\":\"20606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"50806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A067110000\",\"platform\":\"E3\"},{\"fmspc\":\"00606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"00706E470000\",\"platform\":\"client\"},{\"fmspc\":\"00806EA60000\",\"platform\":\"client\"},{\"fmspc\":\"00706A800000\",\"platform\":\"client\"},{\"fmspc\":\"00706A100000\",\"platform\":\"client\"},{\"fmspc\":\"F0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EC50000\",\"platform\":\"client\"},{\"fmspc\":\"90806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06F010000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"B0C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906ED50000\",\"platform\":\"E3\"},{\"fmspc\":\"40A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"D0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A065510000\",\"platform\":\"client\"},{\"fmspc\":\"10A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"30606A000000\",\"platform\":\"E5\"},{\"fmspc\":\"20806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EA10000\",\"platform\":\"E3\"},{\"fmspc\":\"30806F040000\",\"platform\":\"E5\"},{\"fmspc\":\"C0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"30A06D050000\",\"platform\":\"E5\"},{\"fmspc\":\"60C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F050000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"20906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"90C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"80C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EB10000\",\"platform\":\"client\"},{\"fmspc\":\"00606A000000\",\"platform\":\"E5\"}]"
}

View file

@ -0,0 +1,3 @@
{
"fmspcs_json": "[{\"fmspc\":\"00A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"70A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"00A06E050000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EA50000\",\"platform\":\"client\"},{\"fmspc\":\"20606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"50806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A067110000\",\"platform\":\"E3\"},{\"fmspc\":\"00606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"00706E470000\",\"platform\":\"client\"},{\"fmspc\":\"00806EA60000\",\"platform\":\"client\"},{\"fmspc\":\"00706A800000\",\"platform\":\"client\"},{\"fmspc\":\"00706A100000\",\"platform\":\"client\"},{\"fmspc\":\"F0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EC50000\",\"platform\":\"client\"},{\"fmspc\":\"90806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06F010000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"B0C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906ED50000\",\"platform\":\"E3\"},{\"fmspc\":\"40A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"D0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A065510000\",\"platform\":\"client\"},{\"fmspc\":\"10A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"30606A000000\",\"platform\":\"E5\"},{\"fmspc\":\"20806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EA10000\",\"platform\":\"E3\"},{\"fmspc\":\"30806F040000\",\"platform\":\"E5\"},{\"fmspc\":\"C0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"30A06D050000\",\"platform\":\"E5\"},{\"fmspc\":\"60C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F050000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"20906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"90C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"80C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EB10000\",\"platform\":\"client\"},{\"fmspc\":\"00606A000000\",\"platform\":\"E5\"}]"
}

View file

@ -0,0 +1,3 @@
{
"fmspcs_json": "[{\"fmspc\":\"00A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"70A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"00A06E050000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EA50000\",\"platform\":\"client\"},{\"fmspc\":\"20606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"50806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A067110000\",\"platform\":\"E3\"},{\"fmspc\":\"00606C040000\",\"platform\":\"E5\"},{\"fmspc\":\"00706E470000\",\"platform\":\"client\"},{\"fmspc\":\"00806EA60000\",\"platform\":\"client\"},{\"fmspc\":\"00706A800000\",\"platform\":\"client\"},{\"fmspc\":\"00706A100000\",\"platform\":\"client\"},{\"fmspc\":\"F0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EC50000\",\"platform\":\"client\"},{\"fmspc\":\"90806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06F010000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"B0C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906ED50000\",\"platform\":\"E3\"},{\"fmspc\":\"40A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"D0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00A065510000\",\"platform\":\"client\"},{\"fmspc\":\"10A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"30606A000000\",\"platform\":\"E5\"},{\"fmspc\":\"20806EB70000\",\"platform\":\"client\"},{\"fmspc\":\"00906EA10000\",\"platform\":\"E3\"},{\"fmspc\":\"30806F040000\",\"platform\":\"E5\"},{\"fmspc\":\"C0806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"30A06D050000\",\"platform\":\"E5\"},{\"fmspc\":\"60C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"20A06D080000\",\"platform\":\"E5\"},{\"fmspc\":\"10A06D000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F050000\",\"platform\":\"E5\"},{\"fmspc\":\"60A06D070000\",\"platform\":\"E5\"},{\"fmspc\":\"20906EC10000\",\"platform\":\"client\"},{\"fmspc\":\"90C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"80C06F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00806F000000\",\"platform\":\"E5\"},{\"fmspc\":\"00906EB10000\",\"platform\":\"client\"},{\"fmspc\":\"00606A000000\",\"platform\":\"E5\"}]"
}

View file

@ -0,0 +1,4 @@
{
"crl_data": "-----BEGIN X509 CRL-----\nMIIKYTCCCggCAQEwCgYIKoZIzj0EAwIwcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBD\nSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDUy\nNzE5MjUwNVoXDTI1MDYyNjE5MjUwNVowggk0MDMCFG/DTlAj5yiSNDXWGqS4PGGB\nZq01Fw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAO+ubpcV/KE7h+Mz\n6CYe1tmQqSatFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAP1ghkhi\nnLpzB4tNSS9LPqdBrQjNFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIV\nAIr5JBhOHVr93XPD1joS9ei1c35WFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMK\nAQEwNAIVALEleXjPqczdB1mr+MXKcvrjp4qbFw0yNTA1MjcxOTI1MDVaMAwwCgYD\nVR0VBAMKAQEwMwIUdP6mFKlyvg4oQ/IFmDWBHthy+bMXDTI1MDUyNzE5MjUwNVow\nDDAKBgNVHRUEAwoBATA0AhUA+cTvVrOrSNV34Qi67fS/iAFCFLkXDTI1MDUyNzE5\nMjUwNVowDDAKBgNVHRUEAwoBATAzAhQHHeB3j55fxPKHjzDWsHyaMOazCxcNMjUw\nNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDQCFQDN4kJPlyzqlP8jmTf02AwlAp3W\nCxcNMjUwNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFGwzGeUQm2RQfTzxEyzg\nA0nvUnMZFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAN8I11a2anSX\n9DtbtYraBNP096k3Fw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwMwIUKK9I\nW2z2fkCaOdXLWu5FmPeo+nsXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0\nAhUA+4strsCSytqKqbxP8vHCDQNGZowXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUE\nAwoBATA0AhUAzUhQrFK9zGmmpvBYyLxXu9C1+GQXDTI1MDUyNzE5MjUwNVowDDAK\nBgNVHRUEAwoBATA0AhUAmU3TZm9SdfuAX5XdAr1QyyZ52K0XDTI1MDUyNzE5MjUw\nNVowDDAKBgNVHRUEAwoBATAzAhQHAhNpACUidNkDXu31RXRi+tDvTBcNMjUwNTI3\nMTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFGHyv3Pjm04EqifYAb1z0kMZtb+AFw0y\nNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwMwIUOZK+hRuWkC7/OJWebC7/GwZR\npLUXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATAzAhQP2kOgC2jqebfC3q6s\nC0mL37KvkBcNMjUwNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFGOfE5pQQP3P\n8ZHopPsb8IbtYDlxFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAJWd\nUz+SSdweUTVEzcgwvxm38fMBFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEw\nMwIUeuN3SKn5EvTGO6erB8WTzh0dEYEXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUE\nAwoBATAzAhQTiEszJpk4wZWqFw/KddoXdTjfCxcNMjUwNTI3MTkyNTA1WjAMMAoG\nA1UdFQQDCgEBMDQCFQCF08k4G3en4E0RnJ5a1nSf8/+rhxcNMjUwNTI3MTkyNTA1\nWjAMMAoGA1UdFQQDCgEBMDQCFQCTiHykQR56kjvR/tKBmylJ8gG1tBcNMjUwNTI3\nMTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMCFCSY3GKDkwmW/YvyOjesviajvtRXFw0y\nNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAIpm8adJSIZnaJzDkDrFTGYr\ncS5zFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAK/BNhC902y3mF0Q\nZIGogNOgH9oHFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIVAO/gSywz\n0DaqyWymc78emke2TVy7Fw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwNAIV\nAIPZrI2LtQnRxsgJrXEuhDBVntfzFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMK\nAQEwMwIUeTH9ULUHHBu/xbe23ti0W52LhSkXDTI1MDUyNzE5MjUwNVowDDAKBgNV\nHRUEAwoBATAzAhQfog4pcL3l1X97jd+DOUhOHx0IIxcNMjUwNTI3MTkyNTA1WjAM\nMAoGA1UdFQQDCgEBMDMCFB6HssOzLY0j5BHO80GXuVrwyK31Fw0yNTA1MjcxOTI1\nMDVaMAwwCgYDVR0VBAMKAQEwNAIVAJr9LukKRzVQoWfZlpEUN8dQLR8JFw0yNTA1\nMjcxOTI1MDVaMAwwCgYDVR0VBAMKAQEwMwIURIGw8RcooTtpbT6px3CgsV7FjdoX\nDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0AhUAp4WfV5gu8OZ9N7yO8u9a\nyDX/GqkXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0AhUAnWd1O4HkcJCu\np2P77ExFSbzbmTMXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATAzAhQ0v7t6\nHZxWgUfhGLYU97du0+9o3xcNMjUwNTI3MTkyNTA1WjAMMAoGA1UdFQQDCgEBMDMC\nFCw8xv6SedsVFtXOOfKomM2loXXhFw0yNTA1MjcxOTI1MDVaMAwwCgYDVR0VBAMK\nAQEwMwIUcXlIaHUJI0vpeeS33ObzG+9ktowXDTI1MDUyNzE5MjUwNVowDDAKBgNV\nHRUEAwoBATA0AhUAnXbvLDnBNuhli25zlrHXRFonYx8XDTI1MDUyNzE5MjUwNVow\nDDAKBgNVHRUEAwoBATA0AhUAw+Al/KmV829ZtIRnk54+NOY2Gm8XDTI1MDUyNzE5\nMjUwNVowDDAKBgNVHRUEAwoBATA0AhUAjF9rMlfaBbF0KeLmG6ll1nMwYGoXDTI1\nMDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBATA0AhUAoXxRci7B4MMnj+i98FIFnL7E\n5kgXDTI1MDUyNzE5MjUwNVowDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQEw\nHwYDVR0jBBgwFoAUlW9dzb0b4elAScnU9DPOAVcL3lQwCgYIKoZIzj0EAwIDRwAw\nRAIgUpcU4PTB0Bc3qvMCWYHx5EEDXqxSLgCoYKp4C/GgxpkCIE/xDOudQg2ldK1m\nABQqvvzE8ibtGcDyaq1WI56Wv1bl\n-----END X509 CRL-----\n",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"crl_data": "-----BEGIN X509 CRL-----\nMIIBKjCB0QIBATAKBggqhkjOPQQDAjBxMSMwIQYDVQQDDBpJbnRlbCBTR1ggUENL\nIFByb2Nlc3NvciBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDUy\nNzE4NDYyNVoXDTI1MDYyNjE4NDYyNVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQY\nMBaAFNDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMCA0gAMEUCIQDtYSVu\nju3asUsAGZ2Hbe9uvZmk5zvLtwDk38KrWfb5zAIgSfk6Dmqhc4+moiRuRz0wQqLj\nckwO2BEUviI+nZfN75I=\n-----END X509 CRL-----\n",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICmDCCAj6gAwIBAgIVANDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHExIzAh\nBgNVBAMMGkludGVsIFNHWCBQQ0sgUHJvY2Vzc29yIENBMRowGAYDVQQKDBFJbnRl\nbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNB\nMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL9q+NMp2IOg\ntdl1bk/uWZ5+TGQm8aCi8z78fs+fKCQ3d+uDzXnVTAT2ZhDCifyIuJwvN3wNBp9i\nHBSSMJMJrBOjgbswgbgwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqww\nUgYDVR0fBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNl\ncnZpY2VzLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFNDo\nqtp11/kuSReYPHsUZdDV8llNMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEAMAoGCCqGSM49BAMCA0gAMEUCIQCJgTbtVqOyZ1m3jqiAXM6QYa6r5sWS\n4y/G7y8uIJGxdwIgRqPvBSKzzQagBLQq5s5A70pdoiaRJ8z/0uDz4NgV91k=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"crl_data_base64": "MIIBKjCB0QIBATAKBggqhkjOPQQDAjBxMSMwIQYDVQQDDBpJbnRlbCBTR1ggUENLIFByb2Nlc3NvciBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTI1MDUyNzE5MjMwOVoXDTI1MDYyNjE5MjMwOVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFNDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMCA0gAMEUCIQC2Q0kz4IioOr5HsdYUY8b0m3XSS6FwuKVUAIvroURNHgIgIo5mAP1gCBeW719AqdBaxnoNuUypHQ/X+1zfDiY69ec=",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICmDCCAj6gAwIBAgIVANDoqtp11/kuSReYPHsUZdDV8llNMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHExIzAh\nBgNVBAMMGkludGVsIFNHWCBQQ0sgUHJvY2Vzc29yIENBMRowGAYDVQQKDBFJbnRl\nbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNB\nMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL9q+NMp2IOg\ntdl1bk/uWZ5+TGQm8aCi8z78fs+fKCQ3d+uDzXnVTAT2ZhDCifyIuJwvN3wNBp9i\nHBSSMJMJrBOjgbswgbgwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqww\nUgYDVR0fBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNl\ncnZpY2VzLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFNDo\nqtp11/kuSReYPHsUZdDV8llNMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\nAQH/AgEAMAoGCCqGSM49BAMCA0gAMEUCIQCJgTbtVqOyZ1m3jqiAXM6QYa6r5sWS\n4y/G7y8uIJGxdwIgRqPvBSKzzQagBLQq5s5A70pdoiaRJ8z/0uDz4NgV91k=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QAE\",\"version\":2,\"issueDate\":\"2025-05-27T19:31:54Z\",\"nextUpdate\":\"2025-06-26T19:31:54Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"01000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":3,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},\"signature\":\"a5dfb799f78ea3d32f7760f2b529fc80fe7efa3236c9888e8ece69379e206880f0b67b9407a9b139feb5007b785601f09050d4963116c1bd2cd5def4e3a11da8\"}",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2025-05-27T19:05:27Z\",\"nextUpdate\":\"2025-06-26T19:05:27Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00202\",\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]}]},\"signature\":\"5ecc03899589b58e8216c69c3439d1a9310d8af9ebfb37e61518a2a3cb801e0019a5fc955e38e6becc1c75a8a05bb337c93c1a61009a34cc8291fdd82f67ae19\"}",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2025-05-27T18:38:43Z\",\"nextUpdate\":\"2025-06-26T18:38:43Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\"}]},\"signature\":\"b4cc7bd5ee712a62cf6fbad0a052bd44194a25a5313b4bfff241a3c08ff00bcf0d15f1feb3a369bd9b362a6e5104c82f06d827ef676e70fdccf947566b77f6e8\"}",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"QVE\",\"version\":2,\"issueDate\":\"2025-05-27T19:31:54Z\",\"nextUpdate\":\"2025-06-26T19:31:54Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"01000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},\"signature\":\"3bb26b16155b207f884ef10fad705129bf566ccc9e6bd4e9907c99bc0ccd6deb6b6451b103b495926c582ece9d22c491f05a627806e09ca07e1063de898460e7\"}",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n",
"tcb_evaluation_data_numbers_json": "{\"tcbEvaluationDataNumbers\":{\"id\":\"SGX\",\"version\":1,\"issueDate\":\"2025-05-27T19:04:23Z\",\"nextUpdate\":\"2025-06-26T19:04:23Z\",\"tcbEvalNumbers\":[{\"tcbEvaluationDataNumber\":19,\"tcbRecoveryEventDate\":\"2025-05-13T00:00:00Z\",\"tcbDate\":\"2025-05-14T00:00:00Z\"},{\"tcbEvaluationDataNumber\":18,\"tcbRecoveryEventDate\":\"2024-11-12T00:00:00Z\",\"tcbDate\":\"2024-11-13T00:00:00Z\"},{\"tcbEvaluationDataNumber\":17,\"tcbRecoveryEventDate\":\"2024-03-12T00:00:00Z\",\"tcbDate\":\"2024-03-13T00:00:00Z\"}]},\"signature\":\"19799ae10942dc046340aa279123fe743e2ab51c862ab6a04abdaab86083013ca81ac1963aa08f1a3b44f0c12e9c6d094cb98aa5ca51bc40439833ada6f0e9e1\"}"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,4 @@
{
"enclave_identity_json": "{\"enclaveIdentity\":{\"id\":\"TD_QE\",\"version\":2,\"issueDate\":\"2025-05-27T19:22:46Z\",\"nextUpdate\":\"2025-06-26T19:22:46Z\",\"tcbEvaluationDataNumber\":17,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},\"signature\":\"cba4e80e12e114ac591bcf43c155cabb2f48bc6e629dce6d5aab26127c7c23b1a3eafc52f60bab7ac39aff2866431494315fd553fa73d9688a802383eea4edc9\"}",
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n"
}

View file

@ -0,0 +1,4 @@
{
"issuer_chain": "-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n",
"tcb_evaluation_data_numbers_json": "{\"tcbEvaluationDataNumbers\":{\"id\":\"TDX\",\"version\":1,\"issueDate\":\"2025-05-27T18:50:21Z\",\"nextUpdate\":\"2025-06-26T18:50:21Z\",\"tcbEvalNumbers\":[{\"tcbEvaluationDataNumber\":19,\"tcbRecoveryEventDate\":\"2025-05-13T00:00:00Z\",\"tcbDate\":\"2025-05-14T00:00:00Z\"},{\"tcbEvaluationDataNumber\":18,\"tcbRecoveryEventDate\":\"2024-11-12T00:00:00Z\",\"tcbDate\":\"2024-11-13T00:00:00Z\"},{\"tcbEvaluationDataNumber\":17,\"tcbRecoveryEventDate\":\"2024-03-12T00:00:00Z\",\"tcbDate\":\"2024-03-13T00:00:00Z\"}]},\"signature\":\"507f5f4406a15e9fa311142b41c47da082d10ce35e863491061c49adac188a2e974561b134a7eff9e10f98be2c5bd5e28c18e3dc6327067fd1a5459d48cd1e58\"}"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -49,6 +49,7 @@ let
# 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")) (maybeMissing (inputs.src + "/crates/teepot-vault/tests/data"))
(maybeMissing (inputs.src + "/crates/intel-dcap-api/tests/test_data"))
]; ];
}; };