dcap_qvl/lib.rs
1//! # dcap-qvl
2//!
3//! Verify Intel SGX and TDX (DCAP — Data Center Attestation Primitives)
4//! attestation quotes, in pure Rust. Supports both SGX (Software Guard
5//! Extensions) and TDX (Trust Domain Extensions).
6//!
7//! # What it does
8//! - Verify SGX and TDX quotes against Intel's trust chain
9//! - Fetch collateral from a PCCS or Intel PCS, or verify fully offline
10//! - Extract report fields (measurements, report data, TCB status) from a quote
11//!
12//! By default the collateral client uses Phala Network's PCCS
13//! (`https://pccs.phala.network`).
14//!
15//! Native bindings for Python, JavaScript, Go, Kotlin, and Swift are published
16//! from the same core — see the [project README][readme].
17//!
18//! [readme]: https://github.com/Phala-Network/dcap-qvl
19//!
20//! # Example
21//!
22//! ```no_run
23//! use dcap_qvl::collateral::CollateralClient;
24//! use dcap_qvl::verify::verify;
25//! use dcap_qvl::PHALA_PCCS_URL;
26//!
27//! #[tokio::main]
28//! async fn main() {
29//! let quote = std::fs::read("quote").expect("quote file not found");
30//!
31//! // Use default Phala PCCS, or override with custom URL
32//! let pccs_url = std::env::var("PCCS_URL").unwrap_or_else(|_| PHALA_PCCS_URL.to_string());
33//! let collateral = CollateralClient::with_default_http(pccs_url)
34//! .expect("failed to build HTTP client")
35//! .fetch("e)
36//! .await
37//! .expect("failed to get collateral");
38//!
39//! let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
40//! let report = verify("e, &collateral, now).expect("failed to verify quote");
41//! println!("{report:?}");
42//! }
43//! ```
44//!
45//! # Crypto backends
46//!
47//! Two backends are available: **ring** (optimized, uses assembly) and
48//! **rustcrypto** (pure Rust). Both are enabled by default and `ring` takes
49//! priority. For predictable behavior, call an explicit backend module:
50//!
51//! ```ignore
52//! use dcap_qvl::verify::ring::verify; // always ring
53//! use dcap_qvl::verify::rustcrypto::verify; // always rustcrypto
54//! ```
55//!
56//! The top-level [`verify::verify`] selects the backend from enabled features:
57//! `ring` wins when both are on, `rustcrypto` is used when only it is enabled,
58//! and with neither it is unavailable: use [`verify::QuoteVerifier`] with your own
59//! [`config::Config`]. Because Cargo features are additive,
60//! any crate in your dependency tree that enables `ring` makes the top-level
61//! `verify()` use ring — reach for the explicit modules to avoid surprises.
62//!
63//! # Feature flags
64//!
65//! ```toml
66//! # Default: both backends, std, the PCCS collateral client, and x509 parsing.
67//! dcap-qvl = "0.6"
68//!
69//! # Minimal verifier for WASM / on-chain (no PCCS client):
70//! dcap-qvl = { version = "0.6", default-features = false, features = ["std", "rustcrypto", "default-x509"] }
71//! ```
72//!
73//! `no_std` builds are supported by disabling default features. The `report`
74//! feature pulls in the async PCCS collateral client (`reqwest` + `tokio`); drop
75//! it for offline verification on size-constrained targets.
76//!
77//! # On-chain gas
78//!
79//! On `wasm32`, `rustcrypto` verifies signatures faster than `ring`. On NEAR a
80//! full `verify` costs about 98 TGas with `rustcrypto` and 124 TGas with `ring`,
81//! built with `opt-level = 3`. Size-oriented profiles cost much more gas:
82//! `opt-level = "z"` raises it to about 169 TGas with `rustcrypto` and 135 TGas
83//! with `ring`. See `tests/near` in the repository for the benchmark.
84
85#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
86
87#[macro_use]
88extern crate alloc;
89
90use alloc::{string::String, vec::Vec};
91use scale::{Decode, Encode};
92use serde::{Deserialize, Serialize};
93
94#[cfg(feature = "borsh_schema")]
95use borsh::BorshSchema;
96#[cfg(feature = "borsh")]
97use borsh::{BorshDeserialize, BorshSerialize};
98
99#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
100#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
101#[cfg_attr(feature = "borsh_schema", derive(BorshSchema))]
102pub struct QuoteCollateralV3 {
103 pub pck_crl_issuer_chain: String,
104 #[serde(with = "serde_bytes")]
105 pub root_ca_crl: Vec<u8>,
106 #[serde(with = "serde_bytes")]
107 pub pck_crl: Vec<u8>,
108 pub tcb_info_issuer_chain: String,
109 pub tcb_info: String,
110 #[serde(with = "serde_bytes")]
111 pub tcb_info_signature: Vec<u8>,
112 pub qe_identity_issuer_chain: String,
113 pub qe_identity: String,
114 #[serde(with = "serde_bytes")]
115 pub qe_identity_signature: Vec<u8>,
116 /// PCK certificate chain (PEM format).
117 /// For cert_type 5: extracted from quote during collateral fetch.
118 /// For cert_type 3: fetched from PCCS using encrypted PPID.
119 /// Used by verify() for offline verification.
120 #[serde(default, skip_serializing_if = "Option::is_none")]
121 pub pck_certificate_chain: Option<String>,
122}
123
124impl From<&QuoteCollateralV3> for QuoteCollateralV3 {
125 fn from(value: &QuoteCollateralV3) -> Self {
126 value.clone()
127 }
128}
129
130#[cfg(all(feature = "report", not(feature = "_anycrypto")))]
131compile_error!("the `report` feature requires the `ring` or `rustcrypto` feature");
132
133#[cfg(feature = "report")]
134pub mod collateral;
135
136#[cfg(feature = "report")]
137pub use collateral::PHALA_PCCS_URL;
138
139#[cfg(feature = "report")]
140pub mod http;
141
142pub mod config;
143#[cfg(all(feature = "default-x509", feature = "_anycrypto"))]
144pub mod configs;
145pub mod crypto;
146pub mod oids;
147#[cfg(feature = "default-x509")]
148pub mod signature;
149#[cfg(feature = "default-x509")]
150pub mod x509;
151
152mod constants;
153pub mod intel;
154pub mod policy;
155pub mod qe_identity;
156pub mod tcb_info;
157mod utils;
158
159pub use constants::{CpuSvn, Fmspc, MrEnclave, MrSigner, Svn, INTEL_QE_VENDOR_ID};
160pub use policy::{
161 PckCertFlag, PckIdentity, PlatformInfo, Policy, QeInfo, QuoteClaims, QuotePolicy,
162 QuotePolicyConfig, TcbVerdict,
163};
164pub use qe_identity::{QeIdentity, QeTcb, QeTcbLevel};
165pub use tcb_info::{Tcb, TcbComponents, TcbInfo, TcbLevel, TcbStatus, TcbStatusWithAdvisory};
166
167pub mod quote;
168pub mod verify;
169
170#[cfg(feature = "python")]
171pub mod python;
172
173#[cfg(feature = "go")]
174mod ffi;
175
176#[cfg(feature = "python")]
177use pyo3::prelude::*;
178
179#[cfg(feature = "python")]
180#[pymodule]
181fn _dcap_qvl(m: &Bound<'_, PyModule>) -> PyResult<()> {
182 python::register_module(m)
183}