pcs/
pckcrt.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8use 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/// [`SGXType`] is a rust enum representing the IntelĀ® SGX Type.
39///
40/// Ref: <https://api.trustedservices.intel.com/documents/Intel_SGX_PCK_Certificate_CRL_Spec-1.5.pdf>
41#[derive(Debug, Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
42#[serde(rename_all = "kebab-case")]
43pub enum SGXType {
44    Standard,
45    /// Type for machines only provide confidentiality protection for EPC memory, such as Azure DC v3 instance.
46    Scalable,
47    /// Type for machines provide integrity and confidentiality protection for EPC memory, such as our FX2200 series 3 instance.
48    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/// TCB component as specified in the Intel PCKCrt API v3 and v4
71#[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/// TCB component as specified in TcbInfo (version 3) of the PCS version 4 API
93/// https://api.trustedservices.intel.com/documents/PCS_V3-V4_migration_guide.pdf
94#[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        // NOTE: to support older stable compilers (pre 1.77) we are avoiding
172        // the obvious implementation:
173        //
174        // self.0.sgxtcbcomponents.each_ref().map(|c| c.svn)
175        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    /// Returns the index of the TCB component
183    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    /// Compare all 17 components. If all are equal, order as equal. If some
192    /// are less and others are greater, ordering is not defined. If some are
193    /// less, order as less. If some are greater, order as greater.
194    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    /// Returns an iterator over the pck certificates (in der format) in this structure.
350    /// WARNING: Missing, or malformed certificates are hidden from the iterator
351    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    /// Returns a `Vec` of `PckCert` in this structure.
362    /// WARNING: Missing, or malformed certificates are hidden from the iterator
363    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    /// Order all PCKs according to the tcb info
370    /// TCB Info is carefully ordered by Intel
371    fn order_pcks<V: VerificationType>(&self, tcb_info: &TcbData<V>) -> Vec<PckCert<Unverified>> {
372        let mut pck_certs = self.as_pck_certs();
373
374        // Sort PCK certs by applicable TCB level. If two certs are in the same TCB
375        // level, maintain existing ordering (stable sort). PCK certs without a TCB
376        // level are sorted last.
377        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    /// Given the cpusvn, pcesvn and qe_id, searches for the best PCK certificate
382    /// Code re-implements <https://github.com/intel/SGXDataCenterAttestationPrimitives/blob/ab8d31d72f842adb4b8a49eb3639f2e9a789d13b/tools/PCKCertSelection/PCKCertSelectionLib/pck_sorter.cpp#L441>
383    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        // 1. Order PCK certs according to TCB levels
391        let pcks = self.order_pcks(&tcb_info);
392
393        // 2. Find first PCK cert in ordered list that matches current platform
394        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    /// Creates a new PckCert from the PCK certificate and CA chain. The root certificate must be
453    /// the last certificate in the chain
454    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    /// Selects the highest matching TCB level
510    /// see <https://api.portal.trustedservices.intel.com/documentation#pcs-tcb-info-v2>
511    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    /// Returns the the CA chain in the order [leaf .. root]
542    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    /// Find the index of the highest matching TCB level
589    fn find_tcb_level_idx<V2: VerificationType>(&self, tcb_info: &TcbData<V2>) -> Option<usize> {
590        // Go over the sorted collection of TCB Levels retrieved from TCB Info starting from the first item on the list:
591        //   1. Compare all of the SGX TCB Comp SVNs retrieved from the SGX PCK Certificate (from 01 to 16) with the corresponding
592        //      values in the TCB Level. If all SGX TCB Comp SVNs in the certificate are greater or equal to the corresponding values
593        //      in TCB Level, go to 3.b, otherwise move to the next item on TCB Levels list.
594        //   2. Compare PCESVN value retrieved from the SGX PCK certificate with the corresponding value in the TCB Level. If it is
595        //      greater or equal to the value in TCB Level, read status assigned to this TCB level. Otherwise, move to the next item
596        //      on TCB Levels list.
597        // If no TCB level matches your SGX PCK Certificate, your TCB Level is not supported.
598        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    /// Parses an SGX PCK Certificate extension as define in Section 3.5
712    /// <https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/SGX_PCK_Certificate_CRL_Spec-1.4.pdf>
713    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
813/// NOTE: This conversion is only correct if all PCK certs in the vec have the
814/// same CA chain.
815impl<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        // NOTE: assuming that all PCK certs in the vec have the same CA chain,
824        // so we pick the ca_chain from the first one:
825        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(&quote[..])).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        // This TCB matches exactly with the first PCK cert in the list. This PCK cert must be
1295        // selected
1296        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}