1use byteorder::{ByteOrder, LE};
9#[cfg(feature = "verify")]
10use mbedtls::ecp::{EcGroup, EcPoint};
11#[cfg(feature = "verify")]
12use mbedtls::pk::{Pk, EcGroupId};
13#[cfg(feature = "verify")]
14use mbedtls::hash::{self, Md};
15use num_traits::FromPrimitive;
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18#[cfg(feature = "verify")]
19use sgx_isa::Report;
20use std::borrow::Cow;
21use std::mem;
22use anyhow::bail;
23
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub struct Quote<'a> {
30 header: QuoteHeader<'a>,
31 report_body: Cow<'a, [u8]>,
32 signature: Cow<'a, [u8]>,
33}
34
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36pub enum QuoteHeader<'a> {
37 V3 {
38 attestation_key_type: Quote3AttestationKeyType,
39 qe3_svn: u16,
40 pce_svn: u16,
41 qe3_vendor_id: Cow<'a, [u8]>,
42 user_data: Cow<'a, [u8]>,
43 },
44}
45
46#[repr(u16)]
47#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)]
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49pub enum Quote3AttestationKeyType {
50 EcdsaP256 = 2,
51 EcdsaP384 = 3,
52}
53
54pub const QE3_VENDOR_ID_INTEL: [u8; 16] = [
55 0x93, 0x9a, 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07,
56];
57
58pub type QeId<'a> = Cow<'a, [u8]>;
59
60pub struct Quote3SignatureEcdsaP256<'a> {
61 signature: Cow<'a, [u8]>,
62 attestation_public_key: Cow<'a, [u8]>,
63 qe3_report: Cow<'a, [u8]>,
64 qe3_signature: Cow<'a, [u8]>,
65 authentication_data: Cow<'a, [u8]>,
66 certification_data_type: CertificationDataType,
67 certification_data: Cow<'a, [u8]>,
68}
69
70#[repr(u16)]
71#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromPrimitive, ToPrimitive)]
72pub enum CertificationDataType {
73 PpidCleartext = 1,
74 PpidEncryptedRsa2048 = 2,
75 PpidEncryptedRsa3072 = 3,
76 PckCertificate = 4,
77 PckCertificateChain = 5,
78 EcdsaSignatureAuxiliaryData = 6,
79 PlatformManifest = 7,
80}
81
82#[derive(Clone, Debug, Hash, PartialEq, Eq)]
83pub struct Qe3CertDataPpid<'a> {
84 pub ppid: Cow<'a, [u8]>,
85 pub cpusvn: Cow<'a, [u8]>,
86 pub pcesvn: u16,
87 pub pceid: u16,
88}
89
90#[derive(Clone, Debug, Hash, PartialEq, Eq)]
91pub struct Qe3CertDataPckCertChain<'a> {
92 pub certs: Vec<Cow<'a, str>>,
93}
94
95pub type RawQe3CertData<'a> = Cow<'a, [u8]>;
96
97pub type Result<T> = ::std::result::Result<T, anyhow::Error>;
98
99trait TakePrefix: Sized {
104 fn take_prefix(&mut self, mid: usize) -> Result<Self>;
105}
106
107impl<'a, T: 'a> TakePrefix for &'a [T] {
108 fn take_prefix(&mut self, mid: usize) -> Result<Self> {
109 if let (Some(prefix), Some(rest)) = (self.get(..mid), self.get(mid..)) {
110 *self = rest;
111 Ok(prefix)
112 } else {
113 bail!("Unexpected end of quote")
114 }
115 }
116}
117
118impl<'a, T: 'a + Clone> TakePrefix for Cow<'a, [T]> {
119 fn take_prefix(&mut self, mid: usize) -> Result<Self> {
120 if mid <= self.len() {
121 match self {
122 &mut Cow::Borrowed(ref mut slice) => slice.take_prefix(mid).map(Cow::Borrowed),
123 &mut Cow::Owned(ref mut vec) => {
124 let rest = vec.split_off(mid);
125 Ok(Cow::Owned(mem::replace(vec, rest)))
126 },
127 }
128 } else {
129 bail!("Unexpected end of quote")
130 }
131 }
132}
133
134impl<'a> TakePrefix for &'a str {
135 fn take_prefix(&mut self, mid: usize) -> Result<Self> {
136 if let (Some(prefix), Some(rest)) = (self.get(..mid), self.get(mid..)) {
137 *self = rest;
138 Ok(prefix)
139 } else {
140 bail!("Unexpected end of quote")
141 }
142 }
143}
144
145impl<'a> TakePrefix for Cow<'a, str> {
146 fn take_prefix(&mut self, mid: usize) -> Result<Self> {
147 if mid <= self.len() {
148 match self {
149 &mut Cow::Borrowed(ref mut slice) => slice.take_prefix(mid).map(Cow::Borrowed),
150 &mut Cow::Owned(ref mut vec) => {
151 let rest = vec.split_off(mid);
152 Ok(Cow::Owned(mem::replace(vec, rest)))
153 },
154 }
155 } else {
156 bail!("Unexpected end of quote")
157 }
158 }
159}
160
161pub trait Quote3Signature<'a>: Sized {
162 fn parse(type_: Quote3AttestationKeyType, data: Cow<'a, [u8]>) -> Result<Self>;
163}
164
165pub trait Qe3CertData<'a>: Sized {
166 fn parse(type_: CertificationDataType, data: Cow<'a, [u8]>) -> Result<Self>;
167}
168
169const ECDSA_P256_SIGNATURE_LEN: usize = 64;
170const ECDSA_P256_PUBLIC_KEY_LEN: usize = 64;
171const QE3_VENDOR_ID_LEN: usize = 16;
172const QE3_USER_DATA_LEN: usize = 20;
173const REPORT_BODY_LEN: usize = 384;
174const CPUSVN_LEN: usize = 16;
175const QUOTE_VERSION_3: u16 = 3;
176
177impl<'a> Quote<'a> {
178 pub fn parse<T: Into<Cow<'a, [u8]>>>(quote: T) -> Result<Quote<'a>> {
179 let mut quote = quote.into();
180
181 let version = quote.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
182 if version != QUOTE_VERSION_3 {
183 bail!("Unknown quote version: {}", version);
184 }
185 let att_key_type = quote.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
186 let attestation_key_type = Quote3AttestationKeyType::from_u16(att_key_type)
187 .ok_or_else(|| format_err!("Unknown attestation key type: {}", att_key_type))?;
188 let reserved = quote.take_prefix(mem::size_of::<u32>()).map(|v| LE::read_u32(&v))?;
189 if reserved != 0 {
190 bail!("Data in reserved field: {:08x}", reserved);
191 }
192 let qe3_svn = quote.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
193 let pce_svn = quote.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
194 let qe3_vendor_id = quote.take_prefix(QE3_VENDOR_ID_LEN)?;
195 let user_data = quote.take_prefix(QE3_USER_DATA_LEN)?;
196 let report_body = quote.take_prefix(REPORT_BODY_LEN)?;
197
198 Ok(Quote {
199 header: QuoteHeader::V3 {
200 attestation_key_type,
201 qe3_svn,
202 pce_svn,
203 qe3_vendor_id,
204 user_data,
205 },
206 report_body,
207 signature: quote,
208 })
209 }
210}
211
212#[cfg(feature = "verify")]
214fn get_ecdsa_sig_der(sig: &[u8]) -> Result<Vec<u8>> {
215 if sig.len() % 2 != 0 {
216 bail!("sig not even: {}", sig.len());
217 }
218
219 let (r_bytes, s_bytes) = sig.split_at(sig.len() / 2);
220 let r = num::BigUint::from_bytes_be(r_bytes);
221 let s = num::BigUint::from_bytes_be(s_bytes);
222
223 let der = yasna::construct_der(|writer| {
224 writer.write_sequence(|writer| {
225 writer.next().write_biguint(&r);
226 writer.next().write_biguint(&s);
227 })
228 });
229
230 Ok(der)
231}
232
233impl<'a> Quote3Signature<'a> for Quote3SignatureEcdsaP256<'a> {
234 fn parse(type_: Quote3AttestationKeyType, mut data: Cow<'a, [u8]>) -> Result<Self> {
235 if type_ != Quote3AttestationKeyType::EcdsaP256 {
236 bail!("Invalid attestation key type: {:?}", type_)
237 }
238
239 let sig_len = data.take_prefix(mem::size_of::<u32>()).map(|v| LE::read_u32(&v))?;
240 if sig_len as usize != data.len() {
241 bail!(
242 "Invalid signature length. Got {}, expected {}",
243 data.len(),
244 sig_len
245 );
246 }
247 let signature = data.take_prefix(ECDSA_P256_SIGNATURE_LEN)?;
248 let attestation_public_key = data.take_prefix(ECDSA_P256_PUBLIC_KEY_LEN)?;
249 let qe3_report = data.take_prefix(REPORT_BODY_LEN)?;
250 let qe3_signature = data.take_prefix(ECDSA_P256_SIGNATURE_LEN)?;
251 let authdata_len = data.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
252 let authentication_data = data.take_prefix(authdata_len as _)?;
253 let cd_type = data.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
254 let certification_data_type = CertificationDataType::from_u16(cd_type)
255 .ok_or_else(|| format_err!("Unknown certification data type: {}", cd_type))?;
256 let certdata_len = data.take_prefix(mem::size_of::<u32>()).map(|v| LE::read_u32(&v))?;
257 if certdata_len as usize != data.len() {
258 bail!(
259 "Invalid certification data length. Got {}, expected {}",
260 data.len(),
261 certdata_len
262 );
263 }
264
265 Ok(Quote3SignatureEcdsaP256 {
266 signature,
267 attestation_public_key,
268 qe3_report,
269 qe3_signature,
270 authentication_data,
271 certification_data_type,
272 certification_data: data,
273 })
274 }
275}
276
277impl<'a> Qe3CertData<'a> for Qe3CertDataPpid<'a> {
278 fn parse(type_: CertificationDataType, mut data: Cow<'a, [u8]>) -> Result<Self> {
279 let ppid_len = match type_ {
280 CertificationDataType::PpidCleartext => bail!(
281 "PPID clear text not implemented. Data length = {}",
282 data.len()
283 ),
284 CertificationDataType::PpidEncryptedRsa2048 => 256,
285 CertificationDataType::PpidEncryptedRsa3072 => 384,
286 _ => bail!("Invalid certification data type: {:?}", type_),
287 };
288
289 let ppid = data.take_prefix(ppid_len)?;
290 let cpusvn = data.take_prefix(CPUSVN_LEN)?;
291 let pcesvn = data.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
292 let pceid = data.take_prefix(mem::size_of::<u16>()).map(|v| LE::read_u16(&v))?;
293 if !data.is_empty() {
294 bail!(
295 "Invalid certification data length for type {:?}: {}",
296 type_,
297 data.len()
298 );
299 }
300
301 Ok(Qe3CertDataPpid {
302 ppid,
303 cpusvn,
304 pcesvn,
305 pceid,
306 })
307 }
308}
309
310impl<'a> Qe3CertData<'a> for RawQe3CertData<'a>{
311 fn parse(_type_: CertificationDataType, data: Cow<'a, [u8]>) -> Result<Self> {
312 Ok(data)
313 }
314}
315
316impl<'a> Qe3CertData<'a> for Qe3CertDataPckCertChain<'a> {
317 fn parse(type_: CertificationDataType, data: Cow<'a, [u8]>) -> Result<Self>{
318 if type_ != CertificationDataType::PckCertificateChain {
319 bail!("Invalid certification data type: {:?}", type_);
320 }
321
322 let mut data = match data {
323 Cow::Borrowed(s) =>
324 std::str::from_utf8(s)
325 .map(Cow::Borrowed)
326 .map_err(|e| format_err!("Invalid certificate format: {}", e))?,
327 Cow::Owned(s) =>
328 String::from_utf8(s)
329 .map(Cow::Owned)
330 .map_err(|e| format_err!("Invalid certificate format: {}", e))?,
331 };
332 let mut certs = vec![];
334 let mark = "-----END CERTIFICATE-----";
335 while let Some(pos) = data.find(mark) {
336 certs.push(data.take_prefix(pos + mark.len()).expect("validated -- pos is always valid"));
337 if let Some(start) = data.find("-") {
338 data.take_prefix(start).unwrap(); }
340 }
341 Ok(Qe3CertDataPckCertChain{
342 certs
343 })
344 }
345}
346
347impl<'a> Quote<'a> {
352 pub fn header(&self) -> &QuoteHeader<'a> {
353 &self.header
354 }
355
356 pub fn report_body(&self) -> &[u8] {
357 &self.report_body
358 }
359
360 pub fn signature<T: Quote3Signature<'a>>(&self) -> Result<T> {
361 let QuoteHeader::V3 {
362 attestation_key_type,
363 ..
364 } = self.header;
365 T::parse(attestation_key_type, self.signature.clone())
366 }
367
368 pub fn clone_owned(&self) -> Quote<'static> {
369 Quote {
370 header: self.header.clone_owned(),
371 report_body: (*self.report_body).to_owned().into(),
372 signature: (*self.signature).to_owned().into(),
373 }
374 }
375}
376
377impl<'a> QuoteHeader<'a> {
378 pub fn clone_owned(&self) -> QuoteHeader<'static> {
379 match *self {
380 QuoteHeader::V3 {
381 attestation_key_type,
382 qe3_svn,
383 pce_svn,
384 ref qe3_vendor_id,
385 ref user_data,
386 } => QuoteHeader::V3 {
387 attestation_key_type,
388 qe3_svn,
389 pce_svn,
390 qe3_vendor_id: (**qe3_vendor_id).to_owned().into(),
391 user_data: (**user_data).to_owned().into(),
392 },
393 }
394 }
395}
396
397impl<'a> Quote3SignatureEcdsaP256<'a> {
398 pub fn signature(&self) -> &[u8] {
399 &self.signature
400 }
401
402 pub fn attestation_public_key(&self) -> &[u8] {
403 &self.attestation_public_key
404 }
405
406 #[cfg(feature = "verify")]
407 fn attestation_pk(&self) -> Result<Pk> {
408 let mut pt = vec![0x4];
409 pt.extend_from_slice(&mut self.attestation_public_key());
410 let group = EcGroup::new(EcGroupId::SecP256R1).map_err(|e| format_err!("Cannot create EcGroup: {}", e))?;
411 let pt = EcPoint::from_binary(&group, &pt).map_err(|e| format_err!("Cannot create point from Quote header: {}", e))?;
412 Pk::public_from_ec_components(group, pt).map_err(|e| format_err!("Cannot create pub key from Quote header: {}", e))
413 }
414
415 pub fn qe3_report(&self) -> &[u8] {
416 &self.qe3_report
417 }
418
419 pub fn qe3_signature(&self) -> &[u8] {
420 &self.qe3_signature
421 }
422
423 pub fn authentication_data(&self) -> &[u8] {
424 &self.authentication_data
425 }
426
427 pub fn certification_data_type(&self) -> CertificationDataType {
428 self.certification_data_type
429 }
430
431 pub fn certification_data<T: Qe3CertData<'a>>(&self) -> Result<T> {
432 T::parse(self.certification_data_type, self.certification_data.clone())
433 }
434
435 pub fn clone_owned(&self) -> Quote3SignatureEcdsaP256<'static> {
436 Quote3SignatureEcdsaP256 {
437 signature: (*self.signature).to_owned().into(),
438 attestation_public_key: (*self.attestation_public_key).to_owned().into(),
439 qe3_report: (*self.qe3_report).to_owned().into(),
440 qe3_signature: (*self.qe3_signature).to_owned().into(),
441 authentication_data: (*self.authentication_data).to_owned().into(),
442 certification_data_type: self.certification_data_type,
443 certification_data: (*self.certification_data).to_owned().into(),
444 }
445 }
446
447 #[cfg(feature = "verify")]
449 pub fn verify_quote_signature(&'a self, quote: &[u8]) -> Result<&'a Self> {
450 let sig = get_ecdsa_sig_der(self.signature())?;
451 let data = "e[0..432]; let mut hash = [0u8; 32];
453 Md::hash(hash::Type::Sha256, &data, &mut hash)?;
454 let mut pk = self.attestation_pk()?;
455 pk.verify(mbedtls::hash::Type::Sha256, &hash, &sig)?;
456
457 Ok(self)
458 }
459
460 #[cfg(feature = "verify")]
461 pub fn verify_qe3_report_signature(&self, pck_pk: &[u8]) -> Result<()> {
462 let sig = get_ecdsa_sig_der(self.qe3_signature())?;
464 let mut hash = [0u8; 32];
465 Md::hash(hash::Type::Sha256, &self.qe3_report(), &mut hash)?;
466 let mut pck_pk = Pk::from_public_key(&pck_pk)?;
467 pck_pk.verify(mbedtls::hash::Type::Sha256, &hash, &sig)?;
468
469 let mut qe3_report = Vec::with_capacity(Report::UNPADDED_SIZE);
471 qe3_report.extend(self.qe3_report());
472 qe3_report.resize_with(Report::UNPADDED_SIZE, Default::default);
473 let qe3_report = Report::try_copy_from(&qe3_report).ok_or(format_err!("Could not construct Qe3 report"))?;
474
475 let mut hash = [0u8; 32];
476 let mut sha256 = Md::new(hash::Type::Sha256)?;
477 sha256.update(self.attestation_public_key())?;
478 sha256.update(self.authentication_data())?;
479 sha256.finish(&mut hash)?;
480
481 if qe3_report.reportdata[0..32] != hash {
482 bail!("Verification of QE3 report data failed");
483 }
484
485 if qe3_report.reportdata[32..64] != [0; 32] {
486 bail!("Verification of QE3 report data failed (second half not 0)");
487 }
488
489 Ok(())
490 }
491}
492
493impl<'a> Qe3CertDataPpid<'a> {
494 pub fn clone_owned(&self) -> Qe3CertDataPpid<'static> {
495 Qe3CertDataPpid {
496 ppid: (*self.ppid).to_owned().into(),
497 cpusvn: (*self.cpusvn).to_owned().into(),
498 pcesvn: self.pcesvn,
499 pceid: self.pceid,
500 }
501 }
502}
503
504#[cfg(feature = "verify")]
505pub trait Quote3SignatureEcdsaP256Verifier {
506 fn verify_certification_data<'a>(&mut self, quote3signature: &'a Quote3SignatureEcdsaP256) -> Result<Vec<u8>>;
514
515 fn verify_qe3(&mut self, qe3_report: &[u8], authentication_data: &[u8]) -> Result<()>;
517}
518
519#[cfg(feature = "verify")]
520pub trait Quote3SignatureVerify<'a>: Quote3Signature<'a> {
521 type TrustRoot;
522
523 fn verify(&self, quote: &[u8], root_of_trust: Self::TrustRoot) -> Result<()>;
524}
525
526#[cfg(feature = "verify")]
527impl<'a> Quote3SignatureVerify<'a> for Quote3SignatureEcdsaP256<'a> {
528 type TrustRoot = &'a mut dyn Quote3SignatureEcdsaP256Verifier;
529
530 fn verify(&self, quote: &[u8], verifier: Self::TrustRoot) -> Result<()> {
531 let pck_pk = verifier.verify_certification_data(self)?;
532 self.verify_qe3_report_signature(&pck_pk)?;
533 verifier.verify_qe3(self.qe3_report(), self.authentication_data())?;
534 self.verify_quote_signature(quote)?;
535 Ok(())
536 }
537}
538
539impl<'a> Quote<'a> {
540 #[cfg(feature = "verify")]
541 pub fn verify<T: Quote3SignatureVerify<'a>>(quote: &'a [u8], root_of_trust: T::TrustRoot) -> Result<Self> {
542 let parsed_quote = Self::parse(quote)?;
543 let sig = parsed_quote.signature::<T>()?;
544 Quote3SignatureVerify::verify(&sig, quote, root_of_trust)?;
545 Ok(parsed_quote)
546 }
547}
548
549#[cfg(test)]
550mod tests {
551 use super::*;
552 #[cfg(feature = "verify")]
553 use mbedtls::x509::certificate::{Certificate};
554 #[cfg(feature = "verify")]
555 use std::ffi::CString;
556 #[cfg(feature = "verify")]
557 use serde::{Deserialize, Serialize};
558
559 #[cfg(feature = "verify")]
560 #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, Copy)]
561 pub enum TcbStatus {
562 UpToDate,
563 SWHardeningNeeded,
564 ConfigurationNeeded,
565 ConfigurationAndSWHardeningNeeded,
566 OutOfDate,
567 OutOfDateConfigurationNeeded,
568 Revoked,
569 }
570
571 #[cfg(feature = "verify")]
572 #[derive(Clone, Serialize, Deserialize, Debug)]
573 struct Tcb {
574 isvsvn: u16,
575 }
576
577 #[cfg(feature = "verify")]
578 #[serde(rename_all = "camelCase")]
579 #[derive(Clone, Serialize, Deserialize, Debug)]
580 pub struct TcbLevel {
581 tcb: Tcb,
582 tcb_date: String,
583 tcb_status: TcbStatus,
584 #[serde(default, rename = "advisoryIDs", skip_serializing_if = "Vec::is_empty")]
585 advisory_ids: Vec<String>,
586 }
587
588 #[cfg(feature = "verify")]
589 #[serde(rename_all = "camelCase")]
590 #[derive(Clone, Serialize, Deserialize, Debug)]
591 pub struct QeIdentity {
592 version: u16,
593 id: String,
594 issue_date: String,
595 next_update: String,
596 tcb_evaluation_data_number: u32,
597 miscselect: String,
598 miscselect_mask: String,
599 attributes: String,
600 attributes_mask: String,
601 mrsigner: String,
602 isvprodid: u16,
603 tcb_levels: Vec<TcbLevel>,
604 }
605
606 #[cfg(feature = "verify")]
607 #[serde(rename_all = "camelCase")]
608 #[derive(Deserialize)]
609 struct QeIdentitySigned {
610 enclave_identity: QeIdentity,
611 _signature: String,
612 }
613
614 #[test]
615 fn test_parse_certdata() {
616 const TEST_QUOTE: &[u8] = &*include_bytes!("../tests/quote_raw_tcb.bin");
617 const QE_ID: [u8; 16] = [
618 0x00, 0xfb, 0xe6, 0x73, 0x33, 0x36, 0xea, 0xf7, 0xa4, 0xe3, 0xd8, 0xb9, 0x66, 0xa8,
619 0x2e, 0x64,
620 ];
621
622 const EXPECTED_PPID: &[u8; 384] = include_bytes!("../tests/encrypted_ppid.bin");
623 const EXPECTED_CPUSVN: [u8; 16] = [
624 0x05, 0x05, 0x02, 0x05, 0xff, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00,
626 ];
627 const EXPECTED_PCESVN: u16 = 6;
628 const EXPECTED_PCEID: u16 = 0;
629
630 let quote = Quote::parse(TEST_QUOTE).unwrap();
631 let &QuoteHeader::V3 {
632 attestation_key_type,
633 ref qe3_vendor_id,
634 ref user_data,
635 ..
636 } = quote.header();
637
638 assert_eq!(qe3_vendor_id, &&QE3_VENDOR_ID_INTEL[..]);
639 let mut ud = QE_ID.to_vec();
640 ud.resize(20usize, 0u8);
641 assert_eq!(user_data, &ud);
642
643 assert_eq!(attestation_key_type, Quote3AttestationKeyType::EcdsaP256);
644 let sig = quote.signature::<Quote3SignatureEcdsaP256>().unwrap();
645
646 assert_eq!(
647 sig.certification_data_type(),
648 CertificationDataType::PpidEncryptedRsa3072
649 );
650 let cd = sig.certification_data::<Qe3CertDataPpid>().unwrap();
651
652 assert_eq!(cd.ppid, &EXPECTED_PPID[..]);
653 assert_eq!(cd.cpusvn, &EXPECTED_CPUSVN[..]);
654 assert_eq!(cd.pcesvn, EXPECTED_PCESVN);
655 assert_eq!(cd.pceid, EXPECTED_PCEID);
656 }
657
658 #[cfg(feature = "verify")]
659 pub struct MyVerifier{
660 qe3_identity: String,
661 }
662
663 #[cfg(feature = "verify")]
664 impl Quote3SignatureEcdsaP256Verifier for MyVerifier {
665 fn verify_certification_data<'a>(&mut self, quote3signature: &'a Quote3SignatureEcdsaP256) -> Result<Vec<u8>> {
666 let certs = quote3signature.certification_data::<Qe3CertDataPckCertChain>().unwrap().certs;
667 let pck = include_str!("../tests/pck_quote.cert");
668 let processor_ca = include_str!("../tests/processor_ca.cert");
669 let root_ca = include_str!("../tests/root_ca.cert");
670 assert_eq!(certs[0], pck.trim());
671 assert_eq!(certs[1], processor_ca.trim());
672 assert_eq!(certs[2], root_ca.trim());
673 assert_eq!(certs.len(), 3);
674
675 let cert_chain = quote3signature.certification_data::<Qe3CertDataPckCertChain>()?;
676 let pck = CString::new(cert_chain.certs[0].as_ref())?;
677 let mut pck = Certificate::from_pem(pck.as_bytes_with_nul())?;
678 Ok(pck.public_key_mut().write_public_der_vec()?)
679 }
680
681 fn verify_qe3(&mut self, qe3_report: &[u8], authentication_data: &[u8]) -> Result<()> {
683 assert_eq!(authentication_data,(0..=31).collect::<Vec<u8>>().as_slice());
684
685 let mut report = Vec::with_capacity(Report::UNPADDED_SIZE);
686 report.extend(qe3_report);
687 report.resize_with(Report::UNPADDED_SIZE, Default::default);
688 let report = Report::try_copy_from(&report).ok_or(format_err!("Could not construct Qe3 report"))?;
689
690 let qe3_identity: QeIdentitySigned = serde_json::from_str(&self.qe3_identity).unwrap();
691 if let Some(tcb_level) = qe3_identity.enclave_identity.tcb_levels.iter().find(|level| level.tcb.isvsvn == report.isvsvn) {
692 if tcb_level.tcb_status == TcbStatus::UpToDate {
693 return Ok(())
695 }
696 }
697
698 Err(format_err!("QE3 out of date"))
699 }
700 }
701
702 #[test]
703 fn test_quote_verification() {
704 const TEST_QUOTE: &[u8] = &*include_bytes!("../tests/quote_pck_cert_chain.bin");
705 let quote = Quote::parse(TEST_QUOTE).unwrap();
706 let &QuoteHeader::V3 {
707 attestation_key_type,
708 ref qe3_vendor_id,
709 ..
710 } = quote.header();
711
712 assert_eq!(qe3_vendor_id, &&QE3_VENDOR_ID_INTEL[..]);
713
714 assert_eq!(attestation_key_type, Quote3AttestationKeyType::EcdsaP256);
715
716 #[cfg(feature = "verify")]
717 let mut verifier = MyVerifier {
718 qe3_identity: include_str!("../tests/corrupt_qe3_identity.json").to_string(),
724 };
725 #[cfg(feature = "verify")]
726 assert!(Quote::verify::<Quote3SignatureEcdsaP256>(TEST_QUOTE, &mut verifier).is_ok())
727 }
728
729 #[test]
730 fn test_quote_verification_qe3_out_of_date() {
731 const TEST_QUOTE: &[u8] = &*include_bytes!("../tests/quote_pck_cert_chain.bin");
732 let quote = Quote::parse(TEST_QUOTE).unwrap();
733 let &QuoteHeader::V3 {
734 attestation_key_type,
735 ref qe3_vendor_id,
736 ..
737 } = quote.header();
738
739 assert_eq!(qe3_vendor_id, &&QE3_VENDOR_ID_INTEL[..]);
740
741 assert_eq!(attestation_key_type, Quote3AttestationKeyType::EcdsaP256);
742
743 #[cfg(feature = "verify")]
744 let mut verifier = MyVerifier {
745 qe3_identity: include_str!("../tests/qe3_identity.json").to_string(),
746 };
747 #[cfg(feature = "verify")]
748 assert!(Quote::verify::<Quote3SignatureEcdsaP256>(TEST_QUOTE, &mut verifier).is_err())
749 }
750
751 #[test]
752 fn test_corrupt_quote_verification() {
753 const TEST_QUOTE: &[u8] = &*include_bytes!("../tests/quote_pck_cert_chain_corrupted.bin");
754 let quote = Quote::parse(TEST_QUOTE).unwrap();
755 let &QuoteHeader::V3 {
756 attestation_key_type,
757 ref qe3_vendor_id,
758 ..
759 } = quote.header();
760
761 assert_eq!(qe3_vendor_id, &&QE3_VENDOR_ID_INTEL[..]);
762
763 assert_eq!(attestation_key_type, Quote3AttestationKeyType::EcdsaP256);
764
765 #[cfg(feature = "verify")]
766 let mut verifier = MyVerifier {
767 qe3_identity: include_str!("../tests/corrupt_qe3_identity.json").to_string(),
773 };
774 #[cfg(feature = "verify")]
775 assert!(Quote::verify::<Quote3SignatureEcdsaP256>(TEST_QUOTE, &mut verifier).is_err());
776 }
777}