diff --git a/Cargo.lock b/Cargo.lock index 6bbe7018..e27614ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -543,6 +543,7 @@ dependencies = [ "base64 0.22.1", "chrono", "crypto", + "dcap-rs", "flex-error", "hex", "lcp-types", @@ -1512,7 +1513,7 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dcap-rs" version = "0.1.0" -source = "git+https://github.com/bluele/dcap-rs?rev=43f60654515fb3000ebdc11ac80e1af9caba1ff9#43f60654515fb3000ebdc11ac80e1af9caba1ff9" +source = "git+https://github.com/bluele/dcap-rs?rev=71fe1e02f151a28bf5661b01dba5096730564840#71fe1e02f151a28bf5661b01dba5096730564840" dependencies = [ "alloy-sol-types", "chrono", diff --git a/app/src/commands/enclave.rs b/app/src/commands/enclave.rs index 63245aa3..8798fa6a 100644 --- a/app/src/commands/enclave.rs +++ b/app/src/commands/enclave.rs @@ -121,25 +121,37 @@ fn run_list_keys, S: CommitStore>( }; let mut list_json = Vec::new(); for eki in list { - match eki.ias_report { - Some(ias_report) => { - let avr = ias_report.get_avr()?; - let report_data = avr.parse_quote()?.report_data(); - list_json.push(json! {{ - "address": eki.address.to_hex_string(), - "attested": true, - "report_data": report_data.to_string(), - "isv_enclave_quote_status": avr.isv_enclave_quote_status, - "advisory_ids": avr.advisory_ids, - "attested_at": avr.timestamp - }}); - } - None => { - list_json.push(json! {{ - "address": eki.address.to_hex_string(), - "attested": false, - }}); - } + let ias_attested = eki.ias_report.is_some(); + let dcap_attested = eki.dcap_quote.is_some(); + + if ias_attested { + let avr = eki.ias_report.as_ref().unwrap().get_avr()?; + let report_data = avr.parse_quote()?.report_data(); + list_json.push(json! {{ + "type": "ias", + "address": eki.address.to_hex_string(), + "attested": true, + "report_data": report_data.to_string(), + "isv_enclave_quote_status": avr.isv_enclave_quote_status, + "advisory_ids": avr.advisory_ids, + "attested_at": avr.timestamp + }}); + } else if dcap_attested { + let dcap_quote = eki.dcap_quote.as_ref().unwrap(); + list_json.push(json! {{ + "type": "dcap", + "address": eki.address.to_hex_string(), + "attested": true, + "report_data": dcap_quote.report_data().to_string(), + "isv_enclave_quote_status": dcap_quote.tcb_status.to_string(), + "advisory_ids": dcap_quote.advisory_ids, + "attested_at": dcap_quote.attested_at, + }}); + } else { + list_json.push(json! {{ + "address": eki.address.to_hex_string(), + "attested": false, + }}); } } println!("{}", serde_json::to_string(&list_json).unwrap()); diff --git a/modules/attestation-report/Cargo.toml b/modules/attestation-report/Cargo.toml index 4e9adf71..cd85f0cb 100644 --- a/modules/attestation-report/Cargo.toml +++ b/modules/attestation-report/Cargo.toml @@ -16,12 +16,15 @@ base64 = { version = "0.22.1", default-features = false, features = ["alloc"] } pem = { version = "2.0", default-features = false } webpki = { version = "0.22", features = ["alloc"] } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840", optional = true } + [dev-dependencies] tokio = { version = "1.0", default-features = false, features = ["macros"] } [features] default = ["std"] std = [ + "dcap-rs", "webpki/std", "flex-error/std", "lcp-types/std", diff --git a/modules/attestation-report/src/dcap.rs b/modules/attestation-report/src/dcap.rs index 92f5e9ec..92c92769 100644 --- a/modules/attestation-report/src/dcap.rs +++ b/modules/attestation-report/src/dcap.rs @@ -1,6 +1,7 @@ use crate::prelude::*; use crate::serde_base64; use crate::Error; +use crate::ReportData; use lcp_types::Time; use serde::{Deserialize, Serialize}; @@ -8,13 +9,68 @@ use serde::{Deserialize, Serialize}; pub struct DCAPQuote { #[serde(with = "serde_base64")] pub raw: Vec, + pub tcb_status: TcbStatus, + pub advisory_ids: Option>, pub attested_at: Time, } +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum TcbStatus { + OK, + TcbSwHardeningNeeded, + TcbConfigurationAndSwHardeningNeeded, + TcbConfigurationNeeded, + TcbOutOfDate, + TcbOutOfDateConfigurationNeeded, + TcbRevoked, + TcbUnrecognized, +} + +impl TcbStatus { + pub fn from_str(s: &str) -> Self { + return match s { + "UpToDate" => TcbStatus::OK, + "SWHardeningNeeded" => TcbStatus::TcbSwHardeningNeeded, + "ConfigurationAndSWHardeningNeeded" => TcbStatus::TcbConfigurationAndSwHardeningNeeded, + "ConfigurationNeeded" => TcbStatus::TcbConfigurationNeeded, + "OutOfDate" => TcbStatus::TcbOutOfDate, + "OutOfDateConfigurationNeeded" => TcbStatus::TcbOutOfDateConfigurationNeeded, + "Revoked" => TcbStatus::TcbRevoked, + _ => TcbStatus::TcbUnrecognized, + }; + } +} + +impl ToString for TcbStatus { + fn to_string(&self) -> String { + return match self { + TcbStatus::OK => "UpToDate".to_string(), + TcbStatus::TcbSwHardeningNeeded => "SWHardeningNeeded".to_string(), + TcbStatus::TcbConfigurationAndSwHardeningNeeded => { + "ConfigurationAndSWHardeningNeeded".to_string() + } + TcbStatus::TcbConfigurationNeeded => "ConfigurationNeeded".to_string(), + TcbStatus::TcbOutOfDate => "OutOfDate".to_string(), + TcbStatus::TcbOutOfDateConfigurationNeeded => { + "OutOfDateConfigurationNeeded".to_string() + } + TcbStatus::TcbRevoked => "Revoked".to_string(), + TcbStatus::TcbUnrecognized => "Unrecognized".to_string(), + }; + } +} + impl DCAPQuote { - pub fn new(raw_quote: Vec, attested_at: Time) -> Self { + pub fn new( + raw_quote: Vec, + tcb_status: String, + advisory_ids: Option>, + attested_at: Time, + ) -> Self { DCAPQuote { raw: raw_quote, + tcb_status: TcbStatus::from_str(&tcb_status), + advisory_ids, attested_at, } } @@ -26,4 +82,11 @@ impl DCAPQuote { pub fn from_json(json: &str) -> Result { serde_json::from_str(json).map_err(Error::serde_json) } + + #[cfg(feature = "std")] + pub fn report_data(&self) -> ReportData { + use dcap_rs::types::quotes::version_3::QuoteV3; + let quote = QuoteV3::from_bytes(&self.raw); + ReportData(quote.isv_enclave_report.report_data) + } } diff --git a/modules/attestation-report/src/errors.rs b/modules/attestation-report/src/errors.rs index d12e2c47..72f75342 100644 --- a/modules/attestation-report/src/errors.rs +++ b/modules/attestation-report/src/errors.rs @@ -23,14 +23,6 @@ define_error! { format_args!("unexpected report data version: expected={} actual={}", e.expected, e.actual) }, - InvalidReportDataSize - { - size: usize - } - |e| { - format_args!("invalid report data size: size must be >= 20, but got {}", e.size) - }, - MrenclaveMismatch { expected: Mrenclave, diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index 6f50d76a..e963b3f8 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -38,7 +38,7 @@ impl From for VerifiableQuote { /// ReportData is a 64-byte value that is embedded in the Quote /// | version: 1 byte | enclave key: 20 bytes | operator: 20 bytes | nonce: 22 bytes | #[derive(Debug, Clone, PartialEq)] -pub struct ReportData([u8; 64]); +pub struct ReportData(pub(crate) [u8; 64]); impl ReportData { /// Creates a new report data diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 07dc1107..fa1f07cf 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -25,7 +25,7 @@ reqwest = { version = "0.12.9", default-features = false, features = [ ] } urlencoding = { version = "2" } -dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "43f60654515fb3000ebdc11ac80e1af9caba1ff9" } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840" } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index 7c5f3eaa..a99b7119 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -49,7 +49,13 @@ pub fn run_dcap_ra( key_manager .save_verifiable_quote( target_enclave_key, - DCAPQuote::new(raw_quote, current_time).into(), + DCAPQuote::new( + raw_quote, + output.tcb_status.to_string(), + output.advisory_ids, + current_time, + ) + .into(), ) .map_err(|e| { Error::key_manager(format!("cannot save DCAP AVR: {}", target_enclave_key), e) @@ -89,10 +95,9 @@ fn get_collateral(pccs_url: &str, certs_service_url: &str, quote: &QuoteV3) -> I // get the SGX extension let sgx_extensions = extract_sgx_extension(pck_cert); - let fmspc = hex::encode_upper(sgx_extensions.fmspc); - let mut collateral = IntelCollateral::new(); { + let fmspc = hex::encode_upper(sgx_extensions.fmspc); let res = reqwest::blocking::get(format!("{base_url}/tcb?fmspc={fmspc}")).unwrap(); let issuer_chain = extract_raw_certs( get_header(&res, "TCB-Info-Issuer-Chain")