feat(api): add Intel DCAP API client module

Introduced a new `intel-dcap-api` crate for interacting with Intel's DCAP APIs.
- Implemented various API client functionalities for SGX/TDX attestation services.
- Added support for registration, certification, enclave identity, and FMSPC retrieval.

Signed-off-by: Harald Hoyer <harald@matterlabs.dev>
This commit is contained in:
Harald Hoyer 2025-04-09 16:29:37 +02:00
parent 93c35dad38
commit ed84a424db
Signed by: harald
GPG key ID: F519A1143B3FBE32
11 changed files with 1939 additions and 1 deletions

View file

@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use intel_dcap_api::{
ApiClient, ApiVersion, CaType, CrlEncoding, EnclaveIdentityResponse, IntelApiError,
PckCrlResponse, PlatformFilter, TcbInfoResponse,
};
#[tokio::main]
async fn main() -> Result<(), IntelApiError> {
for api_version in [ApiVersion::V3, ApiVersion::V4] {
println!("Using API version: {}", api_version);
let client = ApiClient::new_with_version(api_version)?;
// Example: Get SGX TCB Info
let fmspc_example = "00606A000000"; // Example FMSPC from docs
match client.get_sgx_tcb_info(fmspc_example, None, None).await {
Ok(TcbInfoResponse {
tcb_info_json,
issuer_chain,
}) => println!(
"SGX TCB Info for {}:\n{}\nIssuer Chain: {}",
fmspc_example, tcb_info_json, issuer_chain
),
Err(e) => eprintln!("Error getting SGX TCB info: {}", e),
}
// Example: Get FMSPCs
match client.get_fmspcs(Some(PlatformFilter::E3)).await {
// Filter for E3 platform type [cite: 230]
Ok(fmspc_list) => println!("\nE3 FMSPCs:\n{}", fmspc_list),
Err(e) => eprintln!("Error getting FMSPCs: {}", e),
}
// Example: Get SGX QE Identity
match client.get_sgx_qe_identity(None, None).await {
Ok(EnclaveIdentityResponse {
enclave_identity_json,
issuer_chain,
}) => {
println!(
"\nSGX QE Identity:\n{}\nIssuer Chain: {}",
enclave_identity_json, issuer_chain
)
}
Err(e) => eprintln!("Error getting SGX QE Identity: {}", e),
}
// Example: Get PCK CRL (Platform CA, PEM encoding)
match client
.get_pck_crl(CaType::Platform, Some(CrlEncoding::Pem))
.await
{
// [cite: 118, 119]
Ok(PckCrlResponse {
crl_data,
issuer_chain,
}) => {
// Attempt to decode PEM for display, otherwise show byte count
match String::from_utf8(crl_data.clone()) {
Ok(pem_string) => println!(
"\nPlatform PCK CRL (PEM):\n{}\nIssuer Chain: {}",
pem_string, issuer_chain
),
Err(_) => println!(
"\nPlatform PCK CRL ({} bytes, likely DER):\nIssuer Chain: {}",
crl_data.len(),
issuer_chain
),
}
}
Err(e) => eprintln!("Error getting PCK CRL: {}", e),
}
}
Ok(())
}

View file

@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 Matter Labs
use intel_dcap_api::{ApiClient, CaType, CrlEncoding, IntelApiError, PckCrlResponse};
use x509_cert::{
der::{oid::AssociatedOid, Decode, SliceReader},
ext::pkix::{
crl::dp::DistributionPoint,
name::{DistributionPointName, GeneralName},
CrlDistributionPoints,
},
};
#[tokio::main]
async fn main() -> Result<(), IntelApiError> {
let client = ApiClient::new()?;
let PckCrlResponse {
crl_data,
issuer_chain,
} = client
.get_pck_crl(CaType::Platform, Some(CrlEncoding::Der))
.await?;
let certs = x509_cert::certificate::CertificateInner::<
x509_cert::certificate::Rfc5280
>::load_pem_chain(issuer_chain.as_bytes()).map_err(
|_| IntelApiError::InvalidParameter("Could not load a PEM chain")
)?;
for cert in certs {
println!("Issuer: {}", cert.tbs_certificate.issuer);
println!("Subject: {}", cert.tbs_certificate.subject);
println!("Serial Number: {}", cert.tbs_certificate.serial_number);
println!("Not Before: {}", cert.tbs_certificate.validity.not_before);
println!("Not After: {}", cert.tbs_certificate.validity.not_after);
// Extract and print CRL distribution points
if let Some(extensions) = &cert.tbs_certificate.extensions {
for ext in extensions.iter() {
if ext.extn_id == CrlDistributionPoints::OID {
// Create a SliceReader from the byte slice
let mut reader = SliceReader::new(ext.extn_value.as_bytes()).map_err(|_| {
IntelApiError::InvalidParameter(
"Could not create reader from extension value",
)
})?;
// Now pass the reader to decode_value
if let Ok(dist_points) = Vec::<DistributionPoint>::decode(&mut reader) {
for point in dist_points {
if let Some(DistributionPointName::FullName(names)) =
point.distribution_point
{
for name in names {
if let GeneralName::UniformResourceIdentifier(uri) = name {
let uri = uri.as_str();
let crl_bytes = reqwest::get(uri).await?.bytes().await?;
println!("CRL bytes (hex): {}", hex::encode(&crl_bytes));
}
}
}
}
} else {
println!("Could not decode CRL distribution points");
}
}
}
}
}
println!("CRL bytes (hex): {}", hex::encode(&crl_data));
Ok(())
}