1use pcs::{
15 CpuSvn, DcapArtifactIssuer, EncPpid, Fmspc, PceId, PceIsvsvn, PckCert, PckCerts, PckCrl, QeId, QeIdentitySigned,
16 TcbInfo, RawTcbEvaluationDataNumbers, Unverified,
17};
18use rustc_serialize::hex::ToHex;
19use std::borrow::Cow;
20use std::time::Duration;
21
22use super::common::*;
23use super::{
24 Client, ClientBuilder, Fetcher, PckCertIn, PckCertService, PckCertsIn, PckCertsService,
25 PckCrlIn, PckCrlService, PcsVersion, ProvisioningServiceApi, QeIdIn, QeIdService, StatusCode,
26 TcbEvaluationDataNumbersIn, TcbEvaluationDataNumbersService, TcbInfoIn, TcbInfoService, WithApiVersion,
27};
28use crate::Error;
29
30pub(crate) const INTEL_BASE_URL: &'static str = "https://api.trustedservices.intel.com";
31const SUBSCRIPTION_KEY_HEADER: &'static str = "Ocp-Apim-Subscription-Key";
32
33pub struct IntelProvisioningClientBuilder {
34 api_key: Option<String>,
35 api_version: PcsVersion,
36 client_builder: ClientBuilder,
37}
38
39impl IntelProvisioningClientBuilder {
40 pub fn new(api_version: PcsVersion) -> Self {
41 Self {
42 api_version,
43 api_key: None,
44 client_builder: ClientBuilder::new(),
45 }
46 }
47
48 pub fn set_api_key(&mut self, api_key: String) -> &mut Self {
49 self.api_key = Some(api_key);
50 self
51 }
52
53 pub fn set_retry_timeout(mut self, retry_timeout: Duration) -> Self {
54 self.client_builder = self.client_builder.set_retry_timeout(retry_timeout);
55 self
56 }
57
58 pub fn build<F: for<'a> Fetcher<'a>>(self, fetcher: F) -> Client<F> {
59 let pck_certs = PckCertsApi::new(self.api_version.clone(), self.api_key.clone());
60 let pck_cert = PckCertApi::new(self.api_version.clone(), self.api_key.clone());
61 let pck_crl = PckCrlApi::new(self.api_version.clone());
62 let qeid = QeIdApi::new(self.api_version.clone());
63 let tcbinfo = TcbInfoApi::new(self.api_version.clone());
64 let evaluation_data_numbers = TcbEvaluationDataNumbersApi::new(INTEL_BASE_URL.into());
65 self.client_builder
66 .build(pck_certs, pck_cert, pck_crl, qeid, tcbinfo, evaluation_data_numbers, fetcher)
67 }
68}
69
70pub struct PckCertsApi {
71 api_key: Option<String>,
72 api_version: PcsVersion,
73}
74
75impl PckCertsApi {
76 pub(crate) fn new(api_version: PcsVersion, api_key: Option<String>) -> PckCertsApi {
77 PckCertsApi {
78 api_version,
79 api_key,
80 }
81 }
82}
83
84impl<'inp> PckCertsService<'inp> for PckCertsApi {
85 fn build_input(
86 &'inp self,
87 enc_ppid: &'inp EncPpid,
88 pce_id: PceId,
89 ) -> <Self as ProvisioningServiceApi<'inp>>::Input {
90 PckCertsIn {
91 enc_ppid,
92 pce_id,
93 api_key: &self.api_key,
94 api_version: self.api_version.clone(),
95 }
96 }
97}
98
99impl<'inp> PckCertService<'inp> for PckCertApi {
100 fn build_input(
101 &'inp self,
102 encrypted_ppid: Option<&'inp EncPpid>,
103 pce_id: &'inp PceId,
104 cpu_svn: &'inp CpuSvn,
105 pce_isvsvn: PceIsvsvn,
106 qe_id: Option<&'inp QeId>,
107 ) -> <Self as ProvisioningServiceApi<'inp>>::Input {
108 PckCertIn {
109 encrypted_ppid,
110 pce_id,
111 cpu_svn,
112 pce_isvsvn,
113 qe_id,
114 api_key: &self.api_key,
115 api_version: self.api_version,
116 }
117 }
118}
119
120impl<'inp> ProvisioningServiceApi<'inp> for PckCertsApi {
123 type Input = PckCertsIn<'inp>;
124 type Output = PckCerts;
125
126 fn build_request(&self, input: &Self::Input) -> Result<(String, Vec<(String, String)>), Error> {
127 let api_version = input.api_version as u8;
128 let encrypted_ppid = input.enc_ppid.to_hex();
129 let pce_id = input.pce_id.to_le_bytes().to_hex();
130 let url = format!(
131 "{}/sgx/certification/v{}/pckcerts?encrypted_ppid={}&pceid={}",
132 INTEL_BASE_URL, api_version, encrypted_ppid, pce_id,
133 );
134 let headers = if let Some(api_key) = &input.api_key {
135 vec![(SUBSCRIPTION_KEY_HEADER.to_owned(), api_key.to_string())]
136 } else {
137 Vec::new()
138 };
139 Ok((url, headers))
140 }
141
142 fn validate_response(&self, status_code: StatusCode) -> Result<(), Error> {
143 match status_code {
144 StatusCode::Ok => Ok(()),
145 StatusCode::BadRequest => Err(Error::PCSError(status_code, "Invalid parameter")),
146 StatusCode::Unauthorized => Err(Error::PCSError(
147 status_code,
148 "Failed to authenticate or authorize the request (check your PCS key)",
149 )),
150 StatusCode::NotFound => Err(Error::PCSError(
151 status_code,
152 "Cannot find the requested certificate",
153 )),
154 StatusCode::TooManyRequests => Err(Error::PCSError(status_code, "Too many requests")),
155 StatusCode::InternalServerError => Err(Error::PCSError(
156 status_code,
157 "PCS suffered from an internal server error",
158 )),
159 StatusCode::ServiceUnavailable => Err(Error::PCSError(
160 status_code,
161 "PCS is temporarily unavailable",
162 )),
163 _ => Err(Error::PCSError(
164 status_code,
165 "Unexpected response from PCS server",
166 )),
167 }
168 }
169
170 fn parse_response(
171 &self,
172 response_body: String,
173 response_headers: Vec<(String, String)>,
174 _api_version: PcsVersion,
175 ) -> Result<Self::Output, Error> {
176 let ca_chain = parse_issuer_header(&response_headers, PCK_CERTIFICATE_ISSUER_CHAIN_HEADER)?;
177 PckCerts::parse(&response_body, ca_chain).map_err(|e| Error::OfflineAttestationError(e))
178 }
179}
180
181pub struct PckCertApi {
182 api_key: Option<String>,
183 api_version: PcsVersion,
184}
185
186impl PckCertApi {
187 pub(crate) fn new(api_version: PcsVersion, api_key: Option<String>) -> PckCertApi {
188 PckCertApi {
189 api_version,
190 api_key,
191 }
192 }
193}
194
195impl<'inp> ProvisioningServiceApi<'inp> for PckCertApi {
198 type Input = PckCertIn<'inp>;
199 type Output = PckCert<Unverified>;
200
201 fn build_request(&self, input: &Self::Input) -> Result<(String, Vec<(String, String)>), Error> {
202 let api_version = input.api_version as u8;
203 let encrypted_ppid = input
204 .encrypted_ppid
205 .ok_or(Error::NoEncPPID)
206 .map(|e_ppid| e_ppid.to_hex())?;
207 let cpusvn = input.cpu_svn.to_hex();
208 let pce_isvsvn = input.pce_isvsvn.to_le_bytes().to_hex();
209 let pce_id = input.pce_id.to_le_bytes().to_hex();
210 let url = format!(
211 "{}/sgx/certification/v{}/pckcert?encrypted_ppid={}&cpusvn={}&pcesvn={}&pceid={}",
212 INTEL_BASE_URL, api_version, encrypted_ppid, cpusvn, pce_isvsvn, pce_id,
213 );
214 let headers = if let Some(api_key) = input.api_key {
215 vec![(SUBSCRIPTION_KEY_HEADER.to_owned(), api_key.to_string())]
216 } else {
217 Vec::new()
218 };
219 Ok((url, headers))
220 }
221
222 fn validate_response(&self, status_code: StatusCode) -> Result<(), Error> {
223 match status_code {
224 StatusCode::Ok => Ok(()),
225 StatusCode::BadRequest => Err(Error::PCSError(status_code, "Invalid parameter")),
226 StatusCode::Unauthorized => Err(Error::PCSError(
227 status_code,
228 "Failed to authenticate or authorize the request (check your PCS key)",
229 )),
230 StatusCode::NotFound => Err(Error::PCSError(
231 status_code,
232 "Cannot find the requested certificate",
233 )),
234 StatusCode::TooManyRequests => Err(Error::PCSError(status_code, "Too many requests")),
235 StatusCode::InternalServerError => Err(Error::PCSError(
236 status_code,
237 "PCS suffered from an internal server error",
238 )),
239 StatusCode::ServiceUnavailable => Err(Error::PCSError(
240 status_code,
241 "PCS is temporarily unavailable",
242 )),
243 _ => Err(Error::PCSError(
244 status_code,
245 "Unexpected response from PCS server",
246 )),
247 }
248 }
249
250 fn parse_response(
251 &self,
252 response_body: String,
253 response_headers: Vec<(String, String)>,
254 _api_version: PcsVersion,
255 ) -> Result<Self::Output, Error> {
256 let ca_chain = parse_issuer_header(&response_headers, PCK_CERTIFICATE_ISSUER_CHAIN_HEADER)?;
257 Ok(PckCert::new(response_body, ca_chain))
258 }
259}
260
261pub struct PckCrlApi {
262 api_version: PcsVersion,
263}
264
265impl PckCrlApi {
266 pub fn new(api_version: PcsVersion) -> Self {
267 PckCrlApi { api_version }
268 }
269}
270
271impl<'inp> PckCrlService<'inp> for PckCrlApi {
272 fn build_input(&'inp self, ca: DcapArtifactIssuer) -> <Self as ProvisioningServiceApi<'inp>>::Input {
273 PckCrlIn {
274 api_version: self.api_version.clone(),
275 ca,
276 }
277 }
278}
279
280impl<'inp> ProvisioningServiceApi<'inp> for PckCrlApi {
283 type Input = PckCrlIn;
284 type Output = PckCrl<Unverified>;
285
286 fn build_request(&self, input: &Self::Input) -> Result<(String, Vec<(String, String)>), Error> {
287 let ca = match input.ca {
288 DcapArtifactIssuer::PCKProcessorCA => "processor",
289 DcapArtifactIssuer::PCKPlatformCA => "platform",
290 DcapArtifactIssuer::SGXRootCA => {
291 return Err(Error::PCSError(StatusCode::BadRequest, "Invalid ca parameter"));
292 },
293 };
294 let url = format!(
295 "{}/sgx/certification/v{}/pckcrl?ca={}&encoding=pem",
296 INTEL_BASE_URL, input.api_version as u8, ca,
297 );
298 Ok((url, Vec::new()))
299 }
300
301 fn validate_response(&self, status_code: StatusCode) -> Result<(), Error> {
302 match &status_code {
303 StatusCode::Ok => Ok(()),
304 StatusCode::BadRequest => Err(Error::PCSError(status_code, "Invalid parameter")),
305 StatusCode::Unauthorized => Err(Error::PCSError(
306 status_code,
307 "Failed to authenticate or authorize the request (check your PCS key)",
308 )),
309 StatusCode::InternalServerError => Err(Error::PCSError(
310 status_code,
311 "PCS suffered from an internal server error",
312 )),
313 StatusCode::ServiceUnavailable => Err(Error::PCSError(
314 status_code,
315 "PCS is temporarily unavailable",
316 )),
317 __ => Err(Error::PCSError(
318 status_code,
319 "Unexpected response from PCS server",
320 )),
321 }
322 }
323
324 fn parse_response(
325 &self,
326 response_body: String,
327 response_headers: Vec<(String, String)>,
328 _api_version: PcsVersion,
329 ) -> Result<Self::Output, Error> {
330 let ca_chain = parse_issuer_header(&response_headers, PCK_CRL_ISSUER_CHAIN_HEADER)?;
331 let crl = PckCrl::new(response_body, ca_chain)?;
332 Ok(crl)
333 }
334}
335
336pub struct TcbInfoApi {
337 api_version: PcsVersion,
338}
339
340impl TcbInfoApi {
341 pub fn new(api_version: PcsVersion) -> Self {
342 TcbInfoApi { api_version }
343 }
344}
345
346impl<'inp> TcbInfoService<'inp> for TcbInfoApi {
347 fn build_input(
348 &'inp self,
349 fmspc: &'inp Fmspc,
350 tcb_evaluation_data_number: Option<u16>,
351 ) -> <Self as ProvisioningServiceApi<'inp>>::Input {
352 TcbInfoIn {
353 api_version: self.api_version.clone(),
354 fmspc,
355 tcb_evaluation_data_number,
356 }
357 }
358}
359
360impl<'inp> ProvisioningServiceApi<'inp> for TcbInfoApi {
363 type Input = TcbInfoIn<'inp>;
364 type Output = TcbInfo;
365
366 fn build_request(&self, input: &Self::Input) -> Result<(String, Vec<(String, String)>), Error> {
367 let api_version = input.api_version as u8;
368 let fmspc = input.fmspc.as_bytes().to_hex();
369 let url = if let Some(evaluation_data_number) = input.tcb_evaluation_data_number {
370 format!(
371 "{}/sgx/certification/v{}/tcb?fmspc={}&tcbEvaluationDataNumber={}",
372 INTEL_BASE_URL, api_version, fmspc, evaluation_data_number)
373 } else {
374 format!(
375 "{}/sgx/certification/v{}/tcb?fmspc={}&update=early",
376 INTEL_BASE_URL, api_version, fmspc,
377 )
378 };
379 Ok((url, Vec::new()))
380 }
381
382 fn validate_response(&self, status_code: StatusCode) -> Result<(), Error> {
383 match &status_code {
384 StatusCode::Ok => Ok(()),
385 StatusCode::BadRequest => Err(Error::PCSError(status_code, "Invalid parameter")),
386 StatusCode::Unauthorized => Err(Error::PCSError(
387 status_code,
388 "Failed to authenticate or authorize the request (check your PCS key)",
389 )),
390 StatusCode::NotFound => {
391 Err(Error::PCSError(status_code, "TCB info cannot be found"))
392 }
393 StatusCode::Gone => {
394 Err(Error::PCSError(status_code, "TCB info no longer available"))
395 }
396 StatusCode::InternalServerError => Err(Error::PCSError(
397 status_code,
398 "PCS suffered from an internal server error",
399 )),
400 StatusCode::ServiceUnavailable => Err(Error::PCSError(
401 status_code,
402 "PCS is temporarily unavailable",
403 )),
404 __ => Err(Error::PCSError(
405 status_code,
406 "Unexpected response from PCS server",
407 )),
408 }
409 }
410
411 fn parse_response(
412 &self,
413 response_body: String,
414 response_headers: Vec<(String, String)>,
415 api_version: PcsVersion,
416 ) -> Result<Self::Output, Error> {
417 let key = match api_version {
418 PcsVersion::V3 => TCB_INFO_ISSUER_CHAIN_HEADER_V3,
419 PcsVersion::V4 => TCB_INFO_ISSUER_CHAIN_HEADER_V4,
420 };
421 let ca_chain = parse_issuer_header(&response_headers, key)?;
422 let tcb_info = TcbInfo::parse(&response_body, ca_chain)?;
423 Ok(tcb_info)
424 }
425}
426
427pub struct QeIdApi {
428 api_version: PcsVersion,
429}
430
431impl QeIdApi {
432 pub fn new(api_version: PcsVersion) -> Self {
433 QeIdApi { api_version }
434 }
435}
436
437impl<'inp> QeIdService<'inp> for QeIdApi {
438 fn build_input(&'inp self, tcb_evaluation_data_number: Option<u16>) -> <Self as ProvisioningServiceApi<'inp>>::Input {
439 QeIdIn {
440 api_version: self.api_version.clone(),
441 tcb_evaluation_data_number,
442 }
443 }
444}
445
446impl<'inp> ProvisioningServiceApi<'inp> for QeIdApi {
449 type Input = QeIdIn;
450 type Output = QeIdentitySigned;
451
452 fn build_request(&self, input: &Self::Input) -> Result<(String, Vec<(String, String)>), Error> {
453 let api_version = input.api_version as u8;
454 let url = if let Some(tcb_evaluation_data_number) = input.tcb_evaluation_data_number {
455 format!(
456 "{}/sgx/certification/v{}/qe/identity?tcbEvaluationDataNumber={}",
457 INTEL_BASE_URL, api_version, tcb_evaluation_data_number
458 )
459 } else {
460 format!(
461 "{}/sgx/certification/v{}/qe/identity?update=early",
462 INTEL_BASE_URL, api_version,
463 )
464 };
465 Ok((url, Vec::new()))
466 }
467
468 fn validate_response(&self, status_code: StatusCode) -> Result<(), Error> {
469 match &status_code {
470 StatusCode::Ok => Ok(()),
471 StatusCode::BadRequest => Err(Error::PCSError(status_code, "Invalid parameter")),
472 StatusCode::Unauthorized => Err(Error::PCSError(
473 status_code,
474 "Failed to authenticate or authorize the request (check your PCS key)",
475 )),
476 StatusCode::NotFound => {
477 Err(Error::PCSError(status_code, "QE identity Cannot be found"))
478 }
479 StatusCode::InternalServerError => Err(Error::PCSError(
480 status_code,
481 "PCS suffered from an internal server error",
482 )),
483 StatusCode::ServiceUnavailable => Err(Error::PCSError(
484 status_code,
485 "PCS is temporarily unavailable",
486 )),
487 __ => Err(Error::PCSError(
488 status_code,
489 "Unexpected response from PCS server",
490 )),
491 }
492 }
493
494 fn parse_response(
495 &self,
496 response_body: String,
497 response_headers: Vec<(String, String)>,
498 _api_version: PcsVersion,
499 ) -> Result<Self::Output, Error> {
500 let ca_chain = parse_issuer_header(&response_headers, ENCLAVE_ID_ISSUER_CHAIN_HEADER)?;
501 let id = QeIdentitySigned::parse(&response_body, ca_chain)?;
502 Ok(id)
503 }
504}
505
506pub struct TcbEvaluationDataNumbersApi {
507 base_url: Cow<'static, str>,
508}
509
510impl TcbEvaluationDataNumbersApi {
511 pub fn new(base_url: Cow<'static, str>) -> Self {
512 TcbEvaluationDataNumbersApi {
513 base_url,
514 }
515 }
516}
517
518impl<'inp> TcbEvaluationDataNumbersService<'inp> for TcbEvaluationDataNumbersApi {
519 fn build_input(&self)
520 -> <Self as ProvisioningServiceApi<'inp>>::Input {
521 TcbEvaluationDataNumbersIn
522 }
523}
524
525impl<'inp> ProvisioningServiceApi<'inp> for TcbEvaluationDataNumbersApi {
528 type Input = TcbEvaluationDataNumbersIn;
529 type Output = RawTcbEvaluationDataNumbers;
530
531 fn build_request(&self, input: &Self::Input) -> Result<(String, Vec<(String, String)>), Error> {
532 let url = format!(
533 "{}/sgx/certification/v{}/tcbevaluationdatanumbers",
534 self.base_url, input.api_version() as u8,
535 );
536 Ok((url, Vec::new()))
537 }
538
539 fn validate_response(&self, status_code: StatusCode) -> Result<(), Error> {
540 match &status_code {
541 StatusCode::Ok => Ok(()),
542 StatusCode::InternalServerError => Err(Error::PCSError(
543 status_code,
544 "PCS suffered from an internal server error",
545 )),
546 StatusCode::ServiceUnavailable => Err(Error::PCSError(
547 status_code,
548 "PCS is temporarily unavailable",
549 )),
550 __ => Err(Error::PCSError(
551 status_code,
552 "Unexpected response from PCS server",
553 )),
554 }
555 }
556
557 fn parse_response(
558 &self,
559 response_body: String,
560 response_headers: Vec<(String, String)>,
561 _api_version: PcsVersion,
562 ) -> Result<Self::Output, Error> {
563 let ca_chain = parse_issuer_header(&response_headers, TCB_EVALUATION_DATA_NUMBERS_ISSUER_CHAIN)?;
564 RawTcbEvaluationDataNumbers::parse(&response_body, ca_chain).map_err(|e| e.into())
565 }
566}
567
568#[cfg(all(test, feature = "reqwest"))]
569mod tests {
570 use std::convert::TryFrom;
571 use std::hash::Hash;
572 use std::hash::Hasher;
573 use std::path::PathBuf;
574 use std::time::Duration;
575
576 use pcs::{
577 DcapArtifactIssuer, EnclaveIdentity, Fmspc, PckID, Platform, RawTcbEvaluationDataNumbers,
578 TcbEvaluationDataNumbers,
579 };
580
581 use crate::provisioning_client::{
582 test_helpers, IntelProvisioningClientBuilder, PcsVersion, ProvisioningClient,
583 };
584 use crate::reqwest_client;
585 use std::hash::DefaultHasher;
586
587 const PCKID_TEST_FILE: &str = "./tests/data/pckid_retrieval.csv";
588 const OUTPUT_TEST_DIR: &str = "./tests/data/";
589 const TIME_RETRY_TIMEOUT: Duration = Duration::from_secs(180);
590
591 fn pcs_api_key() -> Option<String> {
592 let api_key_option = std::env::var("PCS_API_KEY").ok();
593 if let Some(api_key) = api_key_option.as_ref() {
594 assert!(!api_key.is_empty(), "Empty string in PCS_API_KEY");
595 }
596 api_key_option
597 }
598
599 #[test]
600 pub fn pcks() {
601 for api_version in [PcsVersion::V3, PcsVersion::V4] {
602 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
603 .set_retry_timeout(TIME_RETRY_TIMEOUT);
604 if api_version == PcsVersion::V3 {
605 if let Some(pcs_api_key) = pcs_api_key() {
606 intel_builder.set_api_key(pcs_api_key);
607 } else {
608 continue;
611 }
612 }
613 let client = intel_builder.build(reqwest_client());
614
615 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
616 .unwrap()
617 .iter()
618 {
619 let pcks = client
620 .pckcerts(&pckid.enc_ppid, pckid.pce_id.clone())
621 .unwrap();
622 assert_eq!(
623 test_helpers::get_cert_subject(pcks.ca_chain().last().unwrap()),
624 "Intel SGX Root CA"
625 );
626 pcks.fmspc().unwrap();
627 pcks.store(OUTPUT_TEST_DIR, pckid.qe_id.as_slice()).unwrap();
628 }
629 }
630 }
631
632 #[test]
633 pub fn pcks_cached() {
634 for api_version in [PcsVersion::V3, PcsVersion::V4] {
635 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
636 .set_retry_timeout(TIME_RETRY_TIMEOUT);
637 if api_version == PcsVersion::V3 {
638 if let Some(pcs_api_key) = pcs_api_key() {
639 intel_builder.set_api_key(pcs_api_key);
640 } else {
641 continue;
644 }
645 }
646 let client = intel_builder.build(reqwest_client());
647
648 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
649 .unwrap()
650 .iter()
651 {
652 let pcks = client
653 .pckcerts(&pckid.enc_ppid, pckid.pce_id.clone())
654 .unwrap();
655
656 {
658 let mut cache = client.pckcerts_service.cache.lock().unwrap();
659
660 assert!(cache.len() > 0);
661
662 let (cached_pcks, _) = {
663 let mut hasher = DefaultHasher::new();
664 let input = client
665 .pckcerts_service
666 .pcs_service()
667 .build_input(&pckid.enc_ppid, pckid.pce_id.clone());
668 input.hash(&mut hasher);
669
670 cache
671 .get_mut(&hasher.finish())
672 .expect("Can't find key in cache")
673 .to_owned()
674 };
675
676 assert_eq!(pcks.fmspc().unwrap(), cached_pcks.fmspc().unwrap());
677 assert_eq!(pcks, cached_pcks);
678 }
679
680 let pcks_from_service = client
682 .pckcerts(&pckid.enc_ppid, pckid.pce_id.clone())
683 .unwrap();
684
685 assert_eq!(pcks, pcks_from_service);
686 assert_eq!(pcks.fmspc().unwrap(), pcks_from_service.fmspc().unwrap());
687 }
688 }
689 }
690
691 #[test]
692 pub fn pck() {
693 for api_version in [PcsVersion::V3, PcsVersion::V4] {
694 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
695 .set_retry_timeout(TIME_RETRY_TIMEOUT);
696 if api_version == PcsVersion::V3 {
697 if let Some(pcs_api_key) = pcs_api_key() {
698 intel_builder.set_api_key(pcs_api_key);
699 } else {
700 continue;
703 }
704 }
705 let client = intel_builder.build(reqwest_client());
706 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
707 .unwrap()
708 .iter()
709 {
710 let pck = client
711 .pckcert(
712 Some(&pckid.enc_ppid),
713 &pckid.pce_id,
714 &pckid.cpu_svn,
715 pckid.pce_isvsvn,
716 None,
717 )
718 .unwrap();
719 assert_eq!(
720 test_helpers::get_cert_subject(pck.ca_chain().last().unwrap()),
721 "Intel SGX Root CA"
722 );
723 }
724 }
725 }
726
727 #[test]
728 pub fn pck_cached() {
729 for api_version in [PcsVersion::V3, PcsVersion::V4] {
730 let root_ca = include_bytes!("../../tests/data/root_SGX_CA_der.cert");
731 let root_cas = [&root_ca[..]];
732 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
733 .set_retry_timeout(TIME_RETRY_TIMEOUT);
734 if api_version == PcsVersion::V3 {
735 if let Some(pcs_api_key) = pcs_api_key() {
736 intel_builder.set_api_key(pcs_api_key);
737 } else {
738 continue;
741 }
742 }
743 let client = intel_builder.build(reqwest_client());
744 let crl_processor = client
745 .pckcrl(DcapArtifactIssuer::PCKProcessorCA)
746 .unwrap()
747 .crl_as_pem()
748 .to_owned();
749 let crl_platform = client
750 .pckcrl(DcapArtifactIssuer::PCKPlatformCA)
751 .unwrap()
752 .crl_as_pem()
753 .to_owned();
754 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
755 .unwrap()
756 .iter()
757 {
758 let pck = client
759 .pckcert(
760 Some(&pckid.enc_ppid),
761 &pckid.pce_id,
762 &pckid.cpu_svn,
763 pckid.pce_isvsvn,
764 None,
765 )
766 .unwrap();
767 let pck = pck
768 .clone()
769 .verify(&root_cas, Some(&crl_processor))
770 .or(pck.clone().verify(&root_cas, Some(&crl_platform)))
771 .unwrap();
772
773 {
775 let mut cache = client.pckcert_service.cache.lock().unwrap();
776
777 assert!(cache.len() > 0);
778
779 let (cached_pck, _) = {
780 let mut hasher = DefaultHasher::new();
781 let input = client.pckcert_service.pcs_service().build_input(
782 Some(&pckid.enc_ppid),
783 &pckid.pce_id,
784 &pckid.cpu_svn,
785 pckid.pce_isvsvn,
786 None,
787 );
788 input.hash(&mut hasher);
789
790 cache
791 .get_mut(&hasher.finish())
792 .expect("Can't find key in cache")
793 .to_owned()
794 };
795
796 assert_eq!(
797 pck.fmspc().unwrap(),
798 cached_pck
799 .clone()
800 .verify(&root_cas, None)
801 .unwrap()
802 .fmspc()
803 .unwrap()
804 );
805 assert_eq!(pck.ca_chain(), cached_pck.ca_chain());
806 }
807
808 let pck_from_service = client
810 .pckcert(
811 Some(&pckid.enc_ppid),
812 &pckid.pce_id,
813 &pckid.cpu_svn,
814 pckid.pce_isvsvn,
815 None,
816 )
817 .unwrap();
818
819 assert_eq!(
820 pck.fmspc().unwrap(),
821 pck_from_service
822 .clone()
823 .verify(&root_cas, None)
824 .unwrap()
825 .fmspc()
826 .unwrap()
827 );
828 assert_eq!(pck.ca_chain(), pck_from_service.ca_chain());
829 }
830 }
831 }
832
833 #[test]
834 pub fn tcb_info() {
835 for api_version in [PcsVersion::V3, PcsVersion::V4] {
836 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
837 .set_retry_timeout(TIME_RETRY_TIMEOUT);
838 if api_version == PcsVersion::V3 {
839 if let Some(pcs_api_key) = pcs_api_key() {
840 intel_builder.set_api_key(pcs_api_key);
841 } else {
842 continue;
845 }
846 }
847 let client = intel_builder.build(reqwest_client());
848 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
849 .unwrap()
850 .iter()
851 {
852 let pckcerts = client
853 .pckcerts(&pckid.enc_ppid, pckid.pce_id.clone())
854 .unwrap();
855 assert!(client
856 .tcbinfo(&pckcerts.fmspc().unwrap(), None)
857 .and_then(|tcb| { Ok(tcb.store(OUTPUT_TEST_DIR).unwrap()) })
858 .is_ok());
859 }
860 }
861 }
862
863 #[test]
864 pub fn tcb_info_with_evaluation_data_number() {
865 let intel_builder = IntelProvisioningClientBuilder::new(PcsVersion::V4)
866 .set_retry_timeout(TIME_RETRY_TIMEOUT);
867 let client = intel_builder.build(reqwest_client());
868 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
869 .unwrap()
870 .iter()
871 {
872 let pckcerts = client
873 .pckcerts(&pckid.enc_ppid, pckid.pce_id.clone())
874 .unwrap();
875 let fmspc = pckcerts.fmspc().unwrap();
876
877 let evaluation_data_numbers = client
878 .tcb_evaluation_data_numbers()
879 .unwrap()
880 .evaluation_data_numbers()
881 .unwrap();
882
883 for number in evaluation_data_numbers.numbers() {
884 let tcb = match client.tcbinfo(&fmspc, Some(number.number())) {
885 Ok(tcb) => tcb,
886 Err(super::Error::PCSError(status_code, _)) if status_code == super::StatusCode::Gone => continue,
890 res @Err(_) => res.unwrap(),
891 };
892 tcb.store(OUTPUT_TEST_DIR).unwrap();
893 }
894 }
895 }
896
897 #[test]
898 pub fn tcb_info_cached() {
899 for api_version in [PcsVersion::V3, PcsVersion::V4] {
900 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
901 .set_retry_timeout(TIME_RETRY_TIMEOUT);
902 if api_version == PcsVersion::V3 {
903 if let Some(pcs_api_key) = pcs_api_key() {
904 intel_builder.set_api_key(pcs_api_key);
905 } else {
906 continue;
909 }
910 }
911 let client = intel_builder.build(reqwest_client());
912 for pckid in PckID::parse_file(&PathBuf::from(PCKID_TEST_FILE).as_path())
913 .unwrap()
914 .iter()
915 {
916 let pckcerts = client
917 .pckcerts(&pckid.enc_ppid, pckid.pce_id.clone())
918 .unwrap();
919 let fmspc = pckcerts.fmspc().unwrap();
920 let tcb_info = client.tcbinfo(&fmspc, None).unwrap();
921
922 {
924 let mut cache = client.tcbinfo_service.cache.lock().unwrap();
925
926 assert!(cache.len() > 0);
927
928 let (cached_tcb_info, _) = {
929 let mut hasher = DefaultHasher::new();
930 let input = client
931 .tcbinfo_service
932 .pcs_service()
933 .build_input(&fmspc, None);
934 input.hash(&mut hasher);
935
936 cache
937 .get_mut(&hasher.finish())
938 .expect("Can't find key in cache")
939 .to_owned()
940 };
941
942 assert_eq!(tcb_info, cached_tcb_info);
943 }
944
945 let tcb_info_from_service = client.tcbinfo(&fmspc, None).unwrap();
947
948 assert_eq!(tcb_info, tcb_info_from_service);
949 }
950 }
951 }
952
953 #[test]
954 pub fn pckcrl() {
955 for ca in [
956 DcapArtifactIssuer::PCKProcessorCA,
957 DcapArtifactIssuer::PCKPlatformCA,
958 ] {
959 for api_version in [PcsVersion::V3, PcsVersion::V4] {
960 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
961 .set_retry_timeout(TIME_RETRY_TIMEOUT);
962 if api_version == PcsVersion::V3 {
963 if let Some(pcs_api_key) = pcs_api_key() {
964 intel_builder.set_api_key(pcs_api_key);
965 } else {
966 continue;
969 }
970 }
971 let client = intel_builder.build(reqwest_client());
972 assert!(client
973 .pckcrl(ca)
974 .and_then(|crl| { Ok(crl.write_to_file(OUTPUT_TEST_DIR).unwrap()) })
975 .is_ok());
976 }
977 }
978 }
979
980 #[test]
981 pub fn pckcrl_cached() {
982 for ca in [
983 DcapArtifactIssuer::PCKProcessorCA,
984 DcapArtifactIssuer::PCKPlatformCA,
985 ] {
986 for api_version in [PcsVersion::V3, PcsVersion::V4] {
987 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
988 .set_retry_timeout(TIME_RETRY_TIMEOUT);
989 if api_version == PcsVersion::V3 {
990 if let Some(pcs_api_key) = pcs_api_key() {
991 intel_builder.set_api_key(pcs_api_key);
992 } else {
993 continue;
996 }
997 }
998 let client = intel_builder.build(reqwest_client());
999 let pckcrl = client.pckcrl(ca).unwrap();
1000
1001 {
1003 let mut cache = client.pckcrl_service.cache.lock().unwrap();
1004
1005 assert!(cache.len() > 0);
1006
1007 let (cached_pckcrl, _) = {
1008 let mut hasher = DefaultHasher::new();
1009 let input = client.pckcrl_service.pcs_service().build_input(ca);
1010 input.hash(&mut hasher);
1011
1012 cache
1013 .get_mut(&hasher.finish())
1014 .expect("Can't find key in cache")
1015 .to_owned()
1016 };
1017
1018 assert_eq!(pckcrl, cached_pckcrl);
1019 }
1020
1021 let pckcrl_from_service = client.pckcrl(ca).unwrap();
1023
1024 assert_eq!(pckcrl, pckcrl_from_service);
1025 }
1026 }
1027 }
1028
1029 #[test]
1030 pub fn qe_identity() {
1031 for api_version in [PcsVersion::V3, PcsVersion::V4] {
1032 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
1033 .set_retry_timeout(TIME_RETRY_TIMEOUT);
1034 if api_version == PcsVersion::V3 {
1035 if let Some(pcs_api_key) = pcs_api_key() {
1036 intel_builder.set_api_key(pcs_api_key);
1037 } else {
1038 continue;
1041 }
1042 }
1043 let client = intel_builder.build(reqwest_client());
1044 let qe_id = client.qe_identity(None);
1045 assert!(qe_id.is_ok());
1046 assert!(qe_id.unwrap().write_to_file(OUTPUT_TEST_DIR).is_ok());
1047 }
1048 }
1049
1050 #[test]
1051 pub fn qe_identity_cached() {
1052 for api_version in [PcsVersion::V3, PcsVersion::V4] {
1053 let mut intel_builder = IntelProvisioningClientBuilder::new(api_version)
1054 .set_retry_timeout(TIME_RETRY_TIMEOUT);
1055 if api_version == PcsVersion::V3 {
1056 if let Some(pcs_api_key) = pcs_api_key() {
1057 intel_builder.set_api_key(pcs_api_key);
1058 } else {
1059 continue;
1062 }
1063 }
1064 let client = intel_builder.build(reqwest_client());
1065 let qe_id = client.qe_identity(None).unwrap();
1066
1067 {
1069 let mut cache = client.qeid_service.cache.lock().unwrap();
1070
1071 assert!(cache.len() > 0);
1072
1073 let (cached_qeid, _) = {
1074 let mut hasher = DefaultHasher::new();
1075 let input = client.qeid_service.pcs_service().build_input(None);
1076 input.hash(&mut hasher);
1077
1078 cache
1079 .get_mut(&hasher.finish())
1080 .expect("Can't find key in cache")
1081 .to_owned()
1082 };
1083
1084 assert_eq!(qe_id, cached_qeid);
1085 }
1086
1087 let qeid_from_service = client.qe_identity(None).unwrap();
1089
1090 assert_eq!(qe_id, qeid_from_service);
1091 }
1092 }
1093
1094 #[test]
1095 pub fn tcb_evaluation_data_numbers() {
1096 let root_ca = include_bytes!("../../tests/data/root_SGX_CA_der.cert");
1097 let root_cas = [&root_ca[..]];
1098 let intel_builder = IntelProvisioningClientBuilder::new(PcsVersion::V4)
1099 .set_retry_timeout(TIME_RETRY_TIMEOUT);
1100 let client = intel_builder.build(reqwest_client());
1101 let eval_numbers = client.tcb_evaluation_data_numbers().unwrap();
1102
1103 let eval_numbers2 = serde_json::ser::to_vec(&eval_numbers)
1104 .and_then(|v| serde_json::from_slice::<RawTcbEvaluationDataNumbers>(&v))
1105 .unwrap();
1106 assert_eq!(eval_numbers, eval_numbers2);
1107
1108 let fmspc = Fmspc::try_from("90806f000000").unwrap();
1109 let eval_numbers: TcbEvaluationDataNumbers =
1110 eval_numbers.verify(&root_cas, Platform::SGX).unwrap();
1111 for number in eval_numbers.numbers().map(|n| n.number()) {
1112 let qe_identity = match client.qe_identity(Some(number)) {
1113 Ok(id) => id,
1114 Err(super::Error::PCSError(status_code, _)) if status_code == super::StatusCode::Gone => continue,
1118 res @Err(_) => res.unwrap(),
1119 };
1120 let verified_qe_id = qe_identity
1121 .verify(&root_cas, EnclaveIdentity::QE)
1122 .unwrap();
1123 assert_eq!(verified_qe_id.tcb_evaluation_data_number(), u64::from(number));
1124
1125 let tcb_info = client
1126 .tcbinfo(&fmspc, Some(number))
1127 .unwrap()
1128 .verify(&root_cas, Platform::SGX, 2)
1129 .unwrap();
1130 assert_eq!(tcb_info.tcb_evaluation_data_number(), u64::from(number));
1131 }
1132 }
1133}