Skip to content

Commit b8b903a

Browse files
committed
refactor collateral service
Signed-off-by: Jun Kimura <jun.kimura@datachain.jp>
1 parent d84afaa commit b8b903a

File tree

5 files changed

+156
-134
lines changed

5 files changed

+156
-134
lines changed

app/src/commands/attestation.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use host::store::transaction::CommitStore;
1010
use remote_attestation::{
1111
dcap,
1212
dcap_simulation::{DCAP_SIM_ROOT_CA_PEM, DCAP_SIM_ROOT_KEY_PKCS8},
13+
dcap_utils::CollateralService,
1314
ias, zkdcap, IASMode,
1415
};
1516
use remote_attestation::{
@@ -262,6 +263,16 @@ impl SgxCollateralService {
262263
}
263264
}
264265

266+
impl From<SgxCollateralService> for CollateralService {
267+
fn from(service: SgxCollateralService) -> Self {
268+
Self {
269+
pccs_url: service.get_pccs_url(),
270+
certs_service_url: service.get_certs_service_url(),
271+
is_early_update: service.is_early_update,
272+
}
273+
}
274+
}
275+
265276
#[derive(Clone, Debug, Parser, PartialEq)]
266277
pub struct DCAPRemoteAttestation {
267278
/// Options for enclave
@@ -284,9 +295,7 @@ fn run_dcap_remote_attestation<E: EnclaveCommandAPI<S>, S: CommitStore>(
284295
dcap::run_dcap_ra(
285296
enclave.get_key_manager(),
286297
Address::from_hex_string(&cmd.enclave_key)?,
287-
&cmd.collateral_service.get_pccs_url(),
288-
&cmd.collateral_service.get_certs_service_url(),
289-
cmd.collateral_service.is_early_update,
298+
cmd.collateral_service.clone().into(),
290299
)?;
291300
Ok(())
292301
}
@@ -380,9 +389,7 @@ fn run_zkdcap_remote_attestation<E: EnclaveCommandAPI<S>, S: CommitStore>(
380389
mode,
381390
cmd.get_zkvm_program()?.as_ref(),
382391
cmd.disable_pre_execution,
383-
&cmd.collateral_service.get_pccs_url(),
384-
&cmd.collateral_service.get_certs_service_url(),
385-
cmd.collateral_service.is_early_update,
392+
cmd.collateral_service.clone().into(),
386393
)?;
387394
Ok(())
388395
}

modules/remote-attestation/src/dcap.rs

