11use az_tdx_vtpm:: { hcl, imds, report, tdx, vtpm} ;
22use tokio_rustls:: rustls:: pki_types:: CertificateDer ;
33// use openssl::pkey::{PKey, Public};
4+ use base64:: prelude:: * ;
5+ use reqwest:: Client ;
6+ use serde:: Serialize ;
47
58use crate :: attestation:: { compute_report_input, AttestationError , AttestationType , QuoteGenerator } ;
69
710#[ derive( Clone ) ]
8- pub struct MaaQuoteGenerator { }
11+ pub struct MaaQuoteGenerator {
12+ maa_endpoint : String ,
13+ aad_access_token : String ,
14+ }
915
1016impl QuoteGenerator for MaaQuoteGenerator {
1117 /// Type of attestation used
@@ -18,7 +24,7 @@ impl QuoteGenerator for MaaQuoteGenerator {
1824 cert_chain : & [ CertificateDer < ' _ > ] ,
1925 exporter : [ u8 ; 32 ] ,
2026 ) -> Result < Vec < u8 > , AttestationError > {
21- let _quote_input = compute_report_input ( cert_chain, exporter) ?;
27+ let quote_input = compute_report_input ( cert_chain, exporter) ?;
2228
2329 let td_report = report:: get_report ( ) . unwrap ( ) ;
2430
@@ -29,22 +35,90 @@ impl QuoteGenerator for MaaQuoteGenerator {
2935 // let rtmr3 = td_report.tdinfo.rtrm[3];
3036
3137 // This makes a request to Azure Instance metadata service and gives us a binary response
32- let _td_quote_bytes = imds:: get_td_quote ( & td_report) . unwrap ( ) ;
38+ let td_quote_bytes = imds:: get_td_quote ( & td_report) . unwrap ( ) ;
3339
34- let bytes = vtpm:: get_report ( ) . unwrap ( ) ;
35- let hcl_report = hcl:: HclReport :: new ( bytes) . unwrap ( ) ;
36- let var_data_hash = hcl_report. var_data_sha256 ( ) ;
37- let _ak_pub = hcl_report. ak_pub ( ) . unwrap ( ) ;
40+ let hcl_report_bytes = vtpm:: get_report_with_report_data ( & quote_input) . unwrap ( ) ;
41+ let hcl_report = hcl:: HclReport :: new ( hcl_report_bytes) . unwrap ( ) ;
42+ let hcl_var_data = hcl_report. var_data ( ) ;
3843
39- let td_report: tdx:: TdReport = hcl_report. try_into ( ) . unwrap ( ) ;
40- assert ! ( var_data_hash == td_report. report_mac. reportdata[ ..32 ] ) ;
44+ // let bytes = vtpm::get_report().unwrap();
45+ // let hcl_report = hcl::HclReport::new(bytes).unwrap();
46+ // let var_data_hash = hcl_report.var_data_sha256();
47+ // let _ak_pub = hcl_report.ak_pub().unwrap();
48+ //
49+ // let td_report: tdx::TdReport = hcl_report.try_into().unwrap();
50+ // assert!(var_data_hash == td_report.report_mac.reportdata[..32]);
4151
4252 // let nonce = "a nonce".as_bytes();
4353 //
4454 // let tpm_quote = vtpm::get_quote(nonce).unwrap();
4555 // let der = ak_pub.key.try_to_der().unwrap();
4656 // let pub_key = PKey::public_key_from_der(&der).unwrap();
4757 // tpm_quote.verify(&pub_key, nonce).unwrap();
58+
59+ let quote_b64 = BASE64_STANDARD . encode ( & td_quote_bytes) ;
60+ let runtime_b64 = BASE64_STANDARD . encode ( hcl_var_data) ;
61+
62+ let body = TdxVmRequest {
63+ quote : quote_b64,
64+ runtimeData : Some ( RuntimeData {
65+ data : runtime_b64,
66+ data_type : "Binary" ,
67+ } ) ,
68+ nonce : Some ( "my-app-nonce-or-session-id" . to_string ( ) ) ,
69+ } ;
70+ let body_bytes = serde_json:: to_vec ( & body) . unwrap ( ) ;
71+ let jwt_token = self . call_tdxvm_attestation ( body_bytes) . await ;
4872 todo ! ( )
4973 }
5074}
75+
76+ impl MaaQuoteGenerator {
77+ /// Get a signed JWT from the azure API
78+ async fn call_tdxvm_attestation (
79+ & self ,
80+ body_bytes : Vec < u8 > ,
81+ ) -> Result < String , Box < dyn std:: error:: Error > > {
82+ let url = format ! ( "{}/attest/TdxVm?api-version=2025-06-01" , self . maa_endpoint) ;
83+
84+ let client = Client :: new ( ) ;
85+ let res = client
86+ . post ( & url)
87+ . bearer_auth ( & self . aad_access_token )
88+ . header ( "Content-Type" , "application/json" )
89+ . body ( body_bytes)
90+ . send ( )
91+ . await ?;
92+
93+ let status = res. status ( ) ;
94+ let text = res. text ( ) . await ?;
95+
96+ if !status. is_success ( ) {
97+ return Err ( format ! ( "MAA attestation failed: {status} {text}" ) . into ( ) ) ;
98+ }
99+
100+ #[ derive( serde:: Deserialize ) ]
101+ struct AttestationResponse {
102+ token : String ,
103+ }
104+
105+ let parsed: AttestationResponse = serde_json:: from_str ( & text) ?;
106+ Ok ( parsed. token ) // Microsoft-signed JWT
107+ }
108+ }
109+
110+ #[ derive( Serialize ) ]
111+ struct RuntimeData < ' a > {
112+ data : String , // base64url of VarData bytes
113+ #[ serde( rename = "dataType" ) ]
114+ data_type : & ' a str , // "Binary" in our case
115+ }
116+
117+ #[ derive( Serialize ) ]
118+ struct TdxVmRequest < ' a > {
119+ quote : String , // base64url(TDX quote)
120+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
121+ runtimeData : Option < RuntimeData < ' a > > ,
122+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
123+ nonce : Option < String > ,
124+ }
0 commit comments