1use std::convert::{TryFrom, TryInto};
9use std::fmt::{self, Display, Formatter};
10use std::marker::PhantomData;
11use std::path::PathBuf;
12
13use chrono::{DateTime, Utc};
14use serde::{de, Deserialize, Deserializer, Serialize};
15use serde_json::value::RawValue;
16use sgx_isa::{Attributes, Miscselect};
17#[cfg(feature = "verify")]
18use {
19 mbedtls::alloc::List as MbedtlsList, mbedtls::x509::certificate::Certificate, mbedtls::error::{codes, Error as ErrMbed}, pkix::oid,
20 pkix::pem::PEM_CERTIFICATE, pkix::x509::GenericCertificate, pkix::FromBer, std::ops::Deref,
21};
22
23use crate::io::{self};
24use crate::{Error, TcbStatus, Unverified, VerificationType, Verified};
25
26#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
27pub enum EnclaveIdentity {
28 QE,
29 QVE,
30 QAE,
31 TDQE,
32}
33
34mod enclave_identity {
35 use serde::{Deserialize, Deserializer};
36 use serde::de;
37 use super::EnclaveIdentity;
38
39 pub fn serialize<S>(id: &EnclaveIdentity, serializer: S) -> Result<S::Ok, S::Error>
40 where
41 S: ::serde::Serializer,
42 {
43 let s = match id {
44 EnclaveIdentity::QE => "QE",
45 EnclaveIdentity::QVE => "QVE",
46 EnclaveIdentity::QAE => "QAE",
47 EnclaveIdentity::TDQE => "TD_QE",
48 };
49 serializer.serialize_str(&s)
50 }
51
52 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<EnclaveIdentity, D::Error> {
53 let id = String::deserialize(deserializer)?;
54 match id.as_str() {
55 "QE" => Ok(EnclaveIdentity::QE),
56 "QVE" => Ok(EnclaveIdentity::QVE),
57 "QAE" => Ok(EnclaveIdentity::QAE),
58 "TD_QE" => Ok(EnclaveIdentity::TDQE),
59 _ => Err(de::Error::custom("Unknown Enclave Identity variant"))
60 }
61 }
62}
63
64impl Display for EnclaveIdentity {
65 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
66 match self {
67 EnclaveIdentity::QE => write!(f, "QE"),
68 EnclaveIdentity::QVE => write!(f, "QVE"),
69 EnclaveIdentity::QAE => write!(f, "QAE"),
70 EnclaveIdentity::TDQE => write!(f, "TD_QE"),
71 }
72 }
73}
74
75#[derive(Clone, Serialize, Deserialize, Debug)]
76pub(crate) struct Tcb {
77 pub(crate) isvsvn: u16,
78}
79
80#[derive(Clone, Serialize, Deserialize, Debug)]
81#[serde(rename_all = "camelCase")]
82pub struct TcbLevel {
83 pub(crate) tcb: Tcb,
84 tcb_date: String,
85 pub(crate) tcb_status: TcbStatus,
86 #[serde(default, rename = "advisoryIDs", skip_serializing_if = "Vec::is_empty")]
87 advisory_ids: Vec<String>,
88}
89
90impl TcbLevel {
91 pub fn tcb_status(&self) -> &TcbStatus {
92 &self.tcb_status
93 }
94}
95
96#[derive(Clone, Serialize, Debug)]
97#[serde(rename_all = "camelCase")]
98pub struct QeIdentity<V: VerificationType = Verified> {
99 version: u16,
100 #[serde(with = "enclave_identity")]
101 id: EnclaveIdentity,
102 #[serde(with = "crate::iso8601")]
103 issue_date: DateTime<Utc>,
104 #[serde(with = "crate::iso8601")]
105 next_update: DateTime<Utc>,
106 tcb_evaluation_data_number: u64,
107 #[serde(deserialize_with = "miscselect_deserializer", serialize_with = "miscselect_serializer")]
108 miscselect: Miscselect,
109 #[serde(
110 deserialize_with = "miscselect_mask_deserializer",
111 serialize_with = "miscselect_mask_serializer"
112 )]
113 miscselect_mask: u32,
114 #[serde(deserialize_with = "attributes_deserializer", serialize_with = "attributes_serializer")]
115 attributes: Attributes,
116 #[serde(deserialize_with = "attributes_deserializer", serialize_with = "attributes_serializer")]
117 attributes_mask: Attributes,
118 #[serde(deserialize_with = "mrsigner_deserializer", serialize_with = "mrsigner_serializer")]
119 mrsigner: [u8; 32],
120 isvprodid: u16,
121 tcb_levels: Vec<TcbLevel>,
122 #[serde(skip)]
123 type_: PhantomData<V>,
124}
125
126impl<'de> Deserialize<'de> for QeIdentity<Unverified> {
127 fn deserialize<D>(deserializer: D) -> Result<QeIdentity<Unverified>, D::Error>
128 where
129 D: Deserializer<'de>,
130 {
131 #[derive(Deserialize)]
132 #[serde(rename_all = "camelCase")]
133 struct Dummy {
134 version: u16,
135 #[serde(with = "enclave_identity")]
136 id: EnclaveIdentity,
137 #[serde(with = "crate::iso8601")]
138 issue_date: DateTime<Utc>,
139 #[serde(with = "crate::iso8601")]
140 next_update: DateTime<Utc>,
141 tcb_evaluation_data_number: u64,
142 #[serde(deserialize_with = "miscselect_deserializer", serialize_with = "miscselect_serializer")]
143 miscselect: Miscselect,
144 #[serde(
145 deserialize_with = "miscselect_mask_deserializer",
146 serialize_with = "miscselect_mask_serializer"
147 )]
148 miscselect_mask: u32,
149 #[serde(deserialize_with = "attributes_deserializer", serialize_with = "attributes_serializer")]
150 attributes: Attributes,
151 #[serde(deserialize_with = "attributes_deserializer", serialize_with = "attributes_serializer")]
152 attributes_mask: Attributes,
153 #[serde(deserialize_with = "mrsigner_deserializer", serialize_with = "mrsigner_serializer")]
154 mrsigner: [u8; 32],
155 isvprodid: u16,
156 tcb_levels: Vec<TcbLevel>,
157 }
158
159 let Dummy {
160 version,
161 id,
162 issue_date,
163 next_update,
164 tcb_evaluation_data_number,
165 miscselect,
166 miscselect_mask,
167 attributes,
168 attributes_mask,
169 mrsigner,
170 isvprodid,
171 tcb_levels,
172 } = Dummy::deserialize(deserializer)?;
173
174 Ok(QeIdentity::<Unverified> {
175 version,
176 id,
177 issue_date,
178 next_update,
179 tcb_evaluation_data_number,
180 miscselect,
181 miscselect_mask,
182 attributes,
183 attributes_mask,
184 mrsigner,
185 isvprodid,
186 tcb_levels,
187 type_: PhantomData,
188 })
189 }
190}
191
192impl QeIdentity {
193 pub fn find_tcb_level<'a>(&'a self, isvsvn: u16) -> Option<&'a TcbLevel> {
195 for tcb in self.tcb_levels.iter() {
197 if tcb.tcb.isvsvn <= isvsvn {
198 return Some(tcb);
199 }
200 }
201 None
202 }
203
204 pub fn mrsigner(&self) -> &[u8; 32] {
205 &self.mrsigner
206 }
207
208 pub fn isvprodid(&self) -> u16 {
209 self.isvprodid
210 }
211
212 pub fn attributes<'a>(&'a self) -> &'a Attributes {
213 &self.attributes
214 }
215
216 pub fn attributes_mask<'a>(&'a self) -> &'a Attributes {
217 &self.attributes_mask
218 }
219
220 pub fn miscselect<'a>(&'a self) -> &'a Miscselect {
221 &self.miscselect
222 }
223
224 pub fn miscselect_mask(&self) -> Miscselect {
225 Miscselect::from_bits_truncate(self.miscselect_mask)
226 }
227}
228
229impl<V: VerificationType> QeIdentity<V> {
230 pub fn tcb_evaluation_data_number(&self) -> u64 {
231 self.tcb_evaluation_data_number
232 }
233
234 pub(crate) fn tcb_levels(&self) -> &[TcbLevel] {
235 &self.tcb_levels
236 }
237}
238
239impl TryFrom<&QeIdentitySigned> for QeIdentity<Unverified> {
240 type Error = Error;
241
242 fn try_from(id: &QeIdentitySigned) -> Result<Self, Self::Error> {
243 serde_json::from_str(&id.raw_enclave_identity).map_err(|e| Error::ParseError(e))
244 }
245}
246
247fn mrsigner_deserializer<'de, D: Deserializer<'de>>(deserializer: D) -> Result<[u8; 32], D::Error> {
248 let mrsigner = String::deserialize(deserializer)?;
249 let mrsigner = base16::decode(&mrsigner).map_err(de::Error::custom)?;
250 mrsigner.as_slice().try_into().map_err(de::Error::custom)
251}
252
253fn mrsigner_serializer<S>(mrsigner: &[u8; 32], serializer: S) -> ::std::result::Result<S::Ok, S::Error>
254where
255 S: ::serde::Serializer,
256{
257 let mrsigner = base16::encode_upper(mrsigner);
258 serializer.serialize_str(&mrsigner)
259}
260
261fn attributes_deserializer<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Attributes, D::Error> {
262 let attributes = String::deserialize(deserializer)?;
263 let attributes = base16::decode(&attributes).map_err(de::Error::custom)?;
264 Attributes::try_copy_from(&attributes).ok_or_else(|| de::Error::custom("Could not parse attribtes"))
265}
266
267fn attributes_serializer<S>(attributes: &Attributes, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
268where
269 S: ::serde::Serializer,
270{
271 let attributes: &[u8] = attributes.as_ref();
272 let attributes = base16::encode_upper(&attributes);
273 serializer.serialize_str(&attributes)
274}
275
276fn miscselect_deserializer<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Miscselect, D::Error> {
277 let miscselect = String::deserialize(deserializer)?;
278 let miscselect = u32::from_str_radix(&miscselect, 16).map_err(de::Error::custom)?;
279 Miscselect::from_bits(miscselect).ok_or_else(|| de::Error::custom("Could not parse miscselect"))
280}
281
282fn miscselect_serializer<S>(miscselect: &Miscselect, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
283where
284 S: ::serde::Serializer,
285{
286 let miscselect = miscselect.bits();
287 let miscselect = base16::encode_upper(&miscselect.to_be_bytes());
288 serializer.serialize_str(&miscselect)
289}
290
291fn miscselect_mask_deserializer<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D::Error> {
292 let miscselect = String::deserialize(deserializer)?;
293 u32::from_str_radix(&miscselect, 16).map_err(de::Error::custom)
294}
295
296fn miscselect_mask_serializer<S>(miscselect: &u32, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
297where
298 S: ::serde::Serializer,
299{
300 let miscselect = base16::encode_upper(&miscselect.to_be_bytes());
301 serializer.serialize_str(&miscselect)
302}
303
304#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
305pub struct QeIdentitySigned {
306 raw_enclave_identity: String,
307 signature: Vec<u8>,
308 ca_chain: Vec<String>,
309}
310
311impl QeIdentitySigned {
312 const FILENAME_PREFIX: &'static str = "qe3_identity";
313 const FILENAME_EXTENSION: &'static str = ".id";
314
315 pub fn parse(body: &String, ca_chain: Vec<String>) -> Result<Self, Error> {
316 #[derive(Deserialize)]
317 #[serde(rename_all = "camelCase")]
318 struct IntelQeIdentitySigned<'a> {
319 #[serde(borrow)]
320 enclave_identity: &'a RawValue,
321 #[serde(deserialize_with = "crate::intel_signature_deserializer")]
322 signature: Vec<u8>,
323 }
324 let IntelQeIdentitySigned {
325 enclave_identity,
326 signature,
327 } = serde_json::from_str(&body)?;
328 Ok(QeIdentitySigned::new(enclave_identity.to_string(), signature, ca_chain))
329 }
330
331 pub fn new(raw_enclave_identity: String, signature: Vec<u8>, ca_chain: Vec<String>) -> Self {
332 QeIdentitySigned {
333 raw_enclave_identity,
334 signature,
335 ca_chain,
336 }
337 }
338
339 pub fn create_filename(evaluation_data_number: Option<u64>) -> String {
340 io::compose_filename(Self::FILENAME_PREFIX, Self::FILENAME_EXTENSION, evaluation_data_number)
341 }
342
343 pub fn write_to_file(&self, output_dir: &str) -> Result<String, Error> {
344 let id = QeIdentity::<Unverified>::try_from(self)?;
345 let filename = Self::create_filename(Some(id.tcb_evaluation_data_number));
346 io::write_to_file(&self, output_dir, &filename)?;
347 Ok(filename)
348 }
349
350 pub fn write_to_file_if_not_exist(&self, output_dir: &str) -> Result<Option<PathBuf>, Error> {
351 let id = QeIdentity::<Unverified>::try_from(self)?;
352 let filename = Self::create_filename(Some(id.tcb_evaluation_data_number));
353 io::write_to_file_if_not_exist(&self, output_dir, &filename)
354 }
355
356 pub fn read_from_file(input_dir: &str, evaluation_data_number: Option<u64>) -> Result<Self, Error> {
357 let filename = Self::create_filename(evaluation_data_number);
358 let identity: Self = io::read_from_file(input_dir, &filename)?;
359 Ok(identity)
360 }
361
362 pub fn read_all<'a>(input_dir: &'a str) -> impl Iterator<Item = Result<Self, Error>> + 'a {
363 io::all_files(input_dir, Self::FILENAME_PREFIX, Self::FILENAME_EXTENSION)
364 .map(move |i| i.and_then(|entry| io::read_from_file(input_dir, entry.file_name())) )
365 }
366
367 pub fn raw_qe_identity(&self) -> &String {
368 &self.raw_enclave_identity
369 }
370
371 pub fn signature(&self) -> &Vec<u8> {
372 &self.signature
373 }
374
375 pub fn certificate_chain(&self) -> &Vec<String> {
376 &self.ca_chain
377 }
378
379 #[cfg(feature = "verify")]
380 pub fn verify<B: Deref<Target = [u8]>>(&self, trusted_root_certs: &[B], enclave_identity: EnclaveIdentity) -> Result<QeIdentity, Error> {
381 let (chain, root) = crate::create_cert_chain(&self.ca_chain)?;
383 let mut leaf = chain.first().unwrap_or(&root).clone();
384 let root_list = std::iter::once(root).collect();
385 if 0 < chain.len() {
386 let trust_ca: MbedtlsList<Certificate> = chain.into_iter().collect();
387 Certificate::verify(&trust_ca, &root_list, None, None).map_err(|e| Error::InvalidQe3Id(e))?;
388 }
389
390 let mut hash = [0u8; 32];
392 mbedtls::hash::Md::hash(mbedtls::hash::Type::Sha256, self.raw_enclave_identity.as_bytes(), &mut hash).unwrap();
393 leaf.public_key_mut()
394 .verify(mbedtls::hash::Type::Sha256, &hash, &self.signature)
395 .map_err(|e| Error::InvalidQe3Id(e))?;
396
397 let leaf = self.ca_chain.first().ok_or(Error::IncorrectCA)?;
399 let tcb =
400 &pkix::pem::pem_to_der(&leaf, Some(PEM_CERTIFICATE)).ok_or(Error::InvalidQe3Id(ErrMbed::HighLevel(codes::X509BadInputData)))?;
401 let tcb = GenericCertificate::from_ber(&tcb).map_err(|_| Error::InvalidQe3Id(ErrMbed::HighLevel(codes::X509BadInputData)))?;
402 let name = tcb
403 .tbscert
404 .subject
405 .get(&*oid::commonName)
406 .ok_or(Error::InvalidQe3Id(ErrMbed::HighLevel(codes::X509BadInputData)))?;
407 if String::from_utf8_lossy(&name.value()) != "Intel SGX TCB Signing" {
408 return Err(Error::IncorrectCA);
409 }
410
411 crate::check_root_ca(trusted_root_certs, &root_list)?;
412
413 let QeIdentity::<Unverified> {
414 version,
415 id,
416 issue_date,
417 next_update,
418 tcb_evaluation_data_number,
419 miscselect,
420 miscselect_mask,
421 attributes,
422 attributes_mask,
423 mrsigner,
424 isvprodid,
425 tcb_levels,
426 type_: PhantomData,
427 } = serde_json::from_str(&self.raw_enclave_identity).map_err(|e| Error::ParseError(e))?;
428
429 if version != 2 {
430 return Err(Error::UnknownQeIdentityVersion(version));
431 }
432
433 if id != enclave_identity {
434 return Err(Error::Qe3NotValid(format!("QE identity {enclave_identity} expected, got {id}")))
435 }
436
437 let now = Utc::now();
438 if now < issue_date {
439 return Err(Error::Qe3NotValid(format!("QE3 only valid from {}", issue_date)))
440 }
441
442 if next_update < now {
443 return Err(Error::Qe3NotValid(format!("QE3 expired on {}", next_update)))
444 }
445
446 Ok(QeIdentity::<Verified> {
447 version,
448 id,
449 issue_date,
450 next_update,
451 tcb_evaluation_data_number,
452 miscselect,
453 miscselect_mask,
454 attributes,
455 attributes_mask,
456 mrsigner,
457 isvprodid,
458 tcb_levels,
459 type_: PhantomData,
460 })
461 }
462}
463
464#[cfg(feature = "verify")]
465#[cfg(test)]
466mod tests {
467 #[cfg(not(target_env = "sgx"))]
468 use {
469 crate::qe_identity::{QeIdentitySigned, EnclaveIdentity},
470 crate::Error,
471 };
472
473 #[test]
474 #[cfg(not(target_env = "sgx"))]
475 fn read_qe3_identity() {
476 let qe_id = QeIdentitySigned::read_from_file("./tests/data/", None).expect("validated");
477
478 let root_cert = include_bytes!("../tests/data/root_SGX_CA_der.cert");
479 let root_certs = [&root_cert[..]];
480 match qe_id.verify(&root_certs, EnclaveIdentity::QE) {
481 Err(Error::Qe3NotValid(msg)) => assert_eq!(msg, "QE3 expired on 2020-06-17 17:49:21 UTC"),
482 e => assert!(false, "wrong result: {:?}", e),
483 }
484
485 match qe_id.verify(&root_certs, EnclaveIdentity::TDQE) {
486 Err(Error::Qe3NotValid(msg)) => assert_eq!(msg, "QE identity TD_QE expected, got QE"),
487 e => assert!(false, "wrong result: {:?}", e),
488 }
489 }
490
491 #[test]
492 #[cfg(not(target_env = "sgx"))]
493 fn read_corrupted_qe3_identity() {
494 let qeid = QeIdentitySigned::read_from_file("./tests/data/corrupted/", None).unwrap();
495
496 let root_cert = include_bytes!("../tests/data/root_SGX_CA_der.cert");
497 let root_certs = [&root_cert[..]];
498 assert!(qeid.verify(&root_certs, EnclaveIdentity::QE).is_err());
499 }
500}