@@ -16,7 +16,7 @@ use lru_cache::LruCache;
1616use num_enum:: TryFromPrimitive ;
1717use pcs:: {
1818 CpuSvn , DcapArtifactIssuer , EncPpid , Fmspc , PceId , PceIsvsvn , PckCert , PckCerts , PckCrl , PckID , QeId ,
19- QeIdentitySigned , TcbInfo , RawTcbEvaluationDataNumbers , Unverified ,
19+ QeIdentitySigned , TcbComponent , TcbInfo , RawTcbEvaluationDataNumbers , Unverified ,
2020} ;
2121#[ cfg( feature = "reqwest" ) ]
2222use reqwest:: blocking:: { Client as ReqwestClient , Response as ReqwestResponse } ;
@@ -583,66 +583,65 @@ pub trait ProvisioningClient {
583583 ///
584584 /// Note that PCK certs for some TCB levels may be missing.
585585 fn pckcerts_with_fallback ( & self , pck_id : & PckID ) -> Result < PckCerts , Error > {
586+ let get_and_collect = |collection : & mut BTreeMap < ( [ u8 ; 16 ] , u16 ) , PckCert < Unverified > > , cpu_svn : & [ u8 ; 16 ] , pce_svn : u16 | -> Result < PckCert < Unverified > , Error > {
587+ let pck_cert = self . pckcert (
588+ Some ( & pck_id. enc_ppid ) ,
589+ & pck_id. pce_id ,
590+ cpu_svn,
591+ pce_svn,
592+ Some ( & pck_id. qe_id ) ,
593+ ) ?;
594+
595+ // Getting PCK cert using CPUSVN from PCKID
596+ let ptcb = pck_cert. platform_tcb ( ) ?;
597+ collection. insert ( ( ptcb. cpusvn , ptcb. tcb_components . pce_svn ( ) ) , pck_cert. clone ( ) ) ;
598+ Ok ( pck_cert)
599+ } ;
600+
586601 match self . pckcerts ( & pck_id. enc_ppid , pck_id. pce_id ) {
587602 Ok ( pck_certs) => return Ok ( pck_certs) ,
588603 Err ( Error :: RequestNotSupported ) => { } // fallback below
589604 Err ( e) => return Err ( e) ,
590605 }
591606 // fallback:
592607
593- // NOTE: at least with PCCS, any call to `pckcert()` will return the
594- // "best available" PCK cert for the specified TCB level.
595- let pck_cert = self . pckcert (
596- Some ( & pck_id. enc_ppid ) ,
597- & pck_id. pce_id ,
598- & pck_id. cpu_svn ,
599- pck_id. pce_isvsvn ,
600- Some ( & pck_id. qe_id ) ,
601- ) ?;
602608 // Use BTreeMap to have an ordered PckCerts at the end
603609 let mut pckcerts_map = BTreeMap :: new ( ) ;
604- // Getting PCK cert using CPUSVN from PCKID
605- {
606- let ptcb = pck_cert. platform_tcb ( ) ?;
607- pckcerts_map. insert ( ( ptcb. cpusvn , ptcb. tcb_components . pce_svn ( ) ) , pck_cert. clone ( ) ) ;
608- }
609- // Getting PCK cert using CPUSVN all 1's
610- {
611- if let Ok ( pck_cert) = self . pckcert (
612- Some ( & pck_id. enc_ppid ) ,
613- & pck_id. pce_id ,
614- & [ u8:: MAX ; 16 ] ,
615- pck_id. pce_isvsvn ,
616- Some ( & pck_id. qe_id ) ,
617- ) {
618- let ptcb = pck_cert. platform_tcb ( ) ?;
619- pckcerts_map. insert ( ( ptcb. cpusvn , ptcb. tcb_components . pce_svn ( ) ) , pck_cert) ;
620- }
621- }
610+
611+ // 1. Use PCK ID to get best available PCK Cert
612+ let pck_cert = get_and_collect ( & mut pckcerts_map, & pck_id. cpu_svn , pck_id. pce_isvsvn ) ?;
613+
614+ // 2. Getting PCK cert using CPUSVN all 1's
615+ let _ign_err = get_and_collect ( & mut pckcerts_map, & [ u8:: MAX ; 16 ] , pck_id. pce_isvsvn ) ;
616+
622617 let fmspc = pck_cert. sgx_extension ( ) ?. fmspc ;
623618 let tcb_info = self . tcbinfo ( & fmspc, None ) ?;
624619 let tcb_data = tcb_info. data ( ) ?;
625- // For every CPUSVN we also try where the late microcode value is higher
626- // than the early microcode value, the CPUSVN where the early
627- // microcode value is set to the late microcode value
628- for ( cpu_svn, pce_isvsvn) in tcb_data. iter_tcb_components ( )
629- . chain ( tcb_data. iter_tcb_components_with_late_tcb_override_only ( ) )
630- {
631- let p = match self . pckcert (
632- Some ( & pck_id. enc_ppid ) ,
633- & pck_id. pce_id ,
634- & cpu_svn,
635- pce_isvsvn,
636- Some ( & pck_id. qe_id ) ,
637- ) {
638- Ok ( cert) => cert,
639- Err ( Error :: PCSError ( StatusCode :: NotFound , _) ) |
640- Err ( Error :: PCSError ( StatusCode :: NonStandard462 , _) ) => continue ,
641- Err ( other) => return Err ( other)
642- } ;
643- let ptcb = p. platform_tcb ( ) ?;
644- pckcerts_map. insert ( ( ptcb. cpusvn , ptcb. tcb_components . pce_svn ( ) ) , p) ;
620+ for ( cpu_svn, pce_isvsvn) in tcb_data. iter_tcb_components ( ) {
621+ // 3. Get PCK based on TCB levels
622+ let _ = get_and_collect ( & mut pckcerts_map, & cpu_svn, pce_isvsvn) ?;
623+
624+ // 4. If late loaded microcode version is higher than early loaded microcode,
625+ // also try with highest microcode version of both components. We found cases where
626+ // fetching the PCK Cert that exactly matched the TCB level, did not result in a PCK
627+ // Cert for that level
628+ const EARLY_UCODE_IDX : usize = 0 ;
629+ const LATE_UCODE_IDX : usize = 1 ;
630+ // Unfortunately the TCB Info does not populate the component type (e.g., curl -v -X GET
631+ // "https://api.trustedservices.intel.com/sgx/certification/v4/tcb?fmspc=00906ED50000&tcbEvaluationDataNumber=20"
632+ // ). We pick a default as backup, and ensure errors fetching these PckCerts are
633+ // ignored.
634+ let eary_ucode_idx = tcb_data. tcb_component_index ( TcbComponent :: EarlyMicrocodeUpdate ) . unwrap_or ( EARLY_UCODE_IDX ) ;
635+ let late_ucode_idx = tcb_data. tcb_component_index ( TcbComponent :: LateMicrocodeUpdate ) . unwrap_or ( LATE_UCODE_IDX ) ;
636+ let early_ucode = cpu_svn[ eary_ucode_idx] ;
637+ let late_ucode = cpu_svn[ late_ucode_idx] ;
638+ if early_ucode < late_ucode {
639+ let mut cpu_svn = cpu_svn. clone ( ) ;
640+ cpu_svn[ eary_ucode_idx] = late_ucode;
641+ let _ign_err = get_and_collect ( & mut pckcerts_map, & cpu_svn, pce_isvsvn) ;
642+ }
645643 }
644+
646645 // BTreeMap by default is Ascending
647646 let pck_certs: Vec < _ > = pckcerts_map. into_iter ( ) . rev ( ) . map ( |( _, v) | v) . collect ( ) ;
648647 pck_certs
0 commit comments