1- use std:: time:: SystemTimeError ;
1+ use std:: {
2+ collections:: HashMap ,
3+ fmt:: { self , Display , Formatter } ,
4+ time:: SystemTimeError ,
5+ } ;
26
37use configfs_tsm:: QuoteGenerationError ;
48use dcap_qvl:: {
59 collateral:: get_collateral_for_fmspc,
610 quote:: { Quote , Report } ,
711} ;
12+ use http:: { header:: InvalidHeaderValue , HeaderValue } ;
813use sha2:: { Digest , Sha256 } ;
914use tdx_quote:: QuoteParseError ;
1015use thiserror:: Error ;
@@ -14,12 +19,105 @@ use x509_parser::prelude::*;
1419/// For fetching collateral directly from intel, if no PCCS is specified
1520const PCS_URL : & str = "https://api.trustedservices.intel.com" ;
1621
22+ #[ derive( Debug , Clone , PartialEq ) ]
23+ pub struct Measurements {
24+ pub platform : PlatformMeasurements ,
25+ pub cvm_image : CvmImageMeasurements ,
26+ }
27+
28+ impl Measurements {
29+ pub fn to_header_format ( & self ) -> Result < HeaderValue , MeasurementFormatError > {
30+ let mut measurements_map = HashMap :: new ( ) ;
31+ measurements_map. insert ( 0 , hex:: encode ( self . platform . mrtd ) ) ;
32+ measurements_map. insert ( 1 , hex:: encode ( self . platform . rtmr0 ) ) ;
33+ measurements_map. insert ( 2 , hex:: encode ( self . cvm_image . rtmr1 ) ) ;
34+ measurements_map. insert ( 3 , hex:: encode ( self . cvm_image . rtmr2 ) ) ;
35+ measurements_map. insert ( 4 , hex:: encode ( self . cvm_image . rtmr3 ) ) ;
36+ Ok ( HeaderValue :: from_str ( & serde_json:: to_string (
37+ & measurements_map,
38+ ) ?) ?)
39+ }
40+
41+ pub fn from_header_format ( input : & str ) -> Result < Self , MeasurementFormatError > {
42+ let measurements_map: HashMap < u32 , String > = serde_json:: from_str ( input) ?;
43+ let measurements_map: HashMap < u32 , [ u8 ; 48 ] > = measurements_map
44+ . into_iter ( )
45+ . map ( |( k, v) | ( k, hex:: decode ( v) . unwrap ( ) . try_into ( ) . unwrap ( ) ) )
46+ . collect ( ) ;
47+
48+ Ok ( Self {
49+ platform : PlatformMeasurements {
50+ mrtd : * measurements_map
51+ . get ( & 0 )
52+ . ok_or ( MeasurementFormatError :: MissingValue ( "MRTD" . to_string ( ) ) ) ?,
53+ rtmr0 : * measurements_map
54+ . get ( & 1 )
55+ . ok_or ( MeasurementFormatError :: MissingValue ( "RTMR0" . to_string ( ) ) ) ?,
56+ } ,
57+ cvm_image : CvmImageMeasurements {
58+ rtmr1 : * measurements_map
59+ . get ( & 2 )
60+ . ok_or ( MeasurementFormatError :: MissingValue ( "RTMR1" . to_string ( ) ) ) ?,
61+ rtmr2 : * measurements_map
62+ . get ( & 3 )
63+ . ok_or ( MeasurementFormatError :: MissingValue ( "RTMR2" . to_string ( ) ) ) ?,
64+ rtmr3 : * measurements_map
65+ . get ( & 4 )
66+ . ok_or ( MeasurementFormatError :: MissingValue ( "RTMR3" . to_string ( ) ) ) ?,
67+ } ,
68+ } )
69+ }
70+ }
71+
72+ #[ derive( Error , Debug ) ]
73+ pub enum MeasurementFormatError {
74+ #[ error( "JSON: {0}" ) ]
75+ Json ( #[ from] serde_json:: Error ) ,
76+ #[ error( "Missing value: {0}" ) ]
77+ MissingValue ( String ) ,
78+ #[ error( "Invalid header value: {0}" ) ]
79+ BadHeaderValue ( #[ from] InvalidHeaderValue ) ,
80+ }
81+
82+ /// Type of attestaion used
83+ /// Only supported (or soon-to-be supported) types are given
84+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
85+ pub enum AttestationType {
86+ /// No attestion
87+ None ,
88+ /// Mock attestion
89+ Dummy ,
90+ /// TDX on Google Cloud Platform
91+ GcpTdx ,
92+ /// TDX on Azure, with MAA
93+ AzureTdx ,
94+ /// TDX on Qemu (no cloud platform)
95+ QemuTdx ,
96+ }
97+
98+ impl AttestationType {
99+ /// Matches the names used by Constellation aTLS
100+ pub fn as_str ( & self ) -> & ' static str {
101+ match self {
102+ AttestationType :: None => "none" ,
103+ AttestationType :: Dummy => "dummy" ,
104+ AttestationType :: AzureTdx => "azure-tdx" ,
105+ AttestationType :: QemuTdx => "qemu-tdx" ,
106+ AttestationType :: GcpTdx => "gcp-tdx" ,
107+ }
108+ }
109+ }
110+
111+ impl Display for AttestationType {
112+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
113+ f. write_str ( self . as_str ( ) )
114+ }
115+ }
116+
17117/// Defines how to generate a quote
18118pub trait QuoteGenerator : Clone + Send + ' static {
19- /// Whether this is CVM attestation. This should always return true except for the [NoQuoteGenerator] case.
20- ///
21- /// When false, allows TLS client to be configured without client authentication
22- fn is_cvm ( & self ) -> bool ;
119+ /// Type of attestation used
120+ fn attestation_type ( & self ) -> AttestationType ;
23121
24122 /// Generate an attestation
25123 fn create_attestation (
@@ -31,27 +129,28 @@ pub trait QuoteGenerator: Clone + Send + 'static {
31129
32130/// Defines how to verify a quote
33131pub trait QuoteVerifier : Clone + Send + ' static {
34- /// Whether this is CVM attestation. This should always return true except for the [NoQuoteVerifier] case.
35- ///
36- /// When false, allows TLS client to be configured without client authentication
37- fn is_cvm ( & self ) -> bool ;
132+ /// Type of attestation used
133+ fn attestation_type ( & self ) -> AttestationType ;
38134
39135 /// Verify the given attestation payload
40136 fn verify_attestation (
41137 & self ,
42138 input : Vec < u8 > ,
43139 cert_chain : & [ CertificateDer < ' _ > ] ,
44140 exporter : [ u8 ; 32 ] ,
45- ) -> impl Future < Output = Result < ( ) , AttestationError > > + Send ;
141+ ) -> impl Future < Output = Result < Option < Measurements > , AttestationError > > + Send ;
46142}
47143
48144/// Quote generation using configfs_tsm
49145#[ derive( Clone ) ]
50- pub struct DcapTdxQuoteGenerator ;
146+ pub struct DcapTdxQuoteGenerator {
147+ pub attestation_type : AttestationType ,
148+ }
51149
52150impl QuoteGenerator for DcapTdxQuoteGenerator {
53- fn is_cvm ( & self ) -> bool {
54- true
151+ /// Type of attestation used
152+ fn attestation_type ( & self ) -> AttestationType {
153+ self . attestation_type
55154 }
56155
57156 fn create_attestation (
@@ -66,7 +165,7 @@ impl QuoteGenerator for DcapTdxQuoteGenerator {
66165}
67166
68167/// Measurements determined by the CVM platform
69- #[ derive( Clone , PartialEq ) ]
168+ #[ derive( Clone , PartialEq , Debug ) ]
70169pub struct PlatformMeasurements {
71170 pub mrtd : [ u8 ; 48 ] ,
72171 pub rtmr0 : [ u8 ; 48 ] ,
@@ -96,7 +195,7 @@ impl PlatformMeasurements {
96195}
97196
98197/// Measurements determined by the CVM image
99- #[ derive( Clone , PartialEq ) ]
198+ #[ derive( Clone , PartialEq , Debug ) ]
100199pub struct CvmImageMeasurements {
101200 pub rtmr1 : [ u8 ; 48 ] ,
102201 pub rtmr2 : [ u8 ; 48 ] ,
@@ -132,6 +231,7 @@ impl CvmImageMeasurements {
132231/// OS image specific measurements
133232#[ derive( Clone ) ]
134233pub struct DcapTdxQuoteVerifier {
234+ pub attestation_type : AttestationType ,
135235 /// Platform specific allowed Measurements
136236 /// Currently an option as this may be determined internally on a per-platform basis (Eg: GCP)
137237 pub accepted_platform_measurements : Option < Vec < PlatformMeasurements > > ,
@@ -142,16 +242,17 @@ pub struct DcapTdxQuoteVerifier {
142242}
143243
144244impl QuoteVerifier for DcapTdxQuoteVerifier {
145- fn is_cvm ( & self ) -> bool {
146- true
245+ /// Type of attestation used
246+ fn attestation_type ( & self ) -> AttestationType {
247+ self . attestation_type
147248 }
148249
149250 async fn verify_attestation (
150251 & self ,
151252 input : Vec < u8 > ,
152253 cert_chain : & [ CertificateDer < ' _ > ] ,
153254 exporter : [ u8 ; 32 ] ,
154- ) -> Result < ( ) , AttestationError > {
255+ ) -> Result < Option < Measurements > , AttestationError > {
155256 let quote_input = compute_report_input ( cert_chain, exporter) ?;
156257 let ( platform_measurements, image_measurements) = if cfg ! ( not( test) ) {
157258 let now = std:: time:: SystemTime :: now ( )
@@ -205,7 +306,10 @@ impl QuoteVerifier for DcapTdxQuoteVerifier {
205306 return Err ( AttestationError :: UnacceptableOsImageMeasurements ) ;
206307 }
207308
208- Ok ( ( ) )
309+ Ok ( Some ( Measurements {
310+ platform : platform_measurements,
311+ cvm_image : image_measurements,
312+ } ) )
209313 }
210314}
211315
@@ -236,8 +340,9 @@ pub fn compute_report_input(
236340pub struct NoQuoteGenerator ;
237341
238342impl QuoteGenerator for NoQuoteGenerator {
239- fn is_cvm ( & self ) -> bool {
240- false
343+ /// Type of attestation used
344+ fn attestation_type ( & self ) -> AttestationType {
345+ AttestationType :: None
241346 }
242347
243348 /// Create an empty attestation
@@ -255,18 +360,20 @@ impl QuoteGenerator for NoQuoteGenerator {
255360pub struct NoQuoteVerifier ;
256361
257362impl QuoteVerifier for NoQuoteVerifier {
258- fn is_cvm ( & self ) -> bool {
259- false
363+ /// Type of attestation used
364+ fn attestation_type ( & self ) -> AttestationType {
365+ AttestationType :: None
260366 }
367+
261368 /// Ensure that an empty attestation is given
262369 async fn verify_attestation (
263370 & self ,
264371 input : Vec < u8 > ,
265372 _cert_chain : & [ CertificateDer < ' _ > ] ,
266373 _exporter : [ u8 ; 32 ] ,
267- ) -> Result < ( ) , AttestationError > {
374+ ) -> Result < Option < Measurements > , AttestationError > {
268375 if input. is_empty ( ) {
269- Ok ( ( ) )
376+ Ok ( None )
270377 } else {
271378 Err ( AttestationError :: AttestationGivenWhenNoneExpected )
272379 }
0 commit comments