Lines changed: 11 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use crate::dcap_utils::DCAPRemoteAttestationResult;
1+
use crate::dcap_utils::{CollateralService, DCAPRemoteAttestationResult};
22
use crate::errors::Error;
33
use attestation_report::QEType;
44
use crypto::Address;
5-
use dcap_quote_verifier::cert::{get_x509_subject_cn, parse_certchain};
6-
use dcap_quote_verifier::sgx_extensions::extract_sgx_extensions;
5+
use dcap_quote_verifier::quotes::version_3::verify_quote_v3;
76
use dcap_quote_verifier::types::quotes::version_3::QuoteV3;
8-
use dcap_quote_verifier::types::utils::parse_pem;
9-
use dcap_quote_verifier::{collaterals::IntelCollateral, quotes::version_3::verify_quote_v3};
107
use keymanager::EnclaveKeyManager;
118
use lcp_types::Time;
129
use log::*;
@@ -27,18 +24,14 @@ pub const INTEL_ROOT_CA_HASH: [u8; 32] = [
2724
pub fn run_dcap_ra(
2825
key_manager: &EnclaveKeyManager,
2926
target_enclave_key: Address,
30-
pccs_url: &str,
31-
certs_service_url: &str,
32-
is_early_update: bool,
27+
collateral_service: CollateralService,
3328
) -> Result<(), Error> {
3429
let current_time = Time::now();
3530
let result = dcap_ra(
3631
key_manager,
3732
target_enclave_key,
3833
current_time,
39-
pccs_url,
40-
certs_service_url,
41-
is_early_update,
34+
collateral_service,
4235
)?;
4336

4437
key_manager
@@ -53,9 +46,7 @@ pub(crate) fn dcap_ra(
5346
key_manager: &EnclaveKeyManager,
5447
target_enclave_key: Address,
5548
current_time: Time,
56-
pccs_url: &str,
57-
certs_service_url: &str,
58-
is_early_update: bool,
49+
collateral_service: CollateralService,
5950
) -> Result<DCAPRemoteAttestationResult, Error> {
6051
let ek_info = key_manager.load(target_enclave_key).map_err(|e| {
6152
Error::key_manager(
@@ -74,7 +65,7 @@ pub(crate) fn dcap_ra(
7465

7566
let quote = QuoteV3::from_bytes(&raw_quote).map_err(Error::dcap_quote_verifier)?;
7667

77-
let collateral = get_collateral(pccs_url, certs_service_url, is_early_update, &quote)?;
68+
let collateral = collateral_service.get_collateral(&quote.signature.qe_cert_data)?;
7869
let output = verify_quote_v3(&quote, &collateral, current_time.as_unix_timestamp_secs())
7970
.map_err(Error::dcap_quote_verifier)?;
8071

@@ -107,104 +98,6 @@ fn rsgx_qe_get_quote(app_report: &sgx_report_t) -> Result<Vec<u8>, sgx_quote3_er
10798
}
10899
}
109100

110-
fn get_collateral(
111-
pccs_url: &str,
112-
certs_service_url: &str,
113-
is_early_update: bool,
114-
quote: &QuoteV3,
115-
) -> Result<IntelCollateral, Error> {
116-
let pccs_url = pccs_url.trim_end_matches('/');
117-
let certs_service_url = certs_service_url.trim_end_matches('/');
118-
let base_url = format!("{pccs_url}/sgx/certification/v4");
119-
if quote.signature.qe_cert_data.cert_data_type != 5 {
120-
return Err(Error::collateral("QE Cert Type must be 5".to_string()));
121-
}
122-
let certchain_pems = parse_pem(&quote.signature.qe_cert_data.cert_data)
123-
.map_err(|e| Error::collateral(format!("cannot parse QE cert chain: {}", e)))?;
124-
125-
let certchain = parse_certchain(&certchain_pems).map_err(Error::dcap_quote_verifier)?;
126-
if certchain.len() != 3 {
127-
return Err(Error::collateral(
128-
"QE Cert chain must have 3 certs".to_string(),
129-
));
130-
}
131-
132-
let update_policy = if is_early_update { "early" } else { "standard" };
133-
134-
// get the pck certificate
135-
let pck_cert = &certchain[0];
136-
let pck_cert_issuer = &certchain[1];
137-
138-
// get the SGX extension
139-
let sgx_extensions = extract_sgx_extensions(pck_cert).map_err(Error::dcap_quote_verifier)?;
140-
let (tcbinfo_bytes, sgx_tcb_signing_der) = {
141-
let fmspc = hex::encode_upper(sgx_extensions.fmspc);
142-
let res = http_get(format!(
143-
"{base_url}/tcb?fmspc={fmspc}&update={update_policy}"
144-
))?;
145-
let issuer_chain =
146-
extract_raw_certs(get_header(&res, "TCB-Info-Issuer-Chain")?.as_bytes())?;
147-
(res.bytes()?.to_vec(), issuer_chain[0].clone())
148-
};
149-
150-
let qeidentity_bytes = http_get(format!("{base_url}/qe/identity?update={update_policy}"))?
151-
.bytes()?
152-
.to_vec();
153-
let sgx_intel_root_ca_crl_der = http_get(format!("{certs_service_url}/IntelSGXRootCA.der"))?
154-
.bytes()?
155-
.to_vec();
156-
157-
let pck_crl_url = match get_x509_subject_cn(pck_cert_issuer).as_str() {
158-
"Intel SGX PCK Platform CA" => format!("{base_url}/pckcrl?ca=platform&encoding=der"),
159-
"Intel SGX PCK Processor CA" => format!("{base_url}/pckcrl?ca=processor&encoding=der"),
160-
cn => {
161-
return Err(Error::collateral(format!(
162-
"Unknown PCK Cert Subject CN: {}",
163-
cn
164-
)));
165-
}
166-
};
167-
let sgx_pck_crl_der = http_get(pck_crl_url)?.bytes()?.to_vec();
168-
169-
Ok(IntelCollateral {
170-
tcbinfo_bytes,
171-
qeidentity_bytes,
172-
sgx_intel_root_ca_der: INTEL_ROOT_CA.to_vec(),
173-
sgx_tcb_signing_der,
174-
sgx_intel_root_ca_crl_der,
175-
sgx_pck_crl_der,
176-
})
177-
}
178-
179-
fn get_header(res: &reqwest::blocking::Response, name: &str) -> Result<String, Error> {
180-
let value = res
181-
.headers()
182-
.get(name)
183-
.ok_or_else(|| Error::collateral(format!("missing header {}", name)))?
184-
.to_str()
185-
.map_err(|e| Error::collateral(format!("invalid header value: {}", e)))?;
186-
let value = urlencoding::decode(value)
187-
.map_err(|e| Error::collateral(format!("invalid header value: {}", e)))?;
188-
Ok(value.into_owned())
189-
}
190-
191-
fn extract_raw_certs(cert_chain: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
192-
Ok(pem::parse_many(cert_chain)
193-
.map_err(Error::pem)?
194-
.iter()
195-
.map(|i| i.contents().to_vec())
196-
.collect())
197-
}
198-
199-
fn http_get(url: String) -> Result<reqwest::blocking::Response, Error> {
200-
info!("get collateral from {}", url);
201-
let res = reqwest::blocking::get(&url).map_err(Error::reqwest_get)?;
202-
if !res.status().is_success() {
203-
return Err(Error::invalid_http_status(url, res.status()));
204-
}
205-
Ok(res)
206-
}
207-
208101
#[cfg(test)]
209102
mod tests {
210103
use super::*;
@@ -219,13 +112,14 @@ mod tests {
219112
fn test_dcap_collateral() {
220113
let quote = get_test_quote();
221114
let quote = QuoteV3::from_bytes(&quote).unwrap();
222-
let collateral = get_collateral(
115+
let service = CollateralService::new(
223116
"https://api.trustedservices.intel.com/",
224117
"https://certificates.trustedservices.intel.com/",
225118
false,
226-
&quote,
227-
)
228-
.unwrap();
119+
);
120+
let collateral = service
121+
.get_collateral(&quote.signature.qe_cert_data)
122+
.unwrap();
229123
let res = verify_quote_v3(&quote, &collateral, Time::now().as_unix_timestamp_secs());
230124
assert!(res.is_ok(), "{:?}", res);
231125
let output = res.unwrap();

modules/remote-attestation/src/dcap_utils.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,131 @@
1+
use crate::dcap::INTEL_ROOT_CA;
2+
use crate::errors::Error;
13
use attestation_report::DCAPQuote;
4+
use dcap_quote_verifier::cert::{get_x509_subject_cn, parse_certchain};
25
use dcap_quote_verifier::collaterals::IntelCollateral;
6+
use dcap_quote_verifier::sgx_extensions::extract_sgx_extensions;
7+
use dcap_quote_verifier::types::quotes::CertData;
8+
use dcap_quote_verifier::types::utils::parse_pem;
39
use dcap_quote_verifier::verifier::QuoteVerificationOutput;
410
use lcp_types::proto::lcp::service::enclave::v1::DcapCollateral;
511
use lcp_types::Time;
12+
use log::info;
13+
14+
#[derive(Debug)]
15+
pub struct CollateralService {
16+
pub pccs_url: String,
17+
pub certs_service_url: String,
18+
pub is_early_update: bool,
19+
}
20+
21+
impl CollateralService {
22+
pub fn new(pccs_ur: &str, certs_service_url: &str, is_early_update: bool) -> Self {
23+
CollateralService {
24+
pccs_url: pccs_ur.to_string(),
25+
certs_service_url: certs_service_url.to_string(),
26+
is_early_update,
27+
}
28+
}
29+
30+
pub fn get_collateral(&self, qe_cert_data: &CertData) -> Result<IntelCollateral, Error> {
31+
let pccs_url = self.pccs_url.trim_end_matches('/');
32+
let certs_service_url = self.certs_service_url.trim_end_matches('/');
33+
let base_url = format!("{pccs_url}/sgx/certification/v4");
34+
if qe_cert_data.cert_data_type != 5 {
35+
return Err(Error::collateral("QE Cert Type must be 5".to_string()));
36+
}
37+
let certchain_pems = parse_pem(&qe_cert_data.cert_data)
38+
.map_err(|e| Error::collateral(format!("cannot parse QE cert chain: {}", e)))?;
39+
40+
let certchain = parse_certchain(&certchain_pems).map_err(Error::dcap_quote_verifier)?;
41+
if certchain.len() != 3 {
42+
return Err(Error::collateral(
43+
"QE Cert chain must have 3 certs".to_string(),
44+
));
45+
}
46+
47+
let update_policy = if self.is_early_update {
48+
"early"
49+
} else {
50+
"standard"
51+
};
52+
53+
// get the pck certificate
54+
let pck_cert = &certchain[0];
55+
let pck_cert_issuer = &certchain[1];
56+
57+
// get the SGX extension
58+
let sgx_extensions =
59+
extract_sgx_extensions(pck_cert).map_err(Error::dcap_quote_verifier)?;
60+
let (tcbinfo_bytes, sgx_tcb_signing_der) = {
61+
let fmspc = hex::encode_upper(sgx_extensions.fmspc);
62+
let res = http_get(format!(
63+
"{base_url}/tcb?fmspc={fmspc}&update={update_policy}"
64+
))?;
65+
let issuer_chain =
66+
extract_raw_certs(get_header(&res, "TCB-Info-Issuer-Chain")?.as_bytes())?;
67+
(res.bytes()?.to_vec(), issuer_chain[0].clone())
68+
};
69+
70+
let qeidentity_bytes = http_get(format!("{base_url}/qe/identity?update={update_policy}"))?
71+
.bytes()?
72+
.to_vec();
73+
let sgx_intel_root_ca_crl_der =
74+
http_get(format!("{certs_service_url}/IntelSGXRootCA.der"))?
75+
.bytes()?
76+
.to_vec();
77+
78+
let pck_crl_url = match get_x509_subject_cn(pck_cert_issuer).as_str() {
79+
"Intel SGX PCK Platform CA" => format!("{base_url}/pckcrl?ca=platform&encoding=der"),
80+
"Intel SGX PCK Processor CA" => format!("{base_url}/pckcrl?ca=processor&encoding=der"),
81+
cn => {
82+
return Err(Error::collateral(format!(
83+
"Unknown PCK Cert Subject CN: {}",
84+
cn
85+
)));
86+
}
87+
};
88+
let sgx_pck_crl_der = http_get(pck_crl_url)?.bytes()?.to_vec();
89+
90+
Ok(IntelCollateral {
91+
tcbinfo_bytes,
92+
qeidentity_bytes,
93+
sgx_intel_root_ca_der: INTEL_ROOT_CA.to_vec(),
94+
sgx_tcb_signing_der,
95+
sgx_intel_root_ca_crl_der,
96+
sgx_pck_crl_der,
97+
})
98+
}
99+
}
100+
101+
fn get_header(res: &reqwest::blocking::Response, name: &str) -> Result<String, Error> {
102+
let value = res
103+
.headers()
104+
.get(name)
105+
.ok_or_else(|| Error::collateral(format!("missing header {}", name)))?
106+
.to_str()
107+
.map_err(|e| Error::collateral(format!("invalid header value: {}", e)))?;
108+
let value = urlencoding::decode(value)
109+
.map_err(|e| Error::collateral(format!("invalid header value: {}", e)))?;
110+
Ok(value.into_owned())
111+
}
112+
113+
fn extract_raw_certs(cert_chain: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
114+
Ok(pem::parse_many(cert_chain)
115+
.map_err(Error::pem)?
116+
.iter()
117+
.map(|i| i.contents().to_vec())
118+
.collect())
119+
}
120+
121+
fn http_get(url: String) -> Result<reqwest::blocking::Response, Error> {
122+
info!("get collateral from {}", url);
123+
let res = reqwest::blocking::get(&url).map_err(Error::reqwest_get)?;
124+
if !res.status().is_success() {
125+
return Err(Error::invalid_http_status(url, res.status()));
126+
}
127+
Ok(res)
128+
}
6129

7130
#[derive(Debug)]
8131
pub struct DCAPRemoteAttestationResult {

modules/remote-attestation/src/zkdcap.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
dcap::dcap_ra,
33
dcap_simulation::{dcap_ra_simulation, DCAPRASimulationOpts},
4-
dcap_utils::DCAPRemoteAttestationResult,
4+
dcap_utils::{CollateralService, DCAPRemoteAttestationResult},
55
errors::Error,
66
};
77
use anyhow::anyhow;
@@ -18,16 +18,13 @@ use zkvm::{
1818
verifier::verify_groth16_proof,
1919
};
2020

21-
#[allow(clippy::too_many_arguments)]
2221
pub fn run_zkdcap_ra(
2322
key_manager: &EnclaveKeyManager,
2423
target_enclave_key: Address,
2524
prover_mode: Risc0ProverMode,
2625
elf: &[u8],
2726
disable_pre_execution: bool,
28-
pccs_url: &str,
29-
certs_server_url: &str,
30-
is_early_update: bool,
27+
collateral_service: CollateralService,
3128
) -> Result<(), Error> {
3229
let image_id = compute_image_id(elf)
3330
.map_err(|e| Error::anyhow(anyhow!("cannot compute image id: {}", e)))?;
@@ -41,9 +38,7 @@ pub fn run_zkdcap_ra(
4138
key_manager,
4239
target_enclave_key,
4340
current_time,
44-
pccs_url,
45-
certs_server_url,
46-
is_early_update,
41+
collateral_service,
4742
)?;
4843

4944
zkdcap_ra(

0 commit comments

Comments
 (0)