1use std::borrow::Cow;
9use std::cmp::Ordering;
10use std::convert::{TryFrom, TryInto};
11use std::marker::PhantomData;
12use std::mem;
13use std::path::PathBuf;
14
15use percent_encoding::percent_decode;
16use pkix::pem::{self, PEM_CERTIFICATE};
17use pkix::types::ObjectIdentifier;
18use pkix::x509::GenericCertificate;
19use pkix::FromBer;
20use serde::{Deserialize, Deserializer, Serialize, Serializer};
21use sgx_pkix::oid::{self, SGX_EXTENSION};
22use yasna::{ASN1Error, ASN1ErrorKind, ASN1Result, BERDecodable, BERReader, BERReaderSeq};
23#[cfg(feature = "verify")]
24use {
25 mbedtls::alloc::{Box as MbedtlsBox, List as MbedtlsList},
26 mbedtls::ecp::EcPoint,
27 mbedtls::x509::certificate::Certificate,
28 mbedtls::error::{codes, Error as ErrMbed},
29 std::ffi::CString,
30 std::ops::Deref,
31 super::{DcapArtifactIssuer, PckCrl},
32};
33
34use crate::io::{self};
35use crate::tcb_info::{Fmspc, TcbData, TcbLevel};
36use crate::{CpuSvn, Error, Unverified, VerificationType, Verified};
37
38#[derive(Debug, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
42#[serde(rename_all = "kebab-case")]
43pub enum SGXType {
44 Standard,
45 Scalable,
47 ScalableWithIntegrity,
49}
50
51impl Default for SGXType {
52 fn default() -> SGXType {
53 SGXType::Standard
54 }
55}
56
57impl TryFrom<i64> for SGXType {
58 type Error = ();
59
60 fn try_from(v: i64) -> Result<Self, ()> {
61 match v {
62 0 => Ok(SGXType::Standard),
63 1 => Ok(SGXType::Scalable),
64 2 => Ok(SGXType::ScalableWithIntegrity),
65 _ => Err(()),
66 }
67 }
68}
69
70#[derive(Serialize, Deserialize, Debug, Default)]
72struct IntelSgxTcbComponentsV3 {
73 sgxtcbcomp01svn: u8,
74 sgxtcbcomp02svn: u8,
75 sgxtcbcomp03svn: u8,
76 sgxtcbcomp04svn: u8,
77 sgxtcbcomp05svn: u8,
78 sgxtcbcomp06svn: u8,
79 sgxtcbcomp07svn: u8,
80 sgxtcbcomp08svn: u8,
81 sgxtcbcomp09svn: u8,
82 sgxtcbcomp10svn: u8,
83 sgxtcbcomp11svn: u8,
84 sgxtcbcomp12svn: u8,
85 sgxtcbcomp13svn: u8,
86 sgxtcbcomp14svn: u8,
87 sgxtcbcomp15svn: u8,
88 sgxtcbcomp16svn: u8,
89 pcesvn: u16,
90}
91
92#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
95struct IntelSgxTcbComponentV4 {
96 svn: u8,
97 #[serde(default)]
98 category: String,
99 #[serde(default, rename = "type")]
100 comp_type: String,
101}
102
103impl From<u8> for IntelSgxTcbComponentV4 {
104 fn from(svn: u8) -> IntelSgxTcbComponentV4 {
105 IntelSgxTcbComponentV4 {
106 svn,
107 category: String::new(),
108 comp_type: String::new(),
109 }
110 }
111}
112
113#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
114struct IntelSgxTcbComponentsV4 {
115 pub sgxtcbcomponents: [IntelSgxTcbComponentV4; 16],
116 pub pcesvn: u16,
117}
118
119#[derive(Serialize, Deserialize, Debug)]
120#[serde(untagged)]
121enum IntelSgxTcbComponents {
122 V3(IntelSgxTcbComponentsV3),
123 V4(IntelSgxTcbComponentsV4),
124}
125
126#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
127#[serde(from = "IntelSgxTcbComponents")]
128pub struct TcbComponents(IntelSgxTcbComponentsV4);
129
130#[derive(PartialEq, Eq, Debug, Clone, Copy)]
131pub enum TcbComponent {
132 EarlyMicrocodeUpdate,
133 LateMicrocodeUpdate,
134}
135
136impl TryFrom<&str> for TcbComponent {
137 type Error = ();
138
139 fn try_from(s: &str) -> Result<Self, Self::Error> {
140 if s == "Early Microcode Update" {
141 Ok(TcbComponent::EarlyMicrocodeUpdate)
142 } else if s == "SGX Late Microcode Update" {
143 Ok(TcbComponent::LateMicrocodeUpdate)
144 } else {
145 Err(())
146 }
147 }
148}
149
150impl TcbComponents {
151 pub fn from_raw(raw_cpusvn: [u8; 16], pcesvn: u16) -> Self {
152 TcbComponents(IntelSgxTcbComponentsV4 {
153 sgxtcbcomponents: raw_cpusvn.map(|svn| svn.into()),
154 pcesvn,
155 })
156 }
157
158 fn iter_components<'a>(&'a self) -> impl Iterator<Item = u16> + 'a {
159 self.0
160 .sgxtcbcomponents
161 .iter()
162 .map(|comp| comp.svn as u16)
163 .chain(std::iter::once(self.0.pcesvn))
164 }
165
166 pub fn pce_svn(&self) -> u16 {
167 self.0.pcesvn
168 }
169
170 pub fn cpu_svn(&self) -> CpuSvn {
171 let mut out: CpuSvn = [0u8; 16];
176 for (i, c) in self.0.sgxtcbcomponents.iter().enumerate() {
177 out[i] = c.svn;
178 }
179 out
180 }
181
182 pub fn tcb_component_index(&self, comp: TcbComponent) -> Option<usize> {
184 self.0.sgxtcbcomponents
185 .iter()
186 .position(|c| TcbComponent::try_from(c.comp_type.as_str()) == Ok(comp))
187 }
188}
189
190impl PartialOrd for TcbComponents {
191 fn partial_cmp(&self, other: &TcbComponents) -> Option<Ordering> {
195 let mut prev: Option<Ordering> = None;
196
197 for (a, b) in self.iter_components().zip(other.iter_components()) {
198 match (a.cmp(&b), prev) {
199 (x, None) | (x, Some(Ordering::Equal)) => prev = Some(x),
200 (Ordering::Greater, Some(Ordering::Less)) | (Ordering::Less, Some(Ordering::Greater)) => return None,
201 (Ordering::Equal, Some(Ordering::Less))
202 | (Ordering::Equal, Some(Ordering::Greater))
203 | (Ordering::Less, Some(Ordering::Less))
204 | (Ordering::Greater, Some(Ordering::Greater)) => (),
205 }
206 }
207
208 prev
209 }
210}
211
212impl std::convert::From<IntelSgxTcbComponentsV3> for IntelSgxTcbComponentsV4 {
213 fn from(c: IntelSgxTcbComponentsV3) -> Self {
214 IntelSgxTcbComponentsV4 {
215 sgxtcbcomponents: [
216 c.sgxtcbcomp01svn.into(),
217 c.sgxtcbcomp02svn.into(),
218 c.sgxtcbcomp03svn.into(),
219 c.sgxtcbcomp04svn.into(),
220 c.sgxtcbcomp05svn.into(),
221 c.sgxtcbcomp06svn.into(),
222 c.sgxtcbcomp07svn.into(),
223 c.sgxtcbcomp08svn.into(),
224 c.sgxtcbcomp09svn.into(),
225 c.sgxtcbcomp10svn.into(),
226 c.sgxtcbcomp11svn.into(),
227 c.sgxtcbcomp12svn.into(),
228 c.sgxtcbcomp13svn.into(),
229 c.sgxtcbcomp14svn.into(),
230 c.sgxtcbcomp15svn.into(),
231 c.sgxtcbcomp16svn.into(),
232 ],
233 pcesvn: c.pcesvn,
234 }
235 }
236}
237
238impl std::convert::From<IntelSgxTcbComponents> for TcbComponents {
239 fn from(c: IntelSgxTcbComponents) -> Self {
240 match c {
241 IntelSgxTcbComponents::V3(c) => TcbComponents(c.into()),
242 IntelSgxTcbComponents::V4(c) => TcbComponents(c.into()),
243 }
244 }
245}
246
247impl std::convert::From<IntelSgxTcbComponentsV4> for TcbComponents {
248 fn from(c: IntelSgxTcbComponentsV4) -> Self {
249 TcbComponents(c)
250 }
251}
252
253#[derive(Debug, Clone, PartialEq, Eq)]
254enum PckCertValue {
255 Cert(Vec<u8>),
256 Missing(String),
257}
258
259impl<'de> Deserialize<'de> for PckCertValue {
260 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
261 where
262 D: Deserializer<'de>,
263 {
264 let s = String::deserialize(deserializer)?;
265 let der = percent_decode(s.as_bytes())
266 .decode_utf8()
267 .map_err(|_| Error::InvalidPcks("utf8 decode error".into()))
268 .map(|c| pem::pem_to_der(c.trim(), Some(PEM_CERTIFICATE)));
269
270 if let Ok(Some(der)) = der {
271 Ok(PckCertValue::Cert(der))
272 } else {
273 Ok(PckCertValue::Missing(s.to_string()))
274 }
275 }
276}
277
278impl Serialize for PckCertValue {
279 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
280 where
281 S: Serializer,
282 {
283 match self {
284 PckCertValue::Cert(der) => serializer.serialize_str(&pem::der_to_pem(der, PEM_CERTIFICATE)),
285 PckCertValue::Missing(s) => serializer.serialize_str(s),
286 }
287 }
288}
289
290#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
291pub struct PckCertBodyItem {
292 tcb: TcbComponents,
293 tcbm: String,
294 cert: PckCertValue,
295}
296
297#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
298pub struct PckCerts {
299 pck_data: Vec<PckCertBodyItem>,
300 ca_chain: Vec<String>,
301}
302
303impl PckCerts {
304 pub fn new(pck_data: Vec<PckCertBodyItem>, ca_chain: Vec<String>) -> Self {
305 Self { pck_data, ca_chain }
306 }
307
308 pub fn parse(body: &str, ca_chain: Vec<String>) -> Result<PckCerts, Error> {
309 let data: Vec<PckCertBodyItem> = serde_json::from_str(body)?;
310
311 let pcks = PckCerts {
312 pck_data: data,
313 ca_chain,
314 };
315 Ok(pcks)
316 }
317
318 pub fn filename(qe_id: &[u8]) -> String {
319 format!("{}.certs", base16::encode_lower(qe_id))
320 }
321
322 pub fn store(&self, output_dir: &str, qe_id: &[u8]) -> Result<String, Error> {
323 let filename = PckCerts::filename(qe_id);
324 io::write_to_file(&self, output_dir, &filename)?;
325 Ok(filename)
326 }
327
328 pub fn store_if_not_exist(&self, output_dir: &str, qe_id: &[u8]) -> Result<Option<PathBuf>, Error> {
329 let filename = PckCerts::filename(qe_id);
330 io::write_to_file_if_not_exist(&self, output_dir, &filename)
331 }
332
333 pub fn restore(input_dir: &str, qe_id: &[u8]) -> Result<Self, Error> {
334 let filename = PckCerts::filename(qe_id);
335 let pcks: PckCerts = io::read_from_file(input_dir, &filename)?;
336 Ok(pcks)
337 }
338
339 pub fn fmspc(&self) -> Result<Fmspc, Error> {
340 let pck = self.iter().nth(0).ok_or(Error::NoPckCertData)?;
341 let sgx_extension = SGXPCKCertificateExtension::try_from(pck).map_err(|e| Error::InvalidPckFormat(e))?;
342 Ok(sgx_extension.fmspc)
343 }
344
345 pub fn ca_chain(&self) -> &[String] {
346 &self.ca_chain
347 }
348
349 pub fn iter(&self) -> impl Iterator<Item = &Vec<u8>> {
352 self.pck_data.iter().filter_map(|pck_body_item| {
353 if let PckCertValue::Cert(der) = &pck_body_item.cert {
354 Some(der)
355 } else {
356 None
357 }
358 })
359 }
360
361 pub fn as_pck_certs(&self) -> Vec<PckCert<Unverified>> {
364 self.iter()
365 .map(|pckcert| PckCert::new(pem::der_to_pem(pckcert, PEM_CERTIFICATE), self.ca_chain.clone()))
366 .collect()
367 }
368
369 fn order_pcks<V: VerificationType>(&self, tcb_info: &TcbData<V>) -> Vec<PckCert<Unverified>> {
372 let mut pck_certs = self.as_pck_certs();
373
374 pck_certs.sort_by_cached_key(|cert| cert.find_tcb_level_idx(tcb_info).unwrap_or(usize::max_value()));
378 pck_certs
379 }
380
381 pub fn select_pck<V: VerificationType>(
384 &self,
385 tcb_info: &TcbData<V>,
386 cpusvn: &[u8; 16],
387 pcesvn: u16,
388 pceid: u16,
389 ) -> Result<PckCert<Unverified>, Error> {
390 let pcks = self.order_pcks(&tcb_info);
392
393 let tcb_components = tcb_info.decompose_raw_cpusvn(cpusvn, pcesvn)?;
395 let pck = pcks
396 .iter()
397 .find(|pck| pck.valid_for_tcb(&tcb_components, pceid).is_ok())
398 .ok_or(Error::NoPckForTcbFound)?;
399 Ok(pck.to_owned())
400 }
401
402 #[cfg(feature = "verify")]
403 pub fn issuer(&self) -> Option<DcapArtifactIssuer> {
404 self.iter()
405 .find_map(|pckcert| {
406 let pck = PckCert::new(pem::der_to_pem(pckcert, PEM_CERTIFICATE), self.ca_chain.clone());
407 pck.issuer().ok()
408 })
409 }
410}
411
412#[derive(Clone, Serialize, Debug, PartialEq, Eq)]
413pub struct PckCert<V: VerificationType = Verified> {
414 cert: String,
415 ca_chain: Vec<String>,
416 #[serde(skip)]
417 type_: PhantomData<V>,
418}
419
420impl<'de> Deserialize<'de> for PckCert<Unverified> {
421 fn deserialize<D>(deserializer: D) -> Result<PckCert<Unverified>, D::Error>
422 where
423 D: Deserializer<'de>,
424 {
425 #[derive(Deserialize)]
426 struct Dummy {
427 cert: String,
428 ca_chain: Vec<String>,
429 }
430
431 let Dummy { cert, ca_chain } = Dummy::deserialize(deserializer)?;
432 Ok(PckCert::<Unverified> {
433 cert,
434 ca_chain,
435 type_: PhantomData,
436 })
437 }
438}
439
440impl PckCert<Unverified> {
441 pub fn from_pck_chain(certs: Vec<Cow<'_, str>>) -> Result<PckCert<Unverified>, Error> {
442 if certs.is_empty() {
443 return Err(Error::InvalidPck("Missing CA chain".into()));
444 }
445 if let Some((first, rest)) = certs.split_first() {
446 Ok(PckCert::new(first.to_string(), rest.iter().map(|c| c.to_string()).collect()))
447 } else {
448 Err(Error::InvalidPck("Expected two certificates in CA chain".into()))
449 }
450 }
451
452 pub fn new(cert: String, ca_chain: Vec<String>) -> PckCert<Unverified> {
455 let ca_chain = ca_chain.iter().map(|cert| cert.trim().to_string()).collect();
456 PckCert {
457 cert,
458 ca_chain,
459 type_: PhantomData,
460 }
461 }
462
463 #[cfg(feature = "verify")]
464 pub fn verify<B: Deref<Target = [u8]>>(self, trusted_root_certs: &[B], pckcrl: Option<&str>) -> Result<PckCert, Error> {
465 let mut crl = if let Some(pckcrl) = pckcrl {
466 let pckcrl = PckCrl::new(pckcrl.to_string(), self.ca_chain.clone())?;
467 let pckcrl = pckcrl.verify(trusted_root_certs)?;
468 Some(pckcrl.as_mbedtls_crl()?)
469 } else {
470 None
471 };
472
473 let pck = CString::new(self.cert.as_bytes()).map_err(|_| Error::InvalidPck("Conversion into CString failed".into()))?;
474 let pck = Certificate::from_pem(pck.as_bytes_with_nul())
475 .map_err(|_| Error::InvalidPck("Cannot decode PCKCert as pem".into()))?;
476
477 let (mut chain, root) = crate::create_cert_chain(&self.ca_chain)?;
478 chain.insert(0, pck);
479 let trust_ca: MbedtlsList<Certificate> = chain.into_iter().collect();
480 let root_list = std::iter::once(root).collect();
481 let mut err = String::default();
482 Certificate::verify(&trust_ca, &root_list, crl.as_mut(), Some(&mut err))
483 .map_err(|_| Error::InvalidPck(format!("Failed to verify PckCert: {}", err)))?;
484
485 crate::check_root_ca(trusted_root_certs, &root_list)?;
486
487 Ok(PckCert {
488 cert: self.cert,
489 ca_chain: self.ca_chain,
490 type_: PhantomData,
491 })
492 }
493
494 #[cfg(feature = "verify")]
495 pub fn issuer(&self) -> Result<DcapArtifactIssuer, Error> {
496 let pck = CString::new(self.cert.as_bytes()).map_err(|e| Error::InvalidPck(e.to_string()))?;
497 let pck = Certificate::from_pem(pck.as_bytes_with_nul()).map_err(|e| Error::InvalidPck(e.to_string()))?;
498 let issuer = pck.issuer().map_err(|e| Error::InvalidPck(e.to_string()))?;
499
500 DcapArtifactIssuer::try_from(issuer.as_str())
501 }
502
503 pub fn read_from_file(input_dir: &str, filename: &str) -> Result<Self, Error> {
504 io::read_from_file(input_dir, filename)
505 }
506}
507
508impl PckCert<Verified> {
509 pub fn find_tcb_state<V: VerificationType>(&self, tcb_data: &TcbData<V>) -> Option<TcbLevel> {
512 let idx = self.find_tcb_level_idx(tcb_data)?;
513 Some(tcb_data.tcb_levels()[idx].clone())
514 }
515
516 #[cfg(feature = "verify")]
517 pub fn pck(&self) -> Result<MbedtlsBox<Certificate>, ErrMbed> {
518 let cert = CString::new(self.cert.as_bytes()).map_err(|_| ErrMbed::HighLevel(codes::X509InvalidFormat))?;
519 Certificate::from_pem(cert.as_bytes_with_nul()).map_err(|_| ErrMbed::HighLevel(codes::X509InvalidFormat))
520 }
521
522 #[cfg(feature = "verify")]
523 pub fn public_key(&self) -> Result<EcPoint, ErrMbed> {
524 let cert = self.pck()?;
525 let pk = cert.public_key();
526 pk.ec_public()
527 }
528
529 pub fn ppid(&self) -> Result<Vec<u8>, ASN1Error> {
530 let extension = self.sgx_extension()?;
531 Ok(extension.ppid)
532 }
533
534 pub fn fmspc(&self) -> Result<Fmspc, ASN1Error> {
535 let extension = self.sgx_extension()?;
536 Ok(extension.fmspc)
537 }
538}
539
540impl<V: VerificationType> PckCert<V> {
541 pub fn ca_chain(&self) -> &[String] {
543 return &self.ca_chain;
544 }
545
546 pub fn pck_pem<'a>(&'a self) -> &'a String {
547 &self.cert
548 }
549
550 pub fn write_to_file(&self, output_dir: &str, filename: &str) -> Result<(), Error> {
551 Ok(io::write_to_file(&self, output_dir, &filename)?)
552 }
553
554 pub fn sgx_extension(&self) -> Result<SGXPCKCertificateExtension, ASN1Error> {
555 let der = &pem::pem_to_der(&self.cert, Some(PEM_CERTIFICATE)).ok_or(ASN1Error::new(ASN1ErrorKind::Invalid))?;
556 let cert = GenericCertificate::from_ber(&der)?;
557 let extension = cert
558 .tbscert
559 .get_extension(&SGX_EXTENSION)
560 .ok_or(ASN1Error::new(ASN1ErrorKind::Eof))?;
561 SGXPCKCertificateExtension::parse_extension(&extension.value)
562 }
563
564 pub fn platform_tcb(&self) -> Result<PlatformTCB, ASN1Error> {
565 let extension = self.sgx_extension()?;
566 Ok(extension.tcb)
567 }
568
569 fn as_pck_cert_body_item(&self) -> Result<PckCertBodyItem, ASN1Error> {
570 let ext = self.sgx_extension()?;
571 let cpusvn = ext.tcb.cpusvn;
572 let pce_svn = ext.tcb.tcb_components.0.pcesvn;
573 let mut tcbm = Vec::from(cpusvn);
574 tcbm.extend_from_slice(&pce_svn.to_le_bytes());
575 let cert = pem::pem_to_der(&self.cert, Some(PEM_CERTIFICATE)).ok_or(ASN1Error::new(ASN1ErrorKind::Invalid))?;
576 Ok(PckCertBodyItem {
577 tcb: ext.tcb.tcb_components,
578 tcbm: base16::encode_upper(&tcbm),
579 cert: PckCertValue::Cert(cert),
580 })
581 }
582
583 pub fn sgx_type(&self) -> Result<SGXType, ASN1Error> {
584 let extension = self.sgx_extension()?;
585 Ok(extension.sgx_type)
586 }
587
588 fn find_tcb_level_idx<V2: VerificationType>(&self, tcb_info: &TcbData<V2>) -> Option<usize> {
590 let pck_tcb_level = self.platform_tcb().ok()?;
599 tcb_info
600 .tcb_levels()
601 .iter()
602 .position(|tcb| *tcb.components() <= pck_tcb_level.tcb_components)
603 }
604
605 fn valid_for_tcb(&self, comps: &TcbComponents, pceid: u16) -> Result<(), Error> {
606 let sgx_extension = self
607 .sgx_extension()
608 .map_err(|_| Error::InvalidPck("Failed to parse SGX extension".into()))?;
609 let tcb = sgx_extension.tcb;
610 if sgx_extension.pceid == pceid && tcb.tcb_components <= *comps {
611 Ok(())
612 } else {
613 Err(Error::InvalidPck("PckCert isn't valid for provided TCB".into()))
614 }
615 }
616}
617
618#[derive(Default, Debug)]
619pub struct PlatformTCB {
620 pub tcb_components: TcbComponents,
621 pub cpusvn: CpuSvn,
622}
623
624fn decode_tcb_sequence<'a, 'b>(reader: &mut BERReaderSeq<'a, 'b>) -> ASN1Result<PlatformTCB> {
625 let mut platform_tcb = PlatformTCB::default();
626 for i in 1..=18 {
627 platform_tcb = reader.next().read_sequence(|reader| {
628 let oid = reader.next().read_oid()?;
629 if let Some((last, rest)) = oid.components().split_last() {
630 if rest != oid::SGX_EXTENSION_TCB.components().as_slice() || i != *last {
631 return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
632 }
633 match last {
634 i @ 1..=16 => {
635 platform_tcb.tcb_components.0.sgxtcbcomponents[(i - 1) as usize].svn = reader.next().read_u8()?
636 }
637 17 => platform_tcb.tcb_components.0.pcesvn = reader.next().read_u16()?,
638 18 => {
639 platform_tcb.cpusvn = reader
640 .next()
641 .read_bytes()?
642 .as_slice()
643 .try_into()
644 .map_err(|_| ASN1Error::new(ASN1ErrorKind::Invalid))?
645 }
646 _ => return Err(ASN1Error::new(ASN1ErrorKind::Invalid)),
647 }
648 Ok(platform_tcb)
649 } else {
650 return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
651 }
652 })?;
653 }
654 Ok(platform_tcb)
655}
656
657fn decode_ber_sgx_type(reader: BERReader) -> ASN1Result<SGXType> {
658 reader
659 .read_enum()?
660 .try_into()
661 .map_err(|_| ASN1Error::new(ASN1ErrorKind::Invalid))
662}
663
664#[derive(Default, Debug)]
665pub struct SGXPlatformConfiguration {
666 pub dynamic: bool,
667 pub cached_keys: bool,
668 pub smt_enabled: bool,
669}
670
671fn read_tagged<'a, 'b, F, T>(reader: BERReader<'a, 'b>, oid: &ObjectIdentifier, callback: F) -> ASN1Result<T>
672where
673 F: for<'c> FnOnce(BERReader<'a, 'c>) -> ASN1Result<T>,
674{
675 reader.read_sequence(|reader| {
676 if reader.next().read_oid()? != *oid {
677 return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
678 }
679 callback(reader.next())
680 })
681}
682
683impl BERDecodable for SGXPlatformConfiguration {
684 fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
685 reader.read_sequence(|reader| {
686 let dynamic = read_tagged(reader.next(), &*oid::SGX_EXTENSION_CONF_DYNAMIC_PLATFORM, |r| r.read_bool())?;
687 let cached_keys = read_tagged(reader.next(), &*oid::SGX_EXTENSION_CONF_CACHED_KEYS, |r| r.read_bool())?;
688 let smt_enabled = read_tagged(reader.next(), &*oid::SGX_EXTENSION_CONF_SMT_ENABLED, |r| r.read_bool())?;
689
690 Ok(SGXPlatformConfiguration {
691 dynamic,
692 cached_keys,
693 smt_enabled,
694 })
695 })
696 }
697}
698
699#[derive(Debug)]
700pub struct SGXPCKCertificateExtension {
701 pub ppid: Vec<u8>,
702 pub tcb: PlatformTCB,
703 pub pceid: u16,
704 pub fmspc: Fmspc,
705 pub sgx_type: SGXType,
706 pub platform_instance_id: Option<Vec<u8>>,
707 pub configuration: Option<SGXPlatformConfiguration>,
708}
709
710impl SGXPCKCertificateExtension {
711 pub fn parse_extension(extension: &[u8]) -> ASN1Result<Self> {
714 yasna::parse_der(extension, |reader| {
715 reader.read_sequence(|reader| {
716 struct SGXPCKCertificateExtensionReader<'r, 'a, 'c> {
717 reader: &'r mut yasna::BERReaderSeq<'a, 'c>,
718 current: u64,
719 }
720
721 impl<'r, 'a, 'c> SGXPCKCertificateExtensionReader<'r, 'a, 'c> {
722 fn next<F, R>(&mut self, with_next: F) -> ASN1Result<R>
723 where
724 F: FnOnce(yasna::BERReader) -> ASN1Result<R>,
725 {
726 let current = &mut self.current;
727 self.reader.next().read_sequence(|reader| {
728 if let Some((last, comp)) = reader.next().read_oid()?.components().split_last() {
729 if *comp == *oid::SGX_EXTENSION.components().as_slice() && *current == *last {
730 *current += 1;
731 return with_next(reader.next());
732 }
733 }
734 return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
735 })
736 }
737 }
738
739 let mut reader = SGXPCKCertificateExtensionReader { reader, current: 1 };
740
741 let ppid = reader.next(|reader| reader.read_bytes())?;
742 let tcb = reader.next(|reader| reader.read_sequence(|reader| decode_tcb_sequence(reader)))?;
743 let pceid = reader.next(|reader| reader.read_bytes())?;
744 let fmspc = reader.next(|reader| reader.read_bytes())?;
745 let sgx_type = reader.next(|reader| decode_ber_sgx_type(reader))?;
746
747 let mut platform_instance_id = None;
748 let mut configuration = None;
749 if sgx_type == SGXType::Scalable || sgx_type == SGXType::ScalableWithIntegrity {
750 platform_instance_id = Some(reader.next(|reader| reader.read_bytes())?);
751 configuration = Some(reader.next(|reader| SGXPlatformConfiguration::decode_ber(reader))?);
752 }
753
754 let fmspc = Fmspc::try_from(&fmspc).map_err(|_| ASN1Error::new(ASN1ErrorKind::Invalid))?;
755 if ppid.len() != 16 || pceid.len() != 2 || platform_instance_id.as_ref().map_or(false, |id| id.len() != 16) {
756 return Err(ASN1Error::new(ASN1ErrorKind::Invalid));
757 }
758
759 let extension = SGXPCKCertificateExtension {
760 ppid,
761 tcb,
762 pceid: u16::from_be_bytes(pceid.as_slice().try_into().expect("validated len = 2")),
763 fmspc,
764 sgx_type,
765 configuration,
766 platform_instance_id,
767 };
768
769 Ok(extension)
770 })
771 })
772 }
773}
774
775impl TryFrom<&str> for SGXPCKCertificateExtension {
776 type Error = ASN1Error;
777
778 fn try_from(cert: &str) -> Result<Self, ASN1Error> {
779 let cert = &pem::pem_to_der(cert, Some(PEM_CERTIFICATE)).ok_or(ASN1Error::new(ASN1ErrorKind::Invalid))?;
780 SGXPCKCertificateExtension::try_from(cert)
781 }
782}
783
784impl TryFrom<&Vec<u8>> for SGXPCKCertificateExtension {
785 type Error = ASN1Error;
786
787 fn try_from(cert: &Vec<u8>) -> Result<Self, ASN1Error> {
788 let cert = GenericCertificate::from_ber(&cert)?;
789 let extension = cert
790 .tbscert
791 .get_extension(&SGX_EXTENSION)
792 .ok_or(ASN1Error::new(ASN1ErrorKind::Eof))?;
793 SGXPCKCertificateExtension::parse_extension(&extension.value)
794 }
795}
796
797impl<V> TryFrom<PckCert<V>> for PckCerts
798where
799 V: VerificationType,
800{
801 type Error = ASN1Error;
802
803 fn try_from(pck: PckCert<V>) -> Result<PckCerts, ASN1Error> {
804 let cert_body_item = pck.as_pck_cert_body_item()?;
805
806 Ok(PckCerts {
807 pck_data: vec![cert_body_item],
808 ca_chain: pck.ca_chain,
809 })
810 }
811}
812
813impl<V> TryFrom<Vec<PckCert<V>>> for PckCerts
816where
817 V: VerificationType,
818{
819 type Error = ASN1Error;
820
821 fn try_from(mut pcks: Vec<PckCert<V>>) -> Result<PckCerts, ASN1Error> {
822 let pck_data = pcks.iter().map(|pck| pck.as_pck_cert_body_item()).collect::<Result<Vec<_>, ASN1Error>>()?;
823 let ca_chain = match pcks.first_mut() {
826 Some(first) => mem::take(&mut first.ca_chain),
827 None => return Err(ASN1Error::new(ASN1ErrorKind::Eof)),
828 };
829 Ok(PckCerts { pck_data, ca_chain })
830 }
831}
832
833#[cfg(test)]
834mod tests {
835 use dcap_ql::quote::{Qe3CertDataPckCertChain, Quote, Quote3SignatureEcdsaP256};
836 use hex::FromHex;
837 use pkix::derives::ObjectIdentifier;
838 use sgx_pkix::oid::{SGX_EXTENSION_PPID, SGX_EXTENSION_TCB, SGX_EXTENSION_TCB_COMP01_SVN};
839 use yasna;
840
841 use super::*;
842 #[cfg(not(target_env = "sgx"))]
843 use crate::{get_cert_subject, get_cert_subject_from_der};
844
845 fn decode_tcb_item<'a, 'b>(reader: &mut BERReaderSeq<'a, 'b>) -> ASN1Result<(ObjectIdentifier, u8)> {
846 let oid = reader.next().read_oid()?;
847 let value = reader.next().read_u8()?;
848 Ok((oid, value))
849 }
850
851 #[test]
852 fn sgx_extension_oid() {
853 let oid_enc = vec![0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x01];
854
855 let oid = yasna::parse_der(&oid_enc, |reader| {
856 let oid = reader.read_oid()?;
857 Ok(oid)
858 })
859 .unwrap();
860 assert_eq!(oid, *SGX_EXTENSION_PPID);
861 }
862
863 #[test]
864 fn sgx_extension_ppid() {
865 let ppid_enc = vec![
866 0x04, 0x10, 0x88, 0x58, 0x9d, 0xd5, 0x8b, 0xd4, 0xe8, 0x0c, 0x2b, 0x12, 0x49, 0x86, 0x22, 0xa3, 0x48, 0x77,
867 ];
868
869 let ppid = yasna::parse_der(&ppid_enc, |reader| {
870 let ppid = reader.read_bytes()?;
871 Ok(ppid)
872 })
873 .unwrap();
874 assert_eq!(
875 ppid,
876 vec![136, 88, 157, 213, 139, 212, 232, 12, 43, 18, 73, 134, 34, 163, 72, 119]
877 );
878 }
879
880 #[test]
881 fn sgx_extension_ppid_seq() {
882 let ppid_seq = vec![
883 0x30, 0x1e, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x01, 0x04, 0x10, 0x88, 0x58, 0x9d,
884 0xd5, 0x8b, 0xd4, 0xe8, 0x0c, 0x2b, 0x12, 0x49, 0x86, 0x22, 0xa3, 0x48, 0x77,
885 ];
886 let (oid, ppid) = yasna::parse_der(&ppid_seq, |reader| {
887 reader.read_sequence(|reader| {
888 let oid = reader.next().read_oid()?;
889 let ppid = reader.next().read_bytes()?;
890 Ok((oid, ppid))
891 })
892 })
893 .unwrap();
894 assert_eq!(oid, *SGX_EXTENSION_PPID);
895 assert_eq!(
896 ppid,
897 vec![136, 88, 157, 213, 139, 212, 232, 12, 43, 18, 73, 134, 34, 163, 72, 119]
898 );
899 }
900
901 #[test]
902 fn sgx_extension_tcb_comp() {
903 let tcb_comp_seq = vec![
904 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x02, 0x01, 0x0d,
905 ];
906
907 let (oid, tcb_comp) = yasna::parse_der(&tcb_comp_seq, |reader| {
908 reader.read_sequence(|reader| {
909 let oid = reader.next().read_oid()?;
910 let tcb_comp = reader.next().read_u8()?;
911 Ok((oid, tcb_comp))
912 })
913 })
914 .unwrap();
915 assert_eq!(oid, *SGX_EXTENSION_TCB_COMP01_SVN);
916 assert_eq!(tcb_comp, 13);
917 }
918
919 #[test]
920 fn sgx_extension_tcb_comp2() {
921 let tcb_comp_seq = vec![
922 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x02, 0x01, 0x0d,
923 ];
924
925 let (oid, tcb_comp) = yasna::parse_der(&tcb_comp_seq, |reader| reader.read_sequence(decode_tcb_item)).unwrap();
926 assert_eq!(oid, *SGX_EXTENSION_TCB_COMP01_SVN);
927 assert_eq!(tcb_comp, 13);
928 }
929
930 #[test]
931 fn sgx_extension_tcb() {
932 let tcb_enc = vec![
933 0x30, 0x82, 0x01, 0x64, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x30, 0x82, 0x01,
934 0x54, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x02, 0x01, 0x0d,
935 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x02, 0x02, 0x01, 0x0d, 0x30,
936 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x03, 0x02, 0x01, 0x02, 0x30, 0x10,
937 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x04, 0x02, 0x01, 0x04, 0x30, 0x10, 0x06,
938 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x05, 0x02, 0x01, 0x01, 0x30, 0x11, 0x06, 0x0b,
939 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x06, 0x02, 0x02, 0x00, 0x80, 0x30, 0x10, 0x06, 0x0b,
940 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x07, 0x02, 0x01, 0x03, 0x30, 0x10, 0x06, 0x0b, 0x2a,
941 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x08, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86,
942 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x09, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48,
943 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x0a, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86,
944 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x0b, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8,
945 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x0c, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d,
946 0x01, 0x0d, 0x01, 0x02, 0x0d, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01,
947 0x0d, 0x01, 0x02, 0x0e, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d,
948 0x01, 0x02, 0x0f, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01,
949 0x02, 0x10, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02,
950 0x11, 0x02, 0x01, 0x09, 0x30, 0x1f, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x12,
951 0x04, 0x10, 0x0d, 0x0d, 0x02, 0x04, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
952 ];
953
954 let (oid, tcb) = yasna::parse_der(&tcb_enc, |reader| {
955 reader.read_sequence(|reader| {
956 let oid = reader.next().read_oid()?;
957 let tcb = reader.next().read_sequence(decode_tcb_sequence)?;
958 Ok((oid, tcb))
959 })
960 })
961 .unwrap();
962 assert_eq!(oid, *SGX_EXTENSION_TCB);
963 assert_eq!(
964 tcb.tcb_components.0.sgxtcbcomponents.map(|c| c.svn),
965 [13, 13, 2, 4, 1, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
966 );
967 assert_eq!(tcb.cpusvn, [13, 13, 2, 4, 1, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
968 assert_eq!(tcb.tcb_components.0.pcesvn, 9);
969 }
970
971 #[test]
972 fn sgx_extension() {
973 let extension = vec![
974 0x30, 0x82, 0x01, 0xc1, 0x30, 0x1e, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x01, 0x04,
975 0x10, 0xa9, 0xf2, 0x39, 0xa8, 0x05, 0xb7, 0xd9, 0x38, 0xf5, 0xb0, 0xea, 0x87, 0x3b, 0x69, 0xdb, 0xa7, 0x30, 0x82,
976 0x01, 0x64, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x30, 0x82, 0x01, 0x54, 0x30,
977 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x01, 0x02, 0x01, 0x0d, 0x30, 0x10,
978 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x02, 0x02, 0x01, 0x0d, 0x30, 0x10, 0x06,
979 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x03, 0x02, 0x01, 0x02, 0x30, 0x10, 0x06, 0x0b,
980 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x04, 0x02, 0x01, 0x04, 0x30, 0x10, 0x06, 0x0b, 0x2a,
981 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x05, 0x02, 0x01, 0x01, 0x30, 0x11, 0x06, 0x0b, 0x2a, 0x86,
982 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x06, 0x02, 0x02, 0x00, 0x80, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86,
983 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x07, 0x02, 0x01, 0x03, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48,
984 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x08, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86,
985 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x09, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8,
986 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x0a, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d,
987 0x01, 0x0d, 0x01, 0x02, 0x0b, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01,
988 0x0d, 0x01, 0x02, 0x0c, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d,
989 0x01, 0x02, 0x0d, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01,
990 0x02, 0x0e, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02,
991 0x0f, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x10,
992 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x11, 0x02,
993 0x01, 0x09, 0x30, 0x1f, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x02, 0x12, 0x04, 0x10,
994 0x0d, 0x0d, 0x02, 0x04, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x06,
995 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x03, 0x04, 0x02, 0x00, 0x00, 0x30, 0x14, 0x06, 0x0a,
996 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x04, 0x04, 0x06, 0x00, 0x90, 0x6e, 0xa1, 0x00, 0x00, 0x30,
997 0x0f, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x05, 0x0a, 0x01, 0x00,
998 ];
999 let sgx_extension = SGXPCKCertificateExtension::parse_extension(&extension);
1000 assert!(sgx_extension.is_ok());
1001 let sgx_extension = sgx_extension.unwrap();
1002 assert_eq!(
1003 sgx_extension.ppid,
1004 [169, 242, 57, 168, 5, 183, 217, 56, 245, 176, 234, 135, 59, 105, 219, 167]
1005 );
1006 assert_eq!(
1007 sgx_extension.tcb.tcb_components.0.sgxtcbcomponents.map(|c| c.svn),
1008 [13, 13, 2, 4, 1, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1009 );
1010 assert_eq!(sgx_extension.tcb.tcb_components.0.pcesvn, 9);
1011 assert_eq!(sgx_extension.tcb.cpusvn, [13, 13, 2, 4, 1, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1012 assert_eq!(sgx_extension.pceid, 0);
1013 assert_eq!(sgx_extension.fmspc, Fmspc::new([0, 144, 110, 161, 0, 0]));
1014 assert_eq!(sgx_extension.sgx_type, SGXType::Standard);
1015 assert!(sgx_extension.platform_instance_id.is_none());
1016 assert!(sgx_extension.configuration.is_none());
1017 }
1018
1019 #[test]
1020 fn sgx_extension_platform_cert() {
1021 let extension = Vec::<u8>::from_hex(
1022 "30820226301e060a2a864886f84d010d010104103f545fc38af1107f31ed41547783bcd730820163060a2a864886f84d010d0102\
1023 308201533010060b2a864886f84d010d0102010201033010060b2a864886f84d010d0102020201033010060b2a864886f84d010d\
1024 0102030201003010060b2a864886f84d010d0102040201003010060b2a864886f84d010d0102050201003010060b2a864886f84d\
1025 010d0102060201003010060b2a864886f84d010d0102070201003010060b2a864886f84d010d0102080201003010060b2a864886\
1026 f84d010d0102090201003010060b2a864886f84d010d01020a0201003010060b2a864886f84d010d01020b0201003010060b2a86\
1027 4886f84d010d01020c0201003010060b2a864886f84d010d01020d0201003010060b2a864886f84d010d01020e0201003010060b\
1028 2a864886f84d010d01020f0201003010060b2a864886f84d010d0102100201003010060b2a864886f84d010d01021102010a301f\
1029 060b2a864886f84d010d0102120410030300000000000000000000000000003010060a2a864886f84d010d010304020000301406\
1030 0a2a864886f84d010d0104040610606a000000300f060a2a864886f84d010d01050a0101301e060a2a864886f84d010d01060410\
1031 5e5a84633cb1ddad3d79b9bea40300923044060a2a864886f84d010d010730363010060b2a864886f84d010d0107010101ff3010\
1032 060b2a864886f84d010d0107020101ff3010060b2a864886f84d010d0107030101ff",
1033 )
1034 .unwrap();
1035 let sgx_extension = SGXPCKCertificateExtension::parse_extension(&extension);
1036 assert!(sgx_extension.is_ok());
1037 let sgx_extension = sgx_extension.unwrap();
1038 assert_eq!(
1039 sgx_extension.ppid,
1040 [0x3F, 0x54, 0x5F, 0xC3, 0x8A, 0xF1, 0x10, 0x7F, 0x31, 0xED, 0x41, 0x54, 0x77, 0x83, 0xBC, 0xD7]
1041 );
1042 assert_eq!(
1043 sgx_extension.tcb.tcb_components.0.sgxtcbcomponents.map(|c| c.svn),
1044 [3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1045 );
1046 assert_eq!(sgx_extension.tcb.tcb_components.0.pcesvn, 10);
1047 assert_eq!(sgx_extension.tcb.cpusvn, [3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1048 assert_eq!(sgx_extension.pceid, 0);
1049 assert_eq!(sgx_extension.fmspc, Fmspc::new([16, 96, 106, 0, 0, 0]));
1050 assert_eq!(sgx_extension.sgx_type, SGXType::Scalable);
1051 assert_eq!(
1052 sgx_extension.platform_instance_id.unwrap(),
1053 [0x5E, 0x5A, 0x84, 0x63, 0x3C, 0xB1, 0xDD, 0xAD, 0x3D, 0x79, 0xB9, 0xBE, 0xA4, 0x03, 0x00, 0x92]
1054 );
1055 let configuration = sgx_extension.configuration.unwrap();
1056 assert!(configuration.dynamic);
1057 assert!(configuration.cached_keys);
1058 assert!(configuration.smt_enabled);
1059 }
1060
1061 #[test]
1062 #[cfg(not(target_env = "sgx"))]
1063 fn read_pckcrt() {
1064 let pck = PckCert::read_from_file(
1065 "./tests/data/",
1066 "5d39f104e642e51c91507932..71b719-0f0f0205ff8007000000000000000000-0900-0000.pckcert",
1067 )
1068 .expect("validated");
1069
1070 assert_eq!(get_cert_subject(&pck.ca_chain.last().unwrap()), "Intel SGX Root CA");
1071 assert_eq!(get_cert_subject(&pck.cert), "Intel SGX PCK Certificate");
1072 #[cfg(feature = "verify")]
1073 {
1074 let root_ca = include_bytes!("../tests/data/root_SGX_CA_der.cert");
1075 let root_cas = [&root_ca[..]];
1076 let platform_crl = reqwest::blocking::get("https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform&encoding=pem")
1077 .unwrap()
1078 .text()
1079 .unwrap();
1080 match pck.clone().verify(&root_cas, Some(&platform_crl)) {
1081 Err(Error::InvalidCrl(ErrMbed::HighLevel(codes::EcpVerifyFailed))) => (),
1082 e => panic!("Unexpected error: {:?}", e),
1083 }
1084 let processor_crl = reqwest::blocking::get("https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=processor&encoding=pem")
1085 .unwrap()
1086 .text()
1087 .unwrap();
1088 let pck = pck.verify(&root_cas, Some(&processor_crl)).unwrap();
1089
1090 let sgx_extension = pck.sgx_extension().expect("validated");
1091 assert_eq!(
1092 sgx_extension.ppid,
1093 [138, 37, 248, 76, 1, 238, 38, 35, 157, 25, 11, 226, 233, 16, 18, 144]
1094 );
1095 assert_eq!(
1096 sgx_extension.tcb.tcb_components.0.sgxtcbcomponents.map(|c| c.svn),
1097 [13, 13, 2, 4, 1, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1098 );
1099 assert_eq!(sgx_extension.tcb.tcb_components.0.pcesvn, 9);
1100 assert_eq!(sgx_extension.tcb.cpusvn, [13, 13, 2, 4, 1, 128, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1101 assert_eq!(sgx_extension.pceid, 0);
1102 assert_eq!(sgx_extension.fmspc, Fmspc::new([0, 144, 110, 161, 0, 0]));
1103 }
1104 }
1105
1106 #[test]
1107 fn pckcrt_from_quote() {
1108 let quote = include_bytes!("../tests/data/quote.bin");
1109 let quote = Quote::parse(Cow::from("e[..])).unwrap();
1110 let sig = quote.signature::<Quote3SignatureEcdsaP256>().unwrap();
1111 let pck_chain: Qe3CertDataPckCertChain = sig.certification_data().unwrap();
1112 let pck = PckCert::from_pck_chain(pck_chain.certs.into()).unwrap();
1113 let sgx_extension = pck.sgx_extension().unwrap();
1114 assert_eq!(sgx_extension.fmspc, Fmspc::new([0, 144, 110, 161, 0, 0]));
1115 }
1116
1117 #[test]
1118 #[cfg(not(target_env = "sgx"))]
1119 fn read_pckcrts() {
1120 let pcks = PckCerts::restore(
1121 "./tests/data/",
1122 &base16::decode("16a5b41ebb076d263a1e39e64e7175e7".as_bytes()).unwrap(),
1123 )
1124 .expect("validated");
1125 assert_eq!(pcks.iter().count(), 12);
1126 for cert in pcks.iter() {
1127 SGXPCKCertificateExtension::try_from(cert).expect("validated");
1128 assert_eq!(get_cert_subject_from_der(&cert), "Intel SGX PCK Certificate");
1129 }
1130 assert_eq!(get_cert_subject(&pcks.ca_chain.last().unwrap()), "Intel SGX Root CA");
1131
1132 let cert = pcks.iter().next().expect("validated");
1133 let sgx_extension = SGXPCKCertificateExtension::try_from(cert).expect("validated");
1134 assert_eq!(
1135 sgx_extension.ppid,
1136 [138, 37, 248, 76, 1, 238, 38, 35, 157, 25, 11, 226, 233, 16, 18, 144]
1137 );
1138 assert_eq!(
1139 sgx_extension.tcb.tcb_components.0.sgxtcbcomponents.map(|c| c.svn),
1140 [14, 14, 2, 4, 1, 128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1141 );
1142 assert_eq!(sgx_extension.tcb.tcb_components.0.pcesvn, 10);
1143 assert_eq!(sgx_extension.tcb.cpusvn, [14, 14, 2, 4, 1, 128, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1144 assert_eq!(sgx_extension.pceid, 0);
1145 assert_eq!(sgx_extension.fmspc, Fmspc::new([0, 144, 110, 161, 0, 0]));
1146 }
1147
1148 #[test]
1149 #[cfg(not(target_env = "sgx"))]
1150 fn read_pckcrts_with_missing_certs() {
1151 let pcks = PckCerts::restore(
1152 "./tests/data/",
1153 &base16::decode("00000000000000000000000000000000".as_bytes()).unwrap(),
1154 )
1155 .expect("validated");
1156 let cert = pem::pem_to_der(
1157 &concat!(
1158 "-----BEGIN CERTIFICATE-----\n",
1159 "MIIE8jCCBJmgAwIBAgIVAIK77m63vG5A1vcRhx5fHPY75FnQMAoGCCqGSM49BAMC\n",
1160 "MHAxIjAgBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoM\n",
1161 "EUludGVsIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UE\n",
1162 "CAwCQ0ExCzAJBgNVBAYTAlVTMB4XDTIyMTIxNjEwMTk0OVoXDTI5MTIxNjEwMTk0\n",
1163 "OVowcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBDSyBDZXJ0aWZpY2F0ZTEaMBgGA1UE\n",
1164 "CgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRhIENsYXJhMQswCQYD\n",
1165 "VQQIDAJDQTELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATq\n",
1166 "R+sFzV6WAsyc8Ka4rul7Hz7l16ToABtGYRzZd5h22Y1eljsI0Vt6GnITfHuiXyS6\n",
1167 "HXsyRZqE4u8nRRTsFKU3o4IDDjCCAwowHwYDVR0jBBgwFoAUlW9dzb0b4elAScnU\n",
1168 "9DPOAVcL3lQwawYDVR0fBGQwYjBgoF6gXIZaaHR0cHM6Ly9hcGkudHJ1c3RlZHNl\n",
1169 "cnZpY2VzLmludGVsLmNvbS9zZ3gvY2VydGlmaWNhdGlvbi92My9wY2tjcmw/Y2E9\n",
1170 "cGxhdGZvcm0mZW5jb2Rpbmc9ZGVyMB0GA1UdDgQWBBR20OYrtxnHDel8lcKFwmhx\n",
1171 "/UEckzAOBgNVHQ8BAf8EBAMCBsAwDAYDVR0TAQH/BAIwADCCAjsGCSqGSIb4TQEN\n",
1172 "AQSCAiwwggIoMB4GCiqGSIb4TQENAQEEEPBi9+kxf7O+L8OZgujiZOswggFlBgoq\n",
1173 "hkiG+E0BDQECMIIBVTAQBgsqhkiG+E0BDQECAQIBBDAQBgsqhkiG+E0BDQECAgIB\n",
1174 "BDAQBgsqhkiG+E0BDQECAwIBAzAQBgsqhkiG+E0BDQECBAIBAzARBgsqhkiG+E0B\n",
1175 "DQECBQICAP8wEQYLKoZIhvhNAQ0BAgYCAgD/MBAGCyqGSIb4TQENAQIHAgEAMBAG\n",
1176 "CyqGSIb4TQENAQIIAgEAMBAGCyqGSIb4TQENAQIJAgEAMBAGCyqGSIb4TQENAQIK\n",
1177 "AgEAMBAGCyqGSIb4TQENAQILAgEAMBAGCyqGSIb4TQENAQIMAgEAMBAGCyqGSIb4\n",
1178 "TQENAQINAgEAMBAGCyqGSIb4TQENAQIOAgEAMBAGCyqGSIb4TQENAQIPAgEAMBAG\n",
1179 "CyqGSIb4TQENAQIQAgEAMBAGCyqGSIb4TQENAQIRAgELMB8GCyqGSIb4TQENAQIS\n",
1180 "BBAEBAMD//8AAAAAAAAAAAAAMBAGCiqGSIb4TQENAQMEAgAAMBQGCiqGSIb4TQEN\n",
1181 "AQQEBgBgagAAADAPBgoqhkiG+E0BDQEFCgEBMB4GCiqGSIb4TQENAQYEEIEDHYFl\n",
1182 "SvQX3oyiTA8B0/MwRAYKKoZIhvhNAQ0BBzA2MBAGCyqGSIb4TQENAQcBAQH/MBAG\n",
1183 "CyqGSIb4TQENAQcCAQH/MBAGCyqGSIb4TQENAQcDAQH/MAoGCCqGSM49BAMCA0cA\n",
1184 "MEQCIA6R9ZOhoLbanU/mPY1hKn3Mk4Wxo0GXb7sEtLzNYWSMAiBnbSyR4iL3qEQt\n",
1185 "GkDTeneBR0bJi4lCLTwIwxg6tuWjdQ==\n",
1186 "-----END CERTIFICATE-----\n"
1187 ),
1188 Some(PEM_CERTIFICATE),
1189 )
1190 .unwrap();
1191 assert_eq!(pcks.pck_data.len(), 5);
1192 assert_eq!(pcks.pck_data[0].cert, PckCertValue::Missing(String::from("Not available")));
1193 assert_eq!(pcks.pck_data[1].cert, PckCertValue::Missing(String::from("Not available")));
1194 assert_eq!(pcks.pck_data[2].cert, PckCertValue::Cert(cert));
1195 assert_eq!(pcks.iter().count(), 3);
1196 }
1197
1198 #[test]
1199 fn pck_cert_value() {
1200 let originals = vec![
1201 PckCertValue::Missing(String::from("Not available")),
1202 PckCertValue::Missing(String::from("bla")),
1203 PckCertValue::Cert(vec![0, 0, 0, 0, 0, 0, 0, 0]),
1204 ];
1205
1206 for original in originals {
1207 let ser = serde_json::to_string(&original).unwrap();
1208 let deser = serde_json::from_str(&ser).unwrap();
1209 assert_eq!(original, deser);
1210 }
1211 }
1212
1213 #[test]
1214 #[cfg(not(target_env = "sgx"))]
1215 fn pckcrts_conversion() {
1216 let pcks = PckCerts::restore(
1217 "./tests/data/",
1218 &base16::decode("16a5b41ebb076d263a1e39e64e7175e7".as_bytes()).unwrap(),
1219 )
1220 .unwrap();
1221
1222 for i in 0..pcks.pck_data.len() {
1223 let pck: PckCert<Unverified> = pcks.as_pck_certs()[i].clone();
1224 let cert = pem::pem_to_der(&pck.cert, Some(PEM_CERTIFICATE)).unwrap();
1225 assert_eq!(pcks.pck_data[i].cert, PckCertValue::Cert(cert));
1226 assert_eq!(pcks.ca_chain.iter().map(|c| c.trim()).collect::<Vec<&str>>(), pck.ca_chain);
1227
1228 let pck: PckCerts = pck.try_into().unwrap();
1229 assert_eq!(
1230 pcks.pck_data[i].tcb.0.sgxtcbcomponents,
1231 pck.pck_data[0].tcb.0.sgxtcbcomponents
1232 );
1233 assert_eq!(pcks.pck_data[i].tcb.0.pcesvn, pck.pck_data[0].tcb.0.pcesvn);
1234 assert_eq!(pcks.pck_data[i].tcbm, pck.pck_data[0].tcbm);
1235 assert_eq!(pcks.pck_data[i].cert, pck.pck_data[0].cert);
1236 }
1237 }
1238
1239 #[test]
1240 fn tcb_level_partial_cmp() {
1241 let base_tcb = [10, 20, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1242 let base = TcbComponents::from_raw(base_tcb, 40);
1243 let base = &base;
1244 let mut other = base.clone();
1245 assert_eq!(base.partial_cmp(&other), Some(Ordering::Equal));
1246
1247 other = base.clone();
1248 other.0.sgxtcbcomponents = [10, 20, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map(|c| c.into());
1249 assert_eq!(base.partial_cmp(&other), Some(Ordering::Less));
1250
1251 other = base.clone();
1252 other.0.sgxtcbcomponents = [20, 20, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map(|c| c.into());
1253 assert_eq!(base.partial_cmp(&other), Some(Ordering::Less));
1254
1255 other = base.clone();
1256 other.0.sgxtcbcomponents = [0, 20, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map(|c| c.into());
1257 assert_eq!(base.partial_cmp(&other), Some(Ordering::Greater));
1258
1259 other = base.clone();
1260 other.0.sgxtcbcomponents = [10, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map(|c| c.into());
1261 assert_eq!(base.partial_cmp(&other), Some(Ordering::Greater));
1262
1263 other = base.clone();
1264 other.0.sgxtcbcomponents = [0, 20, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].map(|c| c.into());
1265 assert_eq!(base.partial_cmp(&other), None);
1266
1267 other = base.clone();
1268 other.0.pcesvn = 50;
1269 assert_eq!(base.partial_cmp(&other), Some(Ordering::Less));
1270
1271 other = base.clone();
1272 other.0.pcesvn = 30;
1273 assert_eq!(base.partial_cmp(&other), Some(Ordering::Greater));
1274 }
1275
1276 #[test]
1277 fn tcb_components_cpu_svn() {
1278 let raw_cpu_svn = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160];
1279 let comp = TcbComponents::from_raw(raw_cpu_svn, 42);
1280 assert_eq!(comp.cpu_svn(), raw_cpu_svn);
1281 }
1282
1283 #[test]
1284 #[cfg(feature = "verify")]
1285 fn pck_for_tcb() {
1286 let root_ca = include_bytes!("../tests/data/root_SGX_CA_der.cert");
1287 let root_cas = [&root_ca[..]];
1288 let pck_certs = PckCerts::restore(
1289 "./tests/data/",
1290 &base16::decode("881c3086c0eef78f60f5702a7e379efe".as_bytes()).unwrap())
1291 .unwrap();
1292 let tcb_info = crate::TcbInfo::restore("./tests/data/", &Fmspc::try_from("90806F000000").unwrap(), Some(19))
1293 .unwrap();
1294 let cpusvn = [8, 8, 2, 2, 4, 1, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0];
1297 let pcesvn = 11;
1298 let pceid = 0;
1299
1300 let pck_cert = pck_certs.select_pck(&tcb_info.data().unwrap(), &cpusvn, pcesvn, pceid)
1301 .unwrap()
1302 .verify(&root_cas, None)
1303 .unwrap();
1304 let ext = pck_cert.sgx_extension().unwrap();
1305 assert_eq!(ext.tcb.tcb_components, TcbComponents::from_raw(cpusvn, pcesvn));
1306 assert_eq!(ext.tcb.cpusvn, cpusvn);
1307 assert_eq!(ext.pceid, pceid);
1308 }
1309}