1#![deny(warnings)]
9
10extern crate percent_encoding;
11extern crate yasna;
12#[macro_use]
13extern crate quick_error;
14
15use std::convert::TryFrom;
16use std::fmt::{self};
17
18use serde::de::{self};
19use serde::{Deserialize, Deserializer, Serialize};
20pub use yasna::ASN1Error;
21#[cfg(feature = "verify")]
22use {
23 mbedtls::Error as MbedError,
24 mbedtls::alloc::{Box as MbedtlsBox, List as MbedtlsList},
25 mbedtls::x509::certificate::Certificate,
26 std::ffi::CString,
27 std::ops::Deref,
28};
29
30pub use crate::pckcrl::PckCrl;
31pub use crate::pckcrt::{PckCert, PckCerts, SGXPCKCertificateExtension, SGXType, TcbComponentType};
32pub use crate::qe_identity::{EnclaveIdentity, QeIdentity, QeIdentitySigned};
33pub use crate::tcb_info::{AdvisoryID, Fmspc, TcbInfo, TcbData, TcbLevel, TdxModule, TdxModuleIdentity, TdxModuleTcbLevel, TdxModuleTcbLevelIsvSvn, PlatformTypeForTcbInfo};
34pub use crate::tcb_evaluation_data_numbers::{RawTcbEvaluationDataNumbers, TcbEvalNumber, TcbEvaluationDataNumbers, TcbPolicy};
35pub use crate::io::{WriteOptions, WriteOptionsBuilder};
36
37mod io;
38mod iso8601;
39mod pckcrl;
40mod pckcrt;
41mod pckid;
42mod qe_identity;
43mod tcb_info;
44mod tcb_evaluation_data_numbers;
45
46pub type CpuSvn = [u8; 16];
47pub type EncPpid = Vec<u8>;
48pub type PceId = u16;
49pub type PceIsvsvn = u16;
50pub type QeId = [u8; 16];
51pub use crate::pckid::PckID;
52
53pub trait PlatformType : Clone + Default {
55 fn platform_id() -> &'static str;
56}
57
58pub fn deserialize_platform_id<'de, D: Deserializer<'de>, T: PlatformType>(deserializer: D) -> Result<T, D::Error> {
60 let platform_str = String::deserialize(deserializer)?;
61 if platform_str == T::platform_id() {
62 Ok(T::default())
63 } else {
64 Err(serde::de::Error::custom(format!("invalid platform id: {platform_str}, expected {}", T::platform_id())))
65 }
66}
67
68pub mod platform {
70 use serde::{Serialize, Deserialize};
71
72 #[derive(Serialize, Deserialize, Clone, Default, Eq, PartialEq, Debug)]
74 pub struct SGX;
75
76 impl super::PlatformType for SGX {
77 fn platform_id() -> &'static str {
78 "SGX"
79 }
80 }
81
82 #[derive(Serialize, Deserialize, Clone, Default, Eq, PartialEq, Debug)]
84 pub struct TDX;
85
86 impl super::PlatformType for TDX {
87 fn platform_id() -> &'static str {
88 "TDX"
89 }
90 }
91}
92
93quick_error! {
94 #[derive(Debug)]
95 pub enum Error {
96 MissingCaChain{
97 display("CA chain was unexpectedly empty")
98 }
99 IncorrectCA {
100 display("Invalid CA")
101 }
102 InvalidCaFormat {
103 display("CA certificate could not be parsed")
104 }
105 InvalidPckFormat(err: ASN1Error){
106 display("Invalid formatted PckCert: {}", err)
107 }
108 InvalidPck(err: String){
109 display("Invalid PCK: {}", err)
110 }
111 InvalidPcks(err: String){
112 display("Invalid PCKs: {}", err)
113 }
114 InvalidFormatQe3Quote{
115 display("Qe3 Quote could not be parsed")
116 }
117 NoPckForTcbFound{
118 display("No PCK matching the TCB was found")
119 }
120 #[cfg(feature = "verify")]
121 InvalidCrl(err: MbedError){
122 display("Invalid CRL: {}", err)
123 }
124 InvalidCrlFormat{
125 display("Invalid CRL format")
126 }
127 InvalidTcbInfo(err: String){
128 display("Invalid TCB info: {}", err)
129 }
130 InvalidTcbEvaluationDataNumbers(err: String){
131 display("Invalid TCB Evaluation Data Numbers: {}", err)
132 }
133 #[cfg(feature = "verify")]
134 UntrustworthyTcbEvaluationDataNumber(err: MbedError) {
135 display("TCB Evaluation Data Number not trustworthy: {}", err)
136 }
137 UnknownTcbType(tcb_type: u16){
138 display("Unknown TCB type: {}", tcb_type)
139 }
140 #[cfg(feature = "verify")]
141 InvalidQe3Id(err: MbedError){
142 display("Invalid QE3 ID: {}", err)
143 }
144 Qe3NotValid(err: String){
145 display("Invalid QE3: {}", err)
146 }
147 InvalidFormatQe3Identity{
148 display("Invalid QE3 Identity format")
149 }
150 IoError(err: std::io::Error){
151 display("I/O error: {}", err)
152 from()
153 }
154 ParseError(err: serde_json::error::Error){
155 from()
156 display("json error: {}", err)
157 }
158 NoPckCertData{
159 display("Empty PckCerts")
160 }
161 EncodingError(err: serde_json::error::Error){
162 display("json error: {}", err)
163 }
164 UnknownTcbInfoVersion(version: u16){
165 display("The TCB Info structure has unexpected version: {}", version)
166 }
167 UntrustedTcbInfoVersion(curr_version: u16, min_version: u16) {
168 display("The TCB Info structure has version {curr_version}, while at least {min_version} is required")
169 }
170 EnclaveTcbLevelNotFound {
171 display("TCB level not found for enclave")
172 }
173 UnknownQeIdentityVersion(version: u16){
174 display("The QEIdentity structure has unexpected version: {}", version)
175 }
176 InvalidDcapAttestationFormat{
177 display("The DCAP Attestation certificate has an unexpected format")
178 }
179 }
180}
181
182#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
183pub enum DcapArtifactIssuer {
184 PCKPlatformCA,
185 PCKProcessorCA,
186 SGXRootCA,
187}
188
189impl TryFrom<&str> for DcapArtifactIssuer {
190 type Error = Error;
191
192 fn try_from(value: &str) -> Result<Self, Self::Error> {
193 if value.contains("Intel SGX PCK Platform CA") {
194 return Ok(DcapArtifactIssuer::PCKPlatformCA);
195 }
196
197 if value.contains("Intel SGX PCK Processor CA") {
198 return Ok(DcapArtifactIssuer::PCKProcessorCA);
199 }
200
201 if value.contains("Intel SGX Root CA") {
202 return Ok(DcapArtifactIssuer::SGXRootCA);
203 }
204
205 Err(Error::InvalidCaFormat)
206 }
207}
208
209pub trait VerificationType { }
212
213#[derive(Clone, Debug, Eq, PartialEq)]
214pub struct Verified;
215
216impl VerificationType for Verified {}
217
218#[derive(Clone, Debug, Eq, PartialEq)]
219pub struct Unverified;
220
221impl VerificationType for Unverified {}
222
223impl<'de> Deserialize<'de> for Unverified {
227 fn deserialize<D>(_: D) -> Result<Self, D::Error>
228 where
229 D: Deserializer<'de> {
230 Ok(Self{})
231 }
232}
233
234fn get_ecdsa_sig_der(sig: &[u8]) -> Result<Vec<u8>, ()> {
237 if sig.len() % 2 != 0 {
238 return Err(());
239 }
240
241 let (r_bytes, s_bytes) = sig.split_at(sig.len() / 2);
242 let r = num::BigUint::from_bytes_be(r_bytes);
243 let s = num::BigUint::from_bytes_be(s_bytes);
244
245 let der = yasna::construct_der(|writer| {
246 writer.write_sequence(|writer| {
247 writer.next().write_biguint(&r);
248 writer.next().write_biguint(&s);
249 })
250 });
251
252 Ok(der)
253}
254
255fn intel_signature_deserializer<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
256 let signature = String::deserialize(deserializer)?;
257 let signature = &base16::decode(signature.as_bytes()).map_err(de::Error::custom)?;
258 crate::get_ecdsa_sig_der(signature).map_err(|_| de::Error::custom("Failed ECDSA signature conversion"))
259}
260
261#[cfg(feature = "verify")]
262fn create_cert_chain(certs: &Vec<String>) -> Result<(Vec<MbedtlsBox<Certificate>>, MbedtlsBox<Certificate>), Error> {
263 fn str_to_cert_box(ca: &String) -> Result<MbedtlsBox<Certificate>, Error> {
264 let ca = CString::new(ca.as_bytes()).map_err(|_| Error::InvalidCaFormat)?;
265 Certificate::from_pem(ca.as_bytes_with_nul()).map_err(|_| Error::InvalidCaFormat)
266 }
267 if let Some((last_cert, certs)) = certs.split_last() {
268 let chain = certs.iter().map(str_to_cert_box).collect::<Result<Vec<_>, _>>()?;
269 let last_cert = str_to_cert_box(last_cert)?;
270 Ok((chain, last_cert))
271 } else {
272 Err(Error::MissingCaChain)
273 }
274}
275
276#[cfg(feature = "verify")]
290fn check_root_ca<B: Deref<Target = [u8]>>(trusted_root_certs: &[B], candidate: &MbedtlsList<Certificate>) -> Result<(), Error> {
291 if trusted_root_certs
292 .iter()
293 .filter_map(|trusted_der| Certificate::from_der(&**trusted_der).ok())
294 .any(|trusted| Certificate::verify(candidate, &std::iter::once(trusted).collect(), None, None).is_ok())
295 {
296 return Ok(());
297 } else {
298 return Err(Error::IncorrectCA);
299 }
300}
301
302#[cfg(test)]
303#[cfg(not(target_env = "sgx"))]
304fn get_cert_subject(cert: &str) -> String {
305 let der = &pkix::pem::pem_to_der(cert.trim(), Some(pkix::pem::PEM_CERTIFICATE))
306 .ok_or(ASN1Error::new(yasna::ASN1ErrorKind::Invalid))
307 .unwrap();
308 get_cert_subject_from_der(der)
309}
310
311#[cfg(test)]
312#[cfg(not(target_env = "sgx"))]
313fn get_cert_subject_from_der(cert: &Vec<u8>) -> String {
314 use pkix::FromBer;
315 let cert = pkix::x509::GenericCertificate::from_ber(&cert).unwrap();
316 let name = cert.tbscert.subject.get(&*pkix::oid::commonName).unwrap();
317 String::from_utf8_lossy(&name.value()).to_string()
318}
319
320#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, Copy)]
321pub enum TcbStatus {
322 UpToDate,
323 SWHardeningNeeded,
324 ConfigurationNeeded,
325 ConfigurationAndSWHardeningNeeded,
326 OutOfDate,
327 OutOfDateConfigurationNeeded,
328 Revoked,
329}
330
331impl TcbStatus {
332 pub(crate) fn drop_sw_hardening_needed(self) -> Self {
333 match self {
334 Self::SWHardeningNeeded => Self::UpToDate,
335 Self::ConfigurationAndSWHardeningNeeded => Self::ConfigurationNeeded,
336 v => v,
337 }
338 }
339}
340
341impl fmt::Display for TcbStatus {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 match self {
344 TcbStatus::UpToDate => write!(f, "Up to Date"),
345 TcbStatus::SWHardeningNeeded => write!(f, "Software Hardening Needed"),
346 TcbStatus::ConfigurationNeeded => write!(f, "Configuration Needed"),
347 TcbStatus::ConfigurationAndSWHardeningNeeded => write!(f, "Configuration And Software Hardening Needed"),
348 TcbStatus::OutOfDate => write!(f, "Out of Date"),
349 TcbStatus::OutOfDateConfigurationNeeded => write!(f, "Out of Date, Configuration Needed"),
350 TcbStatus::Revoked => write!(f, "Revoked"),
351 }
352 }
353}