mirror of
https://github.com/matter-labs/teepot.git
synced 2025-07-21 15:13:56 +02:00

- Add mock tests using real Intel API response data (25 tests) - Create fetch_test_data tool to retrieve real API responses for testing - Add integration_test example covering 17 API endpoints - Add common_usage example demonstrating attestation verification patterns - Add issuer chain validation checks to ensure signature verification is possible - Add comprehensive documentation in CLAUDE.md The test suite now covers all major Intel DCAP API functionality including TCB info, enclave identities, PCK CRLs, FMSPCs, and evaluation data numbers for both SGX and TDX platforms across API v3 and v4. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Harald Hoyer <harald@matterlabs.dev>
312 lines
9.4 KiB
Rust
312 lines
9.4 KiB
Rust
// 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");
|
|
}
|