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