1use std::{borrow::Cow, convert::TryInto, ffi::CString, mem};
2
3use byteorder::{ByteOrder, LittleEndian};
4use chrono::prelude::*;
5use mbedtls::{
6 alloc::List as MbedtlsList,
7 ecp::{EcGroup, EcPoint},
8 hash::{self, Md},
9 pk::{EcGroupId, Pk},
10 x509::certificate::Certificate,
11};
12use num_derive::{FromPrimitive, ToPrimitive};
13use num_traits::FromPrimitive;
14use sgx_isa::AttributesFlags;
15
16use super::{
17 certificates::PCS_TRUST_ROOT,
18 constants::*,
19 policy::QuotePolicy,
20 report::{SgxReport, TdAttributes, TdReport},
21 tcb::{QEIdentity, TCBBundle, TCBInfo, TCBLevel, TCBStatus},
22 utils::{x509_custom_ts_verify_cb, TakePrefix},
23 Error,
24};
25use crate::common::sgx::{EnclaveIdentity, MrEnclave, MrSigner, VerifiedQuote};
26
27#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
29pub struct QuoteBundle {
30 #[cbor(rename = "quote")]
31 pub quote: Vec<u8>,
32
33 #[cbor(rename = "tcb")]
34 pub tcb: TCBBundle,
35}
36
37impl QuoteBundle {
38 pub fn verify(&self, policy: &QuotePolicy, ts: DateTime<Utc>) -> Result<VerifiedQuote, Error> {
40 if policy.disabled {
41 return Err(Error::Disabled);
42 }
43
44 let unsafe_skip_quote_verification = option_env!("OASIS_UNSAFE_SKIP_AVR_VERIFY").is_some();
47 let unsafe_lax_quote_verification = option_env!("OASIS_UNSAFE_LAX_AVR_VERIFY").is_some();
48
49 let quote = Quote::parse(&self.quote)?;
51 let tee_type = quote.header().tee_type();
52
53 match (tee_type, &policy.tdx) {
55 (TeeType::SGX, _) => { }
56 (TeeType::TDX, &None) => return Err(Error::TeeTypeNotAllowed),
57 (TeeType::TDX, &Some(_)) => { }
58 }
59
60 if quote.header().qe_vendor_id() != QE_VENDOR_ID_INTEL {
62 return Err(Error::UnsupportedQEVendor);
63 }
64
65 let mut tcb_cert = self.tcb.verify_certificates(ts)?;
67 let qe_identity =
68 self.tcb
69 .qe_identity
70 .open(tee_type, ts, policy, tcb_cert.public_key_mut())?;
71 let tcb_info = self
72 .tcb
73 .tcb_info
74 .open(tee_type, ts, policy, tcb_cert.public_key_mut())?;
75
76 let timestamp = NaiveDateTime::parse_from_str(&tcb_info.issue_date, PCS_TS_FMT)
78 .map_err(|err| Error::TCBParseError(err.into()))?
79 .and_utc()
80 .timestamp();
81
82 if !unsafe_skip_quote_verification {
84 let tcb_level = quote.verify(tcb_info, qe_identity, ts)?;
85
86 match tcb_level.status {
88 TCBStatus::UpToDate | TCBStatus::SWHardeningNeeded => {}
89 TCBStatus::OutOfDate
90 | TCBStatus::ConfigurationNeeded
91 | TCBStatus::OutOfDateConfigurationNeeded
92 if unsafe_lax_quote_verification => {}
93 _ => {
94 return Err(Error::TCBOutOfDate);
95 }
96 }
97 }
98
99 let is_debug = quote.report_body().is_debug();
102 let allow_debug = option_env!("OASIS_UNSAFE_ALLOW_DEBUG_ENCLAVES").is_some();
103 if is_debug && !allow_debug {
104 return Err(Error::DebugEnclave);
105 } else if !is_debug && allow_debug {
106 return Err(Error::ProductionEnclave);
107 }
108
109 if let ReportBody::Tdx(report) = quote.report_body() {
111 let tdx_policy = policy.tdx.as_ref().ok_or(Error::TeeTypeNotAllowed)?;
112 tdx_policy.verify(report)?;
113 }
114
115 Ok(VerifiedQuote {
116 report_data: quote.report_body().report_data(),
117 identity: quote.report_body().as_enclave_identity(),
118 timestamp,
119 })
120 }
121}
122
123#[derive(Debug)]
125pub struct Quote<'a> {
126 header: Header<'a>,
127 report_body: ReportBody,
128 signature: QuoteSignatureEcdsaP256<'a>,
129 signed_data: Cow<'a, [u8]>,
130}
131
132impl<'a> Quote<'a> {
133 pub fn parse<T: Into<Cow<'a, [u8]>>>(quote: T) -> Result<Quote<'a>, Error> {
134 let mut quote = quote.into();
135 let mut raw = quote.clone();
136
137 let version = quote
139 .take_prefix(mem::size_of::<u16>())
140 .map(|v| LittleEndian::read_u16(&v))?;
141 match version {
142 QUOTE_VERSION_3 => {
143 let att_key_type = quote
145 .take_prefix(mem::size_of::<u16>())
146 .map(|v| LittleEndian::read_u16(&v))?;
147 let attestation_key_type = AttestationKeyType::from_u16(att_key_type)
148 .ok_or(Error::UnsupportedAttestationKeyType)?;
149 let reserved = quote
150 .take_prefix(mem::size_of::<u32>())
151 .map(|v| LittleEndian::read_u32(&v))?;
152 if reserved != 0 {
153 return Err(Error::QuoteParseError("data in reserved field".to_string()));
154 }
155
156 let qe_svn = quote
157 .take_prefix(mem::size_of::<u16>())
158 .map(|v| LittleEndian::read_u16(&v))?;
159 let pce_svn = quote
160 .take_prefix(mem::size_of::<u16>())
161 .map(|v| LittleEndian::read_u16(&v))?;
162 let qe_vendor_id = quote.take_prefix(QE_VENDOR_ID_LEN)?;
163 let user_data = quote.take_prefix(QE_USER_DATA_LEN)?;
164 let report_body = quote.take_prefix(SGX_REPORT_BODY_LEN)?;
165 let report_body = ReportBody::parse(TeeType::SGX, &report_body)?;
166
167 if attestation_key_type != AttestationKeyType::EcdsaP256 {
168 return Err(Error::UnsupportedAttestationKeyType);
169 }
170 let signature = QuoteSignatureEcdsaP256::parse(version, quote)?;
171 let signed_data = raw.take_prefix(QUOTE_HEADER_LEN + SGX_REPORT_BODY_LEN)?;
172
173 Ok(Quote {
174 header: Header::V3 {
175 attestation_key_type,
176 qe_svn,
177 pce_svn,
178 qe_vendor_id,
179 user_data,
180 },
181 report_body,
182 signature,
183 signed_data,
184 })
185 }
186 QUOTE_VERSION_4 => {
187 let att_key_type = quote
189 .take_prefix(mem::size_of::<u16>())
190 .map(|v| LittleEndian::read_u16(&v))?;
191 let attestation_key_type = AttestationKeyType::from_u16(att_key_type)
192 .ok_or(Error::UnsupportedAttestationKeyType)?;
193
194 let tee_type_raw = quote
195 .take_prefix(mem::size_of::<u32>())
196 .map(|v| LittleEndian::read_u32(&v))?;
197 let tee_type = TeeType::from_u32(tee_type_raw).ok_or(Error::UnsupportedTeeType)?;
198
199 let reserved1 = quote
200 .take_prefix(mem::size_of::<u16>())
201 .map(|v| LittleEndian::read_u16(&v))?;
202 let reserved2 = quote
203 .take_prefix(mem::size_of::<u16>())
204 .map(|v| LittleEndian::read_u16(&v))?;
205
206 if reserved1 != 0 || reserved2 != 0 {
207 return Err(Error::QuoteParseError("data in reserved field".to_string()));
208 }
209
210 let qe_vendor_id = quote.take_prefix(QE_VENDOR_ID_LEN)?;
211 let user_data = quote.take_prefix(QE_USER_DATA_LEN)?;
212
213 let header = Header::V4 {
214 attestation_key_type,
215 tee_type,
216 qe_vendor_id,
217 user_data,
218 };
219 let report_body = quote.take_prefix(header.report_body_len())?;
220 let report_body = ReportBody::parse(tee_type, &report_body)?;
221
222 if attestation_key_type != AttestationKeyType::EcdsaP256 {
223 return Err(Error::UnsupportedAttestationKeyType);
224 }
225 let signature = QuoteSignatureEcdsaP256::parse(version, quote)?;
226 let signed_data = raw.take_prefix(QUOTE_HEADER_LEN + header.report_body_len())?;
227
228 Ok(Quote {
229 header,
230 report_body,
231 signature,
232 signed_data,
233 })
234 }
235 _ => Err(Error::QuoteParseError(format!(
236 "unsupported quote version: {}",
237 version
238 ))),
239 }
240 }
241
242 pub fn header(&self) -> &Header<'a> {
244 &self.header
245 }
246
247 pub fn report_body(&self) -> &ReportBody {
249 &self.report_body
250 }
251
252 pub fn verify(
254 &self,
255 tcb_info: TCBInfo,
256 qe_identity: QEIdentity,
257 ts: DateTime<Utc>,
258 ) -> Result<TCBLevel, Error> {
259 let tdx_comp_svn = self.report_body.tdx_comp_svn();
260
261 let mut verifier: QeEcdsaP256Verifier =
262 QeEcdsaP256Verifier::new(tcb_info, qe_identity, tdx_comp_svn, ts);
263 self.signature.verify(&self.signed_data, &mut verifier)?;
264
265 Ok(verifier.tcb_level().unwrap())
266 }
267}
268
269#[derive(Debug)]
271pub enum Header<'a> {
272 V3 {
273 attestation_key_type: AttestationKeyType,
274 qe_svn: u16,
275 pce_svn: u16,
276 qe_vendor_id: Cow<'a, [u8]>,
277 user_data: Cow<'a, [u8]>,
278 },
279
280 V4 {
281 attestation_key_type: AttestationKeyType,
282 tee_type: TeeType,
283 qe_vendor_id: Cow<'a, [u8]>,
284 user_data: Cow<'a, [u8]>,
285 },
286}
287
288impl Header<'_> {
289 pub fn version(&self) -> u16 {
291 match self {
292 Self::V3 { .. } => QUOTE_VERSION_3,
293 Self::V4 { .. } => QUOTE_VERSION_4,
294 }
295 }
296
297 pub fn attestation_key_type(&self) -> AttestationKeyType {
299 match self {
300 Self::V3 {
301 attestation_key_type,
302 ..
303 } => *attestation_key_type,
304 Self::V4 {
305 attestation_key_type,
306 ..
307 } => *attestation_key_type,
308 }
309 }
310
311 pub fn tee_type(&self) -> TeeType {
313 match self {
314 Self::V3 { .. } => TeeType::SGX,
315 Self::V4 { tee_type, .. } => *tee_type,
316 }
317 }
318
319 pub fn qe_vendor_id(&self) -> &[u8] {
321 match self {
322 Self::V3 { qe_vendor_id, .. } => qe_vendor_id,
323 Self::V4 { qe_vendor_id, .. } => qe_vendor_id,
324 }
325 }
326
327 pub fn report_body_len(&self) -> usize {
329 match self.tee_type() {
330 TeeType::SGX => SGX_REPORT_BODY_LEN,
331 TeeType::TDX => TDX_REPORT_BODY_LEN,
332 }
333 }
334}
335
336#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)]
338#[repr(u32)]
339pub enum TeeType {
340 SGX = 0x00000000,
341 TDX = 0x00000081,
342}
343
344#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)]
346#[repr(u16)]
347pub enum AttestationKeyType {
348 EcdsaP256 = 2,
349}
350
351#[derive(Debug)]
353pub enum ReportBody {
354 Sgx(SgxReport),
355 Tdx(TdReport),
356}
357
358impl ReportBody {
359 pub fn parse(tee_type: TeeType, raw: &[u8]) -> Result<Self, Error> {
361 match tee_type {
362 TeeType::SGX => {
363 let mut report_body = Vec::with_capacity(SgxReport::UNPADDED_SIZE);
365 report_body.extend(raw);
366 report_body.resize_with(SgxReport::UNPADDED_SIZE, Default::default);
367 let report =
368 SgxReport::try_copy_from(&report_body).ok_or(Error::MalformedReport)?;
369
370 Ok(Self::Sgx(report))
371 }
372 TeeType::TDX => {
373 let report = TdReport::parse(raw)?;
375
376 Ok(Self::Tdx(report))
377 }
378 }
379 }
380
381 pub fn tdx_comp_svn(&self) -> Option<[u32; 16]> {
385 match self {
386 Self::Sgx(_) => None,
387 Self::Tdx(report) => Some(
388 report
389 .tee_tcb_svn
390 .iter()
391 .map(|x| *x as u32)
392 .collect::<Vec<u32>>()
393 .try_into()
394 .unwrap(),
395 ),
396 }
397 }
398
399 pub fn is_debug(&self) -> bool {
401 match self {
402 Self::Sgx(report) => report.attributes.flags.contains(AttributesFlags::DEBUG),
403 Self::Tdx(report) => report.td_attributes.contains(TdAttributes::DEBUG),
404 }
405 }
406
407 pub fn as_enclave_identity(&self) -> EnclaveIdentity {
409 match self {
410 Self::Sgx(report) => EnclaveIdentity {
411 mr_enclave: MrEnclave::from(report.mrenclave.to_vec()),
412 mr_signer: MrSigner::from(report.mrsigner.to_vec()),
413 },
414 Self::Tdx(report) => report.as_enclave_identity(),
415 }
416 }
417
418 pub fn report_data(&self) -> Vec<u8> {
420 match self {
421 Self::Sgx(report) => report.reportdata.to_vec(),
422 Self::Tdx(report) => report.report_data.to_vec(),
423 }
424 }
425}
426
427pub trait QuoteSignature<'a>: Sized {
429 fn parse(version: u16, data: Cow<'a, [u8]>) -> Result<Self, Error>;
431}
432
433#[derive(Debug)]
435pub struct QuoteSignatureEcdsaP256<'a> {
436 signature: Cow<'a, [u8]>,
437 attestation_public_key: Cow<'a, [u8]>,
438
439 qe: CertificationDataQeReport<'a>,
440}
441
442impl<'a> QuoteSignature<'a> for QuoteSignatureEcdsaP256<'a> {
443 fn parse(version: u16, mut data: Cow<'a, [u8]>) -> Result<Self, Error> {
444 let sig_len = data
445 .take_prefix(mem::size_of::<u32>())
446 .map(|v| LittleEndian::read_u32(&v))?;
447 if sig_len as usize != data.len() {
448 return Err(Error::QuoteParseError(
449 "unexpected trailing data after signature".to_string(),
450 ));
451 }
452 let signature = data.take_prefix(ECDSA_P256_SIGNATURE_LEN)?;
453 let attestation_public_key = data.take_prefix(ECDSA_P256_PUBLIC_KEY_LEN)?;
454
455 if version == QUOTE_VERSION_4 {
457 let cd_type = data
458 .take_prefix(mem::size_of::<u16>())
459 .map(|v| LittleEndian::read_u16(&v))?;
460 let certification_data_type =
461 CertificationDataType::from_u16(cd_type).ok_or_else(|| {
462 Error::QuoteParseError(format!("unknown certification data type: {}", cd_type))
463 })?;
464 let certdata_len = data
465 .take_prefix(mem::size_of::<u32>())
466 .map(|v| LittleEndian::read_u32(&v))?;
467 if certdata_len as usize != data.len() {
468 return Err(Error::QuoteParseError(
469 "invalid certification data length".to_string(),
470 ));
471 }
472
473 if certification_data_type != CertificationDataType::QeReport {
474 return Err(Error::UnexpectedCertificationData);
475 }
476 }
477
478 let qe = CertificationDataQeReport::parse(data)?;
479
480 Ok(QuoteSignatureEcdsaP256 {
481 signature,
482 attestation_public_key,
483 qe,
484 })
485 }
486}
487
488impl<'a> QuoteSignatureEcdsaP256<'a> {
489 pub fn signature(&self) -> &[u8] {
491 &self.signature
492 }
493
494 pub fn attestation_public_key(&self) -> &[u8] {
496 &self.attestation_public_key
497 }
498
499 pub fn verify_quote_signature(&'a self, data: &[u8]) -> Result<&'a Self, Error> {
503 let sig = raw_ecdsa_sig_to_der(self.signature())?;
504 let mut pk = parse_ecdsa_pk(self.attestation_public_key())?;
505
506 let mut hash = [0u8; 32];
507 Md::hash(hash::Type::Sha256, data, &mut hash).map_err(|err| Error::Other(err.into()))?;
508 pk.verify(hash::Type::Sha256, &hash, &sig)
509 .map_err(|_| Error::VerificationFailed("quote signature is invalid".to_string()))?;
510
511 Ok(self)
512 }
513
514 pub fn verify_qe_report_signature(&self, pck_pk: &[u8]) -> Result<(), Error> {
516 self.qe
517 .verify_qe_report_signature(self.attestation_public_key(), pck_pk)
518 }
519}
520
521fn raw_ecdsa_sig_to_der(sig: &[u8]) -> Result<Vec<u8>, Error> {
523 if sig.len() % 2 != 0 {
524 return Err(Error::QuoteParseError(
525 "malformed ECDSA signature".to_string(),
526 ));
527 }
528
529 let (r_bytes, s_bytes) = sig.split_at(sig.len() / 2);
530 let r = num_bigint::BigUint::from_bytes_be(r_bytes);
531 let s = num_bigint::BigUint::from_bytes_be(s_bytes);
532
533 let der = yasna::construct_der(|writer| {
534 writer.write_sequence(|writer| {
535 writer.next().write_biguint(&r);
536 writer.next().write_biguint(&s);
537 })
538 });
539
540 Ok(der)
541}
542
543fn parse_ecdsa_pk(pk: &[u8]) -> Result<Pk, Error> {
545 let mut pt = vec![0x4]; pt.extend_from_slice(pk);
547
548 let group = EcGroup::new(EcGroupId::SecP256R1).map_err(|err| Error::Other(err.into()))?;
549 let pt = EcPoint::from_binary(&group, &pt).map_err(|err| Error::Other(err.into()))?;
550 Pk::public_from_ec_components(group, pt).map_err(|err| Error::Other(err.into()))
551}
552
553pub trait QuoteSignatureEcdsaP256Verifier {
555 fn verify_certification_data(
561 &mut self,
562 signature: &QuoteSignatureEcdsaP256,
563 ) -> Result<Vec<u8>, Error>;
564
565 fn verify_qe(&mut self, qe_report: &[u8], authentication_data: &[u8]) -> Result<(), Error>;
567}
568
569pub trait QuoteSignatureVerify<'a>: QuoteSignature<'a> {
570 type TrustRoot;
571
572 fn verify(&self, quote: &[u8], root_of_trust: Self::TrustRoot) -> Result<(), Error>;
573}
574
575impl<'a> QuoteSignatureVerify<'a> for QuoteSignatureEcdsaP256<'a> {
576 type TrustRoot = &'a mut dyn QuoteSignatureEcdsaP256Verifier;
577
578 fn verify(&self, quote: &[u8], verifier: Self::TrustRoot) -> Result<(), Error> {
579 let pck_pk = verifier.verify_certification_data(self)?;
580 self.verify_qe_report_signature(&pck_pk)?;
581 verifier.verify_qe(self.qe.qe_report(), self.qe.authentication_data())?;
582 self.verify_quote_signature(quote)?;
583 Ok(())
584 }
585}
586
587#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)]
589#[repr(u16)]
590pub enum CertificationDataType {
591 PpidCleartext = 1,
592 PpidEncryptedRsa2048 = 2,
593 PpidEncryptedRsa3072 = 3,
594 PckCertificate = 4,
595 PckCertificateChain = 5,
596 QeReport = 6,
597 PlatformManifest = 7,
598}
599
600pub trait CertificationData<'a>: Sized {
602 fn parse(r#type: CertificationDataType, data: Cow<'a, [u8]>) -> Result<Self, Error>;
604}
605
606#[derive(Clone, Debug, Hash, PartialEq, Eq)]
608pub struct CertificationDataPpid<'a> {
609 pub ppid: Cow<'a, [u8]>,
610 pub cpusvn: Cow<'a, [u8]>,
611 pub pcesvn: u16,
612 pub pceid: u16,
613}
614
615impl<'a> CertificationData<'a> for CertificationDataPpid<'a> {
616 fn parse(r#type: CertificationDataType, mut data: Cow<'a, [u8]>) -> Result<Self, Error> {
617 let ppid_len = match r#type {
618 CertificationDataType::PpidEncryptedRsa2048 => 256,
619 CertificationDataType::PpidEncryptedRsa3072 => 384,
620 _ => return Err(Error::UnexpectedCertificationData),
621 };
622
623 let ppid = data.take_prefix(ppid_len)?;
624 let cpusvn = data.take_prefix(CPUSVN_LEN)?;
625 let pcesvn = data
626 .take_prefix(mem::size_of::<u16>())
627 .map(|v| LittleEndian::read_u16(&v))?;
628 let pceid = data
629 .take_prefix(mem::size_of::<u16>())
630 .map(|v| LittleEndian::read_u16(&v))?;
631 if !data.is_empty() {
632 return Err(Error::MalformedCertificationData);
633 }
634
635 Ok(CertificationDataPpid {
636 ppid,
637 cpusvn,
638 pcesvn,
639 pceid,
640 })
641 }
642}
643
644#[derive(Clone, Debug, Hash, PartialEq, Eq)]
646pub struct CertificationDataPckCertificateChain<'a> {
647 pub certs: Vec<Cow<'a, str>>,
648}
649
650impl<'a> CertificationData<'a> for CertificationDataPckCertificateChain<'a> {
651 fn parse(r#type: CertificationDataType, data: Cow<'a, [u8]>) -> Result<Self, Error> {
652 if r#type != CertificationDataType::PckCertificateChain {
653 return Err(Error::UnexpectedCertificationData);
654 }
655
656 let mut data = match data {
657 Cow::Borrowed(s) => std::str::from_utf8(s)
658 .map(Cow::Borrowed)
659 .map_err(|_| Error::MalformedPCK)?,
660 Cow::Owned(s) => String::from_utf8(s)
661 .map(Cow::Owned)
662 .map_err(|_| Error::MalformedPCK)?,
663 };
664
665 let mut certs = vec![];
666 let mark = "-----END CERTIFICATE-----";
667 while let Some(pos) = data.find(mark) {
668 certs.push(data.take_prefix(pos + mark.len()).unwrap()); if let Some(start) = data.find("-") {
670 data.take_prefix(start).unwrap(); }
672 }
673
674 Ok(CertificationDataPckCertificateChain { certs })
675 }
676}
677
678#[derive(Debug)]
680pub struct CertificationDataQeReport<'a> {
681 qe_report: Cow<'a, [u8]>,
682 qe_report_signature: Cow<'a, [u8]>,
683 authentication_data: Cow<'a, [u8]>,
684 certification_data_type: CertificationDataType,
685 certification_data: Cow<'a, [u8]>,
686}
687
688impl<'a> CertificationDataQeReport<'a> {
689 fn parse(mut data: Cow<'a, [u8]>) -> Result<Self, Error> {
690 let qe_report = data.take_prefix(SGX_REPORT_BODY_LEN)?;
691 let qe_report_signature = data.take_prefix(ECDSA_P256_SIGNATURE_LEN)?;
692 let authdata_len = data
693 .take_prefix(mem::size_of::<u16>())
694 .map(|v| LittleEndian::read_u16(&v))?;
695 let authentication_data = data.take_prefix(authdata_len as _)?;
696
697 let cd_type = data
698 .take_prefix(mem::size_of::<u16>())
699 .map(|v| LittleEndian::read_u16(&v))?;
700 let certification_data_type =
701 CertificationDataType::from_u16(cd_type).ok_or_else(|| {
702 Error::QuoteParseError(format!("unknown certification data type: {}", cd_type))
703 })?;
704 let certdata_len = data
705 .take_prefix(mem::size_of::<u32>())
706 .map(|v| LittleEndian::read_u32(&v))?;
707 if certdata_len as usize != data.len() {
708 return Err(Error::QuoteParseError(
709 "invalid certification data length".to_string(),
710 ));
711 }
712
713 Ok(CertificationDataQeReport {
714 qe_report,
715 qe_report_signature,
716 authentication_data,
717 certification_data_type,
718 certification_data: data,
719 })
720 }
721
722 pub fn qe_report(&self) -> &[u8] {
724 &self.qe_report
725 }
726
727 pub fn qe_report_signature(&self) -> &[u8] {
729 &self.qe_report_signature
730 }
731
732 pub fn authentication_data(&self) -> &[u8] {
734 &self.authentication_data
735 }
736
737 pub fn certification_data<T: CertificationData<'a>>(&self) -> Result<T, Error> {
739 T::parse(
740 self.certification_data_type,
741 self.certification_data.clone(),
742 )
743 }
744
745 pub fn verify_qe_report_signature(
747 &self,
748 attestation_pk: &[u8],
749 pck_pk: &[u8],
750 ) -> Result<(), Error> {
751 let sig = raw_ecdsa_sig_to_der(self.qe_report_signature())?;
753 let mut hash = [0u8; 32];
754 Md::hash(hash::Type::Sha256, self.qe_report(), &mut hash)
755 .map_err(|err| Error::Other(err.into()))?;
756 let mut pck_pk = Pk::from_public_key(pck_pk).map_err(|err| Error::Other(err.into()))?;
757 pck_pk
758 .verify(mbedtls::hash::Type::Sha256, &hash, &sig)
759 .map_err(|_| Error::VerificationFailed("QE report signature is invalid".to_string()))?;
760
761 let mut hash = [0u8; 32];
765 let mut sha256 = Md::new(hash::Type::Sha256).map_err(|err| Error::Other(err.into()))?;
766 sha256
767 .update(attestation_pk)
768 .map_err(|err| Error::Other(err.into()))?;
769 sha256
770 .update(self.authentication_data())
771 .map_err(|err| Error::Other(err.into()))?;
772 sha256
773 .finish(&mut hash)
774 .map_err(|err| Error::Other(err.into()))?;
775
776 let mut qe_report = Vec::with_capacity(SgxReport::UNPADDED_SIZE);
777 qe_report.extend(self.qe_report());
778 qe_report.resize_with(SgxReport::UNPADDED_SIZE, Default::default);
779 let qe_report = SgxReport::try_copy_from(&qe_report).ok_or(Error::MalformedQEReport)?;
780
781 if qe_report.reportdata[0..32] != hash {
782 return Err(Error::VerificationFailed(
783 "QE report data does not match expected value".to_string(),
784 ));
785 }
786 if qe_report.reportdata[32..64] != [0; 32] {
787 return Err(Error::VerificationFailed(
788 "QE report data does not match expected value".to_string(),
789 ));
790 }
791
792 Ok(())
793 }
794}
795
796pub struct QeEcdsaP256Verifier {
798 ts: DateTime<Utc>,
799 tcb_info: TCBInfo,
800 qe_identity: QEIdentity,
801 tdx_comp_svn: Option<[u32; 16]>,
802 tcb_level: Option<TCBLevel>,
803}
804
805impl QeEcdsaP256Verifier {
806 pub fn new(
808 tcb_info: TCBInfo,
809 qe_identity: QEIdentity,
810 tdx_comp_svn: Option<[u32; 16]>,
811 ts: DateTime<Utc>,
812 ) -> Self {
813 Self {
814 ts,
815 tcb_info,
816 qe_identity,
817 tdx_comp_svn,
818 tcb_level: None,
819 }
820 }
821
822 pub fn tcb_level(&self) -> Option<TCBLevel> {
825 self.tcb_level.clone()
826 }
827}
828
829impl QuoteSignatureEcdsaP256Verifier for QeEcdsaP256Verifier {
830 fn verify_certification_data(
831 &mut self,
832 signature: &QuoteSignatureEcdsaP256,
833 ) -> Result<Vec<u8>, Error> {
834 let certs = signature
836 .qe
837 .certification_data::<CertificationDataPckCertificateChain>()?
838 .certs;
839 if certs.len() != 3 {
840 return Err(Error::UnexpectedCertificateChain);
841 }
842
843 let mut cert_chain = MbedtlsList::new();
845 for raw_cert in &certs {
846 let raw_cert = CString::new(raw_cert.as_ref()).map_err(|_| Error::MalformedPCK)?;
847 let cert = Certificate::from_pem(raw_cert.as_bytes_with_nul())
848 .map_err(|_| Error::MalformedPCK)?;
849 cert_chain.push(cert);
850 }
851 Certificate::verify_with_callback(
852 &cert_chain,
853 &PCS_TRUST_ROOT,
854 None,
855 None,
856 x509_custom_ts_verify_cb(self.ts),
857 )
858 .map_err(|_| Error::VerificationFailed("PCK certificate chain is invalid".to_string()))?;
859
860 let mut pck_cert = cert_chain.pop_front().unwrap();
862
863 let sgx_extensions = pck_cert
864 .extensions()
865 .map_err(|_| Error::MalformedPCK)?
866 .into_iter()
867 .find(|ext| ext.oid.as_ref() == PCK_SGX_EXTENSIONS_OID)
868 .ok_or(Error::TCBVerificationFailed)?;
869 let mut fmspc: Option<Vec<u8>> = None;
870 let mut tcb_comp_svn: Option<[u32; 16]> = None;
871 let mut pcesvn: Option<u32> = None;
872 yasna::parse_der(&sgx_extensions.value, |reader| {
873 reader.read_sequence_of(|reader| {
874 reader.read_sequence(|reader| {
875 match reader.next().read_oid()?.as_ref() {
876 PCK_SGX_EXTENSIONS_FMSPC_OID => {
877 let raw_fmspc = reader.next().read_bytes()?;
879 if raw_fmspc.len() != 6 {
880 return Err(yasna::ASN1Error::new(yasna::ASN1ErrorKind::Invalid));
881 }
882 fmspc = Some(raw_fmspc);
883 }
884 PCK_SGX_EXTENSIONS_TCB_OID => {
885 reader.next().read_sequence_of(|reader| {
887 reader.read_sequence(|reader| {
888 let comp_id =
889 *reader.next().read_oid()?.as_ref().last().unwrap();
890 if (1..=16).contains(&comp_id) {
891 tcb_comp_svn.get_or_insert([0; 16])
893 [(comp_id - 1) as usize] = reader.next().read_u32()?;
894 } else if comp_id == 17 {
895 pcesvn = Some(reader.next().read_u32()?);
897 } else if comp_id == 18 {
898 reader.next().read_bytes()?;
900 }
901 Ok(())
902 })
903 })?;
904 }
905 _ => {
906 reader.next().read_der()?;
907 }
908 }
909
910 Ok(())
911 })
912 })
913 })
914 .map_err(|_| Error::MalformedPCK)?;
915 if fmspc.is_none() || tcb_comp_svn.is_none() || pcesvn.is_none() {
916 return Err(Error::MalformedPCK);
917 }
918
919 let tcb_level = self.tcb_info.verify(
921 &fmspc.unwrap(),
922 &tcb_comp_svn.unwrap(),
923 self.tdx_comp_svn.as_ref(),
924 pcesvn.unwrap(),
925 )?;
926 self.tcb_level = Some(tcb_level);
927
928 let pck_pk = pck_cert
930 .public_key_mut()
931 .write_public_der_vec()
932 .map_err(|_| Error::MalformedPCK)?;
933
934 Ok(pck_pk)
935 }
936
937 fn verify_qe(&mut self, qe_report: &[u8], _authentication_data: &[u8]) -> Result<(), Error> {
938 let mut report = Vec::with_capacity(SgxReport::UNPADDED_SIZE);
939 report.extend(qe_report);
940 report.resize_with(SgxReport::UNPADDED_SIZE, Default::default);
941
942 let report = SgxReport::try_copy_from(&report).ok_or(Error::MalformedQEReport)?;
943 self.qe_identity.verify(&report)?;
944
945 Ok(())
946 }
947}