1+ use std:: time:: SystemTimeError ;
2+
13use configfs_tsm:: QuoteGenerationError ;
24use dcap_qvl:: {
35 collateral:: get_collateral_for_fmspc,
46 quote:: { Quote , Report } ,
57} ;
68use sha2:: { Digest , Sha256 } ;
9+ use tdx_quote:: QuoteParseError ;
710use thiserror:: Error ;
811use tokio_rustls:: rustls:: pki_types:: CertificateDer ;
912use x509_parser:: prelude:: * ;
1013
14+ /// For fetching collateral directly from intel, if no PCCS is specified
1115const PCS_URL : & str = "https://api.trustedservices.intel.com" ;
1216
17+ /// Defines how to generate a quote
1318pub trait QuoteGenerator : Clone + Send + ' static {
14- /// Whether this is CVM attestation. This should always return true except for the [NoAttestation ] case.
19+ /// Whether this is CVM attestation. This should always return true except for the [NoQuoteGenerator ] case.
1520 ///
1621 /// When false, allows TLS client to be configured without client authentication
1722 fn is_cvm ( & self ) -> bool ;
@@ -24,8 +29,9 @@ pub trait QuoteGenerator: Clone + Send + 'static {
2429 ) -> Result < Vec < u8 > , AttestationError > ;
2530}
2631
32+ /// Defines how to verify a quote
2733pub trait QuoteVerifier : Clone + Send + ' static {
28- /// Whether this is CVM attestation. This should always return true except for the [NoAttestation ] case.
34+ /// Whether this is CVM attestation. This should always return true except for the [NoQuoteVerifier ] case.
2935 ///
3036 /// When false, allows TLS client to be configured without client authentication
3137 fn is_cvm ( & self ) -> bool ;
@@ -39,6 +45,7 @@ pub trait QuoteVerifier: Clone + Send + 'static {
3945 ) -> impl Future < Output = Result < ( ) , AttestationError > > + Send ;
4046}
4147
48+ /// Quote generation using configfs_tsm
4249#[ derive( Clone ) ]
4350pub struct DcapTdxQuoteGenerator ;
4451
@@ -120,10 +127,18 @@ impl CvmImageMeasurements {
120127 }
121128 }
122129}
130+
131+ /// Verify DCAP TDX quotes, allowing them if they have one of a given set of platform-specific and
132+ /// OS image specific measurements
123133#[ derive( Clone ) ]
124134pub struct DcapTdxQuoteVerifier {
135+ /// Platform specific allowed Measurements
136+ /// Currently an option as this may be determined internally on a per-platform basis (Eg: GCP)
125137 pub accepted_platform_measurements : Option < Vec < PlatformMeasurements > > ,
138+ /// OS-image specific allows measurement - this is effectively a list of allowed OS images
126139 pub accepted_cvm_image_measurements : Vec < CvmImageMeasurements > ,
140+ /// URL of a PCCS (defaults to Intel PCS)
141+ pub pccs_url : Option < String > ,
127142}
128143
129144impl QuoteVerifier for DcapTdxQuoteVerifier {
@@ -140,18 +155,22 @@ impl QuoteVerifier for DcapTdxQuoteVerifier {
140155 let quote_input = compute_report_input ( cert_chain, exporter) ?;
141156 let ( platform_measurements, image_measurements) = if cfg ! ( not( test) ) {
142157 let now = std:: time:: SystemTime :: now ( )
143- . duration_since ( std:: time:: UNIX_EPOCH )
144- . unwrap ( )
158+ . duration_since ( std:: time:: UNIX_EPOCH ) ?
145159 . as_secs ( ) ;
146- let quote = Quote :: parse ( & input) . unwrap ( ) ;
147- let ca = quote. ca ( ) . unwrap ( ) ;
148- let fmspc = hex:: encode_upper ( quote. fmspc ( ) . unwrap ( ) ) ;
149- let collateral = get_collateral_for_fmspc ( PCS_URL , fmspc, ca, false )
150- . await
151- . unwrap ( ) ;
152- let _verified_report = dcap_qvl:: verify:: verify ( & input, & collateral, now) . unwrap ( ) ;
153-
154- let quote = Quote :: parse ( & input) . unwrap ( ) ;
160+ let quote = Quote :: parse ( & input) ?;
161+
162+ let ca = quote. ca ( ) ?;
163+ let fmspc = hex:: encode_upper ( quote. fmspc ( ) ?) ;
164+ let collateral = get_collateral_for_fmspc (
165+ & self . pccs_url . clone ( ) . unwrap_or ( PCS_URL . to_string ( ) ) ,
166+ fmspc,
167+ ca,
168+ false ,
169+ )
170+ . await ?;
171+
172+ let _verified_report = dcap_qvl:: verify:: verify ( & input, & collateral, now) ?;
173+
155174 let measurements = (
156175 PlatformMeasurements :: from_dcap_qvl_quote ( & quote) ?,
157176 CvmImageMeasurements :: from_dcap_qvl_quote ( & quote) ?,
@@ -162,7 +181,7 @@ impl QuoteVerifier for DcapTdxQuoteVerifier {
162181 measurements
163182 } else {
164183 // In tests we use mock quotes which will fail to verify
165- let quote = tdx_quote:: Quote :: from_bytes ( & input) . unwrap ( ) ;
184+ let quote = tdx_quote:: Quote :: from_bytes ( & input) ? ;
166185 if quote. report_input_data ( ) != quote_input {
167186 return Err ( AttestationError :: InputMismatch ) ;
168187 }
@@ -176,15 +195,16 @@ impl QuoteVerifier for DcapTdxQuoteVerifier {
176195 if let Some ( accepted_platform_measurements) = & self . accepted_platform_measurements
177196 && !accepted_platform_measurements. contains ( & platform_measurements)
178197 {
179- panic ! ( "Bad measurements" ) ;
198+ return Err ( AttestationError :: UnacceptablePlatformMeasurements ) ;
180199 }
181200
182201 if !self
183202 . accepted_cvm_image_measurements
184203 . contains ( & image_measurements)
185204 {
186- panic ! ( "Bad measurements" ) ;
205+ return Err ( AttestationError :: UnacceptableOsImageMeasurements ) ;
187206 }
207+
188208 Ok ( ( ) )
189209 }
190210}
@@ -304,4 +324,14 @@ pub enum AttestationError {
304324 QuoteGeneration ( #[ from] configfs_tsm:: QuoteGenerationError ) ,
305325 #[ error( "SGX quote given when TDX quote expected" ) ]
306326 SgxNotSupported ,
327+ #[ error( "Platform measurements do not match any accepted values" ) ]
328+ UnacceptablePlatformMeasurements ,
329+ #[ error( "OS image measurements do not match any accepted values" ) ]
330+ UnacceptableOsImageMeasurements ,
331+ #[ error( "System Time: {0}" ) ]
332+ SystemTime ( #[ from] SystemTimeError ) ,
333+ #[ error( "DCAP quote verification: {0}" ) ]
334+ DcapQvl ( #[ from] anyhow:: Error ) ,
335+ #[ error( "Quote parse: {0}" ) ]
336+ QuoteParse ( #[ from] QuoteParseError ) ,
307337}
0 commit comments