pcs/
qe_identity.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8use 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    /// Returns the most recent TCB level matching the isvsvn
194    pub fn find_tcb_level<'a>(&'a self, isvsvn: u16) -> Option<&'a TcbLevel> {
195        // Note: tcb levels are ordered in descending order
196        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        // check cert chain
382        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        // Check signature on data
391        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        // Check common name TCB cert
398        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}