1use std::path::PathBuf;
9
10use pkix::pem::PEM_CRL;
11use serde::{Deserialize, Deserializer, Serialize};
12use std::marker::PhantomData;
13#[cfg(feature = "verify")]
14use {
15 mbedtls::alloc::List as MbedtlsList,
16 mbedtls::x509::{Certificate, Crl},
17 std::convert::TryFrom,
18 std::ffi::CString,
19 std::ops::Deref,
20};
21
22use crate::io::{self};
23use crate::{DcapArtifactIssuer, Error, Unverified, VerificationType, Verified};
24
25#[derive(Clone, Serialize, Debug, Eq, PartialEq)]
26pub struct PckCrl<V: VerificationType = Verified> {
27 crl: String,
28 ca_chain: Vec<String>,
29 #[serde(skip)]
30 type_: PhantomData<V>,
31}
32
33impl<'de> Deserialize<'de> for PckCrl<Unverified> {
34 fn deserialize<D>(deserializer: D) -> Result<PckCrl<Unverified>, D::Error>
35 where
36 D: Deserializer<'de>,
37 {
38 #[derive(Deserialize)]
39 struct Dummy {
40 crl: String,
41 ca_chain: Vec<String>,
42 }
43
44 let Dummy { crl, ca_chain } = Dummy::deserialize(deserializer)?;
45 Ok(PckCrl::<Unverified> {
46 crl,
47 ca_chain,
48 type_: PhantomData,
49 })
50 }
51}
52
53impl PckCrl<Unverified> {
54 pub fn new(crl: String, ca_chain: Vec<String>) -> Result<PckCrl<Unverified>, Error> {
55 let crl = PckCrl { crl, ca_chain, type_: PhantomData };
56
57 Ok(crl)
58 }
59
60 #[cfg(feature = "verify")]
61 pub fn verify<B: Deref<Target = [u8]>>(self, trusted_root_certs: &[B]) -> Result<PckCrl<Verified>, Error> {
62 let (chain, root) = crate::create_cert_chain(&self.ca_chain)?;
64 let chain: MbedtlsList<Certificate> = chain.into_iter().collect();
65 let root = std::iter::once(root).collect();
66 let mut err = String::default();
67 Certificate::verify(&chain, &root, None, Some(&mut err))
68 .map_err(|e| Error::InvalidCrl(e))?;
69
70 crate::check_root_ca(trusted_root_certs, &root)?;
72
73 let crl = self.as_mbedtls_crl()?;
75 let crl_signature = crl.signature()
76 .map_err(|e| Error::InvalidCrl(e))?;
77 let crl_tbs = crl.tbs_raw()
78 .map_err(|e| Error::InvalidCrl(e))?;
79 let mut hash = [0u8; 32];
80 mbedtls::hash::Md::hash(mbedtls::hash::Type::Sha256, &crl_tbs, &mut hash).unwrap();
81
82 let pck_ca = self.ca_chain.first()
83 .ok_or(Error::InvalidPck("Pck CRL doesn't have a CA".into()))?;
84 let pck_ca = CString::new(pck_ca.as_bytes()).map_err(|_| Error::InvalidCaFormat)?;
85 let mut pck_ca = Certificate::from_pem(pck_ca.as_bytes_with_nul()).map_err(|_| Error::InvalidCaFormat)?;
86 let pck_ca = pck_ca.public_key_mut();
87 pck_ca
88 .verify(mbedtls::hash::Type::Sha256, &hash, &crl_signature)
89 .map_err(|e| Error::InvalidCrl(e))?;
90
91 self.ca()?;
93
94 let PckCrl { crl, ca_chain, .. } = self;
95 Ok(PckCrl::<Verified>{ crl, ca_chain, type_: PhantomData})
96 }
97
98 pub fn read_from_file(input_dir: &str, ca: DcapArtifactIssuer) -> Result<Self, Error> {
99 let filename = Self::filename_from_ca(ca);
100 let crl: Self = io::read_from_file(input_dir, &filename)?;
101 Ok(crl)
102 }
103}
104
105impl<V: VerificationType> PckCrl<V> {
106 fn filename_from_ca(ca: DcapArtifactIssuer) -> String {
107 match ca {
108 DcapArtifactIssuer::PCKProcessorCA => String::from("processor.crl"),
109 DcapArtifactIssuer::PCKPlatformCA => String::from("platform.crl"),
110 DcapArtifactIssuer::SGXRootCA => String::from("root.crl"),
111 }
112 }
113
114 #[cfg(feature = "verify")]
115 pub fn filename(&self) -> Result<String, Error> {
116 Ok(Self::filename_from_ca(self.ca()?))
117 }
118
119 #[cfg(feature = "verify")]
120 pub fn write_to_file(&self, output_dir: &str) -> Result<String, Error> {
121 let filename = self.filename()?;
122 io::write_to_file(&self, output_dir, &filename)?;
123 Ok(filename)
124 }
125
126 pub fn write_to_file_as(&self, output_dir: &str, ca: DcapArtifactIssuer) -> Result<String, Error> {
127 let filename = Self::filename_from_ca(ca);
128 io::write_to_file(&self, output_dir, &filename)?;
129 Ok(filename)
130 }
131
132 #[cfg(feature = "verify")]
133 pub fn write_to_file_if_not_exist(&self, output_dir: &str) -> Result<Option<PathBuf>, Error> {
134 let filename = self.filename()?;
135 io::write_to_file_if_not_exist(&self, output_dir, &filename)
136 }
137
138 pub fn write_to_file_if_not_exist_as(&self, output_dir: &str, ca: DcapArtifactIssuer) -> Result<Option<PathBuf>, Error> {
139 let filename = Self::filename_from_ca(ca);
140 io::write_to_file_if_not_exist(&self, output_dir, &filename)
141 }
142
143 pub fn crl_as_pem(&self) -> &String {
144 &self.crl
145 }
146
147 pub fn crl_as_der(&self) -> Result<Vec<u8>, Error> {
148 pkix::pem::pem_to_der(&self.crl, Some(PEM_CRL)).ok_or(Error::InvalidCrlFormat)
149 }
150
151 pub fn certificate_chain(&self) -> &Vec<String> {
152 &self.ca_chain
153 }
154
155 #[cfg(feature = "verify")]
156 pub(crate) fn as_mbedtls_crl(&self) -> Result<Crl, Error> {
157 let c = CString::new(self.crl.as_bytes()).map_err(|_| Error::InvalidCrlFormat)?;
158 let mut crl = Crl::new();
159 crl.push_from_pem(c.as_bytes_with_nul()).map_err(|_| Error::InvalidCrlFormat)?;
160 Ok(crl)
161 }
162
163 #[cfg(feature = "verify")]
164 fn ca(&self) -> Result<DcapArtifactIssuer, Error> {
165 let issuer = self
166 .as_mbedtls_crl()
167 .and_then(|crl| crl.issuer().map_err(|_| Error::InvalidCrlFormat))?;
168 let issuer = DcapArtifactIssuer::try_from(issuer.as_str())?;
169
170 if let DcapArtifactIssuer::SGXRootCA = issuer {
171 return Err(Error::InvalidCrlFormat);
173 }
174 Ok(issuer)
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 #[cfg(all(not(target_env = "sgx"), feature = "verify"))]
181 use {
182 super::PckCrl,
183 crate::DcapArtifactIssuer,
184 };
185
186 #[cfg(all(not(target_env = "sgx"), feature = "verify"))]
187 #[test]
188 fn read_pck_crl() {
189 let crl = PckCrl::read_from_file("./tests/data/", DcapArtifactIssuer::PCKProcessorCA).unwrap();
190 assert_eq!(crl.ca().unwrap(), DcapArtifactIssuer::PCKProcessorCA);
191 let root_ca = include_bytes!("../tests/data/root_SGX_CA_der.cert");
192 let root_cas = [&root_ca[..]];
193 crl.verify(&root_cas).unwrap();
194 }
195
196 #[cfg(all(not(target_env = "sgx"), feature = "verify"))]
197 #[test]
198 fn read_platform_pck_crl() {
199 let pckcrl = PckCrl::read_from_file("./tests/data/", DcapArtifactIssuer::PCKPlatformCA).unwrap();
200 let root_ca = include_bytes!("../tests/data/root_SGX_CA_der.cert");
201 let root_cas = [&root_ca[..]];
202 pckcrl.clone().verify(&root_cas).unwrap();
203 assert_eq!(pckcrl.ca().unwrap(), DcapArtifactIssuer::PCKPlatformCA);
204 }
205}