diff --git a/Cargo.lock b/Cargo.lock index 2bf72420..eb3bbabb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2628,6 +2628,7 @@ checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" name = "keymanager" version = "0.1.0" dependencies = [ + "anyhow", "attestation-report", "chrono", "crypto", @@ -2638,6 +2639,8 @@ dependencies = [ "rusqlite", "serde", "serde_json", + "serde_with", + "sgx_types", ] [[package]] @@ -2727,6 +2730,7 @@ dependencies = [ "prost", "serde", "serde_json", + "serde_with", "sgx_types", "tendermint 0.29.0", ] @@ -3918,11 +3922,11 @@ dependencies = [ "base64 0.22.1", "chrono", "crypto", - "ecall-commands", "enclave-api", "flex-error", "hex", "httparse", + "keymanager", "lcp-types", "log", "rand 0.8.5", diff --git a/app/src/commands/attestation.rs b/app/src/commands/attestation.rs index c2357bf1..67fdaf12 100644 --- a/app/src/commands/attestation.rs +++ b/app/src/commands/attestation.rs @@ -64,27 +64,11 @@ pub struct IASRemoteAttestation { help = "An enclave key attested by Remote Attestation" )] pub enclave_key: String, - /// An operator address to perform `registerEnclaveKey` transaction on-chain - #[clap( - long = "operator", - help = "An operator address to perform `registerEnclaveKey` transaction on-chain" - )] - pub operator: Option, /// IAS mode #[clap(long = "development", help = "Use IAS development mode")] pub is_dev: bool, } -impl IASRemoteAttestation { - fn get_operator(&self) -> Result> { - if let Some(operator) = &self.operator { - Ok(Some(Address::from_hex_string(operator)?)) - } else { - Ok(None) - } - } -} - fn run_ias_remote_attestation, S: CommitStore>( enclave: E, cmd: &IASRemoteAttestation, @@ -95,7 +79,6 @@ fn run_ias_remote_attestation, S: CommitStore>( match ias::run_ias_ra( &enclave, target_enclave_key, - cmd.get_operator()?, if cmd.is_dev { IASMode::Development } else { @@ -179,17 +162,6 @@ pub struct SimulateRemoteAttestation { pub isv_enclave_quote_status: String, } -#[cfg(feature = "sgx-sw")] -impl SimulateRemoteAttestation { - fn get_operator(&self) -> Result> { - if let Some(operator) = &self.operator { - Ok(Some(Address::from_hex_string(operator)?)) - } else { - Ok(None) - } - } -} - #[cfg(feature = "sgx-sw")] fn run_simulate_remote_attestation, S: CommitStore>( enclave: E, @@ -242,7 +214,6 @@ fn run_simulate_remote_attestation, S: CommitStore>( match remote_attestation::ias_simulation::run_ias_ra_simulation( &enclave, target_enclave_key, - cmd.get_operator()?, cmd.advisory_ids.clone(), cmd.isv_enclave_quote_status.clone(), signing_key, diff --git a/app/src/commands/enclave.rs b/app/src/commands/enclave.rs index 22e58a6a..165c38c5 100644 --- a/app/src/commands/enclave.rs +++ b/app/src/commands/enclave.rs @@ -4,6 +4,7 @@ use crate::{ }; use anyhow::{anyhow, Result}; use clap::Parser; +use crypto::Address; use ecall_commands::GenerateEnclaveKeyInput; use enclave_api::{Enclave, EnclaveCommandAPI, EnclaveProtoAPI}; use lcp_types::Mrenclave; @@ -59,14 +60,36 @@ pub struct GenerateKey { /// Options for enclave #[clap(flatten)] pub enclave: EnclaveOpts, + /// An operator address to perform `registerEnclaveKey` transaction on-chain + #[clap( + long = "operator", + help = "An operator address to perform `registerEnclaveKey` transaction on-c + hain" + )] + pub operator: Option, + // TODO add target qe option +} + +impl GenerateKey { + fn get_operator(&self) -> Result> { + if let Some(operator) = &self.operator { + Ok(Some(Address::from_hex_string(operator)?)) + } else { + Ok(None) + } + } } fn run_generate_key, S: CommitStore>( enclave: E, - _: &GenerateKey, + input: &GenerateKey, ) -> Result<()> { + let (target_info, _) = remote_attestation::init_quote()?; let res = enclave - .generate_enclave_key(GenerateEnclaveKeyInput) + .generate_enclave_key(GenerateEnclaveKeyInput { + target_info, + operator: input.get_operator()?, + }) .map_err(|e| anyhow!("failed to generate an enclave key: {:?}", e))?; println!("{}", res.pub_key.as_address()); Ok(()) @@ -97,9 +120,9 @@ fn run_list_keys, S: CommitStore>( }; let mut list_json = Vec::new(); for eki in list { - match eki.avr { - Some(eavr) => { - let avr = eavr.get_avr()?; + match eki.signed_avr { + Some(signed_avr) => { + let avr = signed_avr.get_avr()?; let report_data = avr.parse_quote()?.report_data(); list_json.push(json! {{ "address": eki.address.to_hex_string(), diff --git a/enclave-modules/ecall-handler/src/enclave_manage/enclave.rs b/enclave-modules/ecall-handler/src/enclave_manage/enclave.rs index d95cf510..b88087ae 100644 --- a/enclave-modules/ecall-handler/src/enclave_manage/enclave.rs +++ b/enclave-modules/ecall-handler/src/enclave_manage/enclave.rs @@ -1,15 +1,26 @@ use crate::enclave_manage::Error; use crate::prelude::*; +use attestation_report::ReportData; use crypto::{EnclaveKey, SealingKey}; use ecall_commands::{GenerateEnclaveKeyInput, GenerateEnclaveKeyResponse}; +use sgx_tse::rsgx_create_report; pub(crate) fn generate_enclave_key( - _: GenerateEnclaveKeyInput, + input: GenerateEnclaveKeyInput, ) -> Result { let ek = EnclaveKey::new()?; let sealed_ek = ek.seal()?; + let ek_pub = ek.get_pubkey(); + let report_data = ReportData::new(ek_pub.as_address(), input.operator); + let report = match rsgx_create_report(&input.target_info, &report_data.into()) { + Ok(r) => r, + Err(e) => { + return Err(Error::sgx_error(e, "Report creation => failed".to_string())); + } + }; Ok(GenerateEnclaveKeyResponse { - pub_key: ek.get_pubkey(), + pub_key: ek_pub, sealed_ek, + report, }) } diff --git a/enclave-modules/ecall-handler/src/enclave_manage/mod.rs b/enclave-modules/ecall-handler/src/enclave_manage/mod.rs index b9f16a9d..eff070a7 100644 --- a/enclave-modules/ecall-handler/src/enclave_manage/mod.rs +++ b/enclave-modules/ecall-handler/src/enclave_manage/mod.rs @@ -3,5 +3,4 @@ pub use router::dispatch; mod enclave; mod errors; -mod report; mod router; diff --git a/enclave-modules/ecall-handler/src/enclave_manage/report.rs b/enclave-modules/ecall-handler/src/enclave_manage/report.rs deleted file mode 100644 index ee9d8b26..00000000 --- a/enclave-modules/ecall-handler/src/enclave_manage/report.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::enclave_manage::Error; -use crate::prelude::*; -use attestation_report::ReportData; -use crypto::{EnclaveKey, SealingKey}; -use ecall_commands::{CommandContext, CreateReportInput, CreateReportResponse}; -use sgx_tse::rsgx_create_report; - -pub fn create_report( - cctx: CommandContext, - input: CreateReportInput, -) -> Result { - let pub_key = - EnclaveKey::unseal(&cctx.sealed_ek.ok_or(Error::enclave_key_not_found())?)?.get_pubkey(); - let report_data = ReportData::new(pub_key.as_address(), input.operator); - - let report = match rsgx_create_report(&input.target_info, &report_data.into()) { - Ok(r) => r, - Err(e) => { - return Err(Error::sgx_error(e, "Report creation => failed".to_string())); - } - }; - Ok(CreateReportResponse { report }) -} diff --git a/enclave-modules/ecall-handler/src/enclave_manage/router.rs b/enclave-modules/ecall-handler/src/enclave_manage/router.rs index 2dc235d3..5cd6f8ca 100644 --- a/enclave-modules/ecall-handler/src/enclave_manage/router.rs +++ b/enclave-modules/ecall-handler/src/enclave_manage/router.rs @@ -1,23 +1,14 @@ -use crate::enclave_manage::report::create_report; use crate::enclave_manage::{enclave::generate_enclave_key, Error}; use crate::prelude::*; -use ecall_commands::{ - CommandContext, CommandResponse, EnclaveManageCommand, EnclaveManageResponse, -}; +use ecall_commands::{CommandResponse, EnclaveManageCommand, EnclaveManageResponse}; -pub fn dispatch( - cctx: CommandContext, - command: EnclaveManageCommand, -) -> Result { +pub fn dispatch(command: EnclaveManageCommand) -> Result { use EnclaveManageCommand::*; let res = match command { GenerateEnclaveKey(input) => CommandResponse::EnclaveManage( EnclaveManageResponse::GenerateEnclaveKey(generate_enclave_key(input)?), ), - CreateReport(input) => CommandResponse::EnclaveManage(EnclaveManageResponse::CreateReport( - create_report(cctx, input)?, - )), }; Ok(res) } diff --git a/enclave-modules/ecall-handler/src/router.rs b/enclave-modules/ecall-handler/src/router.rs index ee63800e..53f61aad 100644 --- a/enclave-modules/ecall-handler/src/router.rs +++ b/enclave-modules/ecall-handler/src/router.rs @@ -7,7 +7,7 @@ use enclave_environment::Env; pub fn dispatch(env: E, command: ECallCommand) -> Result { match command.cmd { Command::EnclaveManage(cmd) => { - enclave_manage::dispatch(command.ctx, cmd).map_err(Error::enclave_manage_command) + enclave_manage::dispatch(cmd).map_err(Error::enclave_manage_command) } Command::LightClient(cmd) => { light_client::dispatch(env, command.ctx, cmd).map_err(Error::light_client_command) diff --git a/enclave/Cargo.lock b/enclave/Cargo.lock index 0bd41645..6f9a9223 100644 --- a/enclave/Cargo.lock +++ b/enclave/Cargo.lock @@ -865,6 +865,7 @@ dependencies = [ "prost", "serde", "serde_json", + "serde_with", "sgx_types", "tendermint", ] diff --git a/modules/attestation-report/src/lib.rs b/modules/attestation-report/src/lib.rs index 949b27df..89217b26 100644 --- a/modules/attestation-report/src/lib.rs +++ b/modules/attestation-report/src/lib.rs @@ -24,7 +24,7 @@ pub use errors::Error; mod errors; pub use report::{ - AttestationVerificationReport, EndorsedAttestationVerificationReport, Quote, ReportData, + AttestationVerificationReport, Quote, ReportData, SignedAttestationVerificationReport, }; mod report; diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index d3a93331..472a5172 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -16,6 +16,7 @@ pub const REPORT_DATA_V1: u8 = 1; pub struct ReportData([u8; 64]); impl ReportData { + /// Creates a new report data pub fn new(ek: Address, operator: Option
) -> Self { let mut data: ReportData = Default::default(); data.0[0] = REPORT_DATA_V1; @@ -26,16 +27,23 @@ impl ReportData { data } + /// Returns the enclave key from the report data + /// + /// CONTRACT: The report data must be validated before calling this function pub fn enclave_key(&self) -> Address { // Unwrap is safe because the size of the slice is 20 Address::try_from(&self.0[1..21]).unwrap() } + /// Returns the operator from the report data + /// + /// CONTRACT: The report data must be validated before calling this function pub fn operator(&self) -> Address { // Unwrap is safe because the size of the slice is 20 Address::try_from(&self.0[21..41]).unwrap() } + /// Validates the report data pub fn validate(&self) -> Result<(), Error> { if self.0[0] != REPORT_DATA_V1 { return Err(Error::unexpected_report_data_version( @@ -71,14 +79,12 @@ impl From for ReportData { } } -/// AttestationReport can be endorsed by either the Intel Attestation Service -/// using EPID or Data Center Attestation -/// Service (platform dependent) using ECDSA. +/// SignedAttestationVerificationReport represents the signed attestation verification report from Intel #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct EndorsedAttestationVerificationReport { - /// Attestation report generated by the hardware +pub struct SignedAttestationVerificationReport { + /// A report generated by the Intel Attestation Service pub avr: String, - /// Singature of the report + /// Signature of the report #[serde(with = "serde_base64")] pub signature: Vec, /// Certificate matching the signing key of the signature @@ -86,10 +92,18 @@ pub struct EndorsedAttestationVerificationReport { pub signing_cert: Vec, } -impl EndorsedAttestationVerificationReport { +impl SignedAttestationVerificationReport { pub fn get_avr(&self) -> Result { serde_json::from_slice(self.avr.as_ref()).map_err(Error::serde_json) } + + pub fn to_json(&self) -> Result { + serde_json::to_string(self).map_err(Error::serde_json) + } + + pub fn from_json(json: &str) -> Result { + serde_json::from_str(json).map_err(Error::serde_json) + } } // AttestationVerificationReport represents Intel's Attestation Verification Report diff --git a/modules/attestation-report/src/verification.rs b/modules/attestation-report/src/verification.rs index db14c267..4a79c23f 100644 --- a/modules/attestation-report/src/verification.rs +++ b/modules/attestation-report/src/verification.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use crate::{errors::Error, EndorsedAttestationVerificationReport}; +use crate::{errors::Error, SignedAttestationVerificationReport}; use lcp_types::{nanos_to_duration, Time}; pub const IAS_REPORT_CA: &[u8] = @@ -22,7 +22,7 @@ static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[ pub fn verify_report( current_timestamp: Time, - report: &EndorsedAttestationVerificationReport, + report: &SignedAttestationVerificationReport, ) -> Result<(), Error> { // NOTE: Currently, webpki::Time's constructor only accepts seconds as unix timestamp. // Therefore, the current time are rounded up conservatively. diff --git a/modules/ecall-commands/src/commands.rs b/modules/ecall-commands/src/commands.rs index b3a71a3d..db84c214 100644 --- a/modules/ecall-commands/src/commands.rs +++ b/modules/ecall-commands/src/commands.rs @@ -45,7 +45,7 @@ pub enum Command { impl EnclaveKeySelector for Command { fn get_enclave_key(&self) -> Option { match self { - Self::EnclaveManage(cmd) => cmd.get_enclave_key(), + Self::EnclaveManage(_) => None, Self::LightClient(cmd) => cmd.get_enclave_key(), } } diff --git a/modules/ecall-commands/src/enclave_manage.rs b/modules/ecall-commands/src/enclave_manage.rs index a8d39477..176a83da 100644 --- a/modules/ecall-commands/src/enclave_manage.rs +++ b/modules/ecall-commands/src/enclave_manage.rs @@ -1,6 +1,6 @@ -use crate::transmuter::BytesTransmuter; -use crate::{prelude::*, EnclaveKeySelector}; +use crate::prelude::*; use crypto::{Address, EnclavePublicKey, SealedEnclaveKey}; +use lcp_types::BytesTransmuter; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use sgx_types::{sgx_report_t, sgx_target_info_t}; @@ -8,45 +8,26 @@ use sgx_types::{sgx_report_t, sgx_target_info_t}; #[derive(Serialize, Deserialize, Debug)] pub enum EnclaveManageCommand { GenerateEnclaveKey(GenerateEnclaveKeyInput), - CreateReport(CreateReportInput), } -impl EnclaveKeySelector for EnclaveManageCommand { - fn get_enclave_key(&self) -> Option
{ - match self { - Self::GenerateEnclaveKey(_) => None, - Self::CreateReport(input) => Some(input.target_enclave_key), - } - } -} - -#[derive(Serialize, Deserialize, Debug, Default)] -pub struct GenerateEnclaveKeyInput; - #[serde_as] #[derive(Serialize, Deserialize, Debug, Default)] -pub struct CreateReportInput { +pub struct GenerateEnclaveKeyInput { #[serde_as(as = "BytesTransmuter")] pub target_info: sgx_target_info_t, - pub target_enclave_key: Address, pub operator: Option
, } #[derive(Serialize, Deserialize, Debug)] pub enum EnclaveManageResponse { GenerateEnclaveKey(GenerateEnclaveKeyResponse), - CreateReport(CreateReportResponse), } +#[serde_as] #[derive(Serialize, Deserialize, Debug)] pub struct GenerateEnclaveKeyResponse { pub pub_key: EnclavePublicKey, pub sealed_ek: SealedEnclaveKey, -} - -#[serde_as] -#[derive(Serialize, Deserialize, Debug)] -pub struct CreateReportResponse { #[serde_as(as = "BytesTransmuter")] pub report: sgx_report_t, } diff --git a/modules/ecall-commands/src/lib.rs b/modules/ecall-commands/src/lib.rs index 22637ddb..8f9e2af5 100644 --- a/modules/ecall-commands/src/lib.rs +++ b/modules/ecall-commands/src/lib.rs @@ -26,8 +26,8 @@ mod prelude { pub use commands::{Command, CommandContext, CommandResponse, ECallCommand}; use crypto::Address; pub use enclave_manage::{ - CreateReportInput, CreateReportResponse, EnclaveManageCommand, EnclaveManageResponse, - GenerateEnclaveKeyInput, GenerateEnclaveKeyResponse, + EnclaveManageCommand, EnclaveManageResponse, GenerateEnclaveKeyInput, + GenerateEnclaveKeyResponse, }; pub use errors::InputValidationError; pub use light_client::{ @@ -42,7 +42,6 @@ mod commands; mod enclave_manage; mod errors; mod light_client; -mod transmuter; #[cfg(feature = "std")] pub mod msgs; diff --git a/modules/ecall-commands/src/transmuter.rs b/modules/ecall-commands/src/transmuter.rs deleted file mode 100644 index d829c6ac..00000000 --- a/modules/ecall-commands/src/transmuter.rs +++ /dev/null @@ -1,42 +0,0 @@ -use alloc::string::ToString; -use core::marker::PhantomData; -use serde::Deserialize; -use serde_with::{DeserializeAs, SerializeAs}; - -pub(crate) struct BytesTransmuter(PhantomData); - -impl SerializeAs for BytesTransmuter -where - [(); core::mem::size_of::()]:, -{ - fn serialize_as(source: &T, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_bytes(&unsafe { - core::mem::transmute_copy::<_, [u8; core::mem::size_of::()]>(source) - }) - } -} - -impl<'de, T> DeserializeAs<'de, T> for BytesTransmuter -where - [(); core::mem::size_of::()]:, -{ - fn deserialize_as(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let bz = <&[u8]>::deserialize(deserializer).map_err(serde::de::Error::custom)?; - let mut array = [0; core::mem::size_of::()]; - if bz.len() == array.len() { - array.copy_from_slice(bz); - Ok(unsafe { core::mem::transmute_copy(&array) }) - } else { - Err(serde::de::Error::invalid_length( - bz.len(), - &array.len().to_string().as_str(), - )) - } - } -} diff --git a/modules/enclave-api/src/api/command.rs b/modules/enclave-api/src/api/command.rs index c4a5e52e..bd1ed1b0 100644 --- a/modules/enclave-api/src/api/command.rs +++ b/modules/enclave-api/src/api/command.rs @@ -1,7 +1,7 @@ use crate::{EnclavePrimitiveAPI, Result}; use ecall_commands::{ - AggregateMessagesInput, AggregateMessagesResponse, Command, CommandResponse, CreateReportInput, - CreateReportResponse, EnclaveManageCommand, EnclaveManageResponse, GenerateEnclaveKeyInput, + AggregateMessagesInput, AggregateMessagesResponse, Command, CommandResponse, + EnclaveManageCommand, EnclaveManageResponse, GenerateEnclaveKeyInput, GenerateEnclaveKeyResponse, InitClientInput, InitClientResponse, LightClientCommand, LightClientExecuteCommand, LightClientQueryCommand, LightClientResponse, QueryClientInput, QueryClientResponse, UpdateClientInput, UpdateClientResponse, VerifyMembershipInput, @@ -22,26 +22,11 @@ pub trait EnclaveCommandAPI: EnclavePrimitiveAPI { CommandResponse::EnclaveManage(EnclaveManageResponse::GenerateEnclaveKey(res)) => res, _ => unreachable!(), }; - let metadata = self.metadata()?; - self.get_key_manager().save( - res.pub_key.as_address(), - res.sealed_ek.clone(), - metadata.enclave_css.body.enclave_hash.m.into(), - )?; + self.get_key_manager() + .save(res.sealed_ek.clone(), res.report)?; Ok(res) } - /// create_report creates a report for the given target_info - fn create_report(&self, input: CreateReportInput) -> Result { - match self.execute_command( - Command::EnclaveManage(EnclaveManageCommand::CreateReport(input)), - None, - )? { - CommandResponse::EnclaveManage(EnclaveManageResponse::CreateReport(res)) => Ok(res), - _ => unreachable!(), - } - } - /// init_client initializes an ELC instance with given states fn init_client(&self, input: InitClientInput) -> Result { let update_key = Some(input.any_client_state.type_url.clone()); diff --git a/modules/keymanager/Cargo.toml b/modules/keymanager/Cargo.toml index 67d7fd3f..f4ea957f 100644 --- a/modules/keymanager/Cargo.toml +++ b/modules/keymanager/Cargo.toml @@ -4,7 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] +sgx_types = { rev = "v1.1.6", git = "https://github.com/apache/incubator-teaclave-sgx-sdk" } +serde_with = { version = "2.0.1", default-features = false, features = ["alloc", "macros"] } log = "0.4.8" +anyhow = { version = "1.0.56" } flex-error = { version = "0.4.4" } serde = { version = "1.0.184", default-features = false, features = ["alloc"] } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } diff --git a/modules/keymanager/src/lib.rs b/modules/keymanager/src/lib.rs index af4ffb03..d4b04bcc 100644 --- a/modules/keymanager/src/lib.rs +++ b/modules/keymanager/src/lib.rs @@ -1,14 +1,18 @@ pub mod errors; pub use crate::errors::Error; -use attestation_report::EndorsedAttestationVerificationReport; +use anyhow::anyhow; +use attestation_report::{ReportData, SignedAttestationVerificationReport}; use crypto::{Address, SealedEnclaveKey}; -use lcp_types::proto::lcp::service::enclave::v1::EnclaveKeyInfo as ProtoEnclaveKeyInfo; -use lcp_types::{Mrenclave, Time}; +use lcp_types::{ + deserialize_bytes, proto::lcp::service::enclave::v1::EnclaveKeyInfo as ProtoEnclaveKeyInfo, + serialize_bytes, BytesTransmuter, Mrenclave, Time, +}; use log::*; use rusqlite::{params, types::Type, Connection}; use serde::{Deserialize, Serialize}; -use std::sync::Mutex; -use std::{ops::Deref, path::Path, time::Duration}; +use serde_with::serde_as; +use sgx_types::sgx_report_t; +use std::{path::Path, sync::Mutex, time::Duration}; pub static KEY_MANAGER_DB: &str = "km.sqlite"; @@ -47,12 +51,11 @@ impl EnclaveKeyManager { BEGIN; CREATE TABLE enclave_keys ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - ek_address VARCHAR NOT NULL UNIQUE, - ek_sealed TEXT NOT NULL, - mrenclave VARCHAR NOT NULL, - avr TEXT, - signature TEXT, - signing_cert TEXT, + ek_address TEXT NOT NULL UNIQUE, + ek_sealed BLOB NOT NULL, + mrenclave TEXT NOT NULL, + report BLOB NOT NULL, + signed_avr TEXT, attested_at TEXT, created_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), updated_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')) @@ -71,29 +74,49 @@ impl EnclaveKeyManager { .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( - "SELECT ek_sealed, mrenclave, avr, signature, signing_cert FROM enclave_keys WHERE ek_address = ?1", + r#" + SELECT ek_sealed, mrenclave, report, signed_avr + FROM enclave_keys + WHERE ek_address = ?1 + "#, )?; let key_info = stmt.query_row(params![address.to_hex_string()], |row| { Ok(SealedEnclaveKeyInfo { address, sealed_ek: SealedEnclaveKey::new_from_bytes(row.get::<_, Vec>(0)?.as_slice()) .map_err(|e| { - rusqlite::Error::FromSqlConversionFailure(0, Type::Blob, e.into()) + rusqlite::Error::FromSqlConversionFailure( + 0, + Type::Blob, + anyhow!("sealed_ek: {:?}", e).into(), + ) + })?, + mrenclave: Mrenclave::from_hex_string(&row.get::<_, String>(1)?).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 1, + Type::Text, + anyhow!("mrenclave: {:?}", e).into(), + ) + })?, + report: deserialize_bytes(&row.get::<_, Vec>(2)?).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 2, + Type::Blob, + anyhow!("report: {:?}", e).into(), + ) })?, - mrenclave: Mrenclave(row.get(1)?), - avr: match (row.get(2), row.get(3), row.get(4)) { - (Ok(None), Ok(None), Ok(None)) => None, - (Ok(Some(avr)), Ok(Some(signature)), Ok(Some(signing_cert))) => { - Some(EndorsedAttestationVerificationReport { - avr, - signature, - signing_cert, - }) - } - (e0, e1, e2) => [e0.err(), e1.err(), e2.err()] - .into_iter() - .find_map(|e| e.map(Err)) - .unwrap()?, + signed_avr: match row.get::<_, Option>(3) { + Ok(None) => None, + Ok(Some(avr)) => Some( + SignedAttestationVerificationReport::from_json(&avr).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + Type::Text, + anyhow!("signed_avr: {:?}", e).into(), + ) + })?, + ), + Err(e) => return Err(e), }, }) })?; @@ -101,23 +124,23 @@ impl EnclaveKeyManager { } /// Save a sealed enclave key - pub fn save( - &self, - address: Address, - sealed_ek: SealedEnclaveKey, - mrenclave: Mrenclave, - ) -> Result<(), Error> { + pub fn save(&self, sealed_ek: SealedEnclaveKey, report: sgx_report_t) -> Result<(), Error> { let conn = self .conn .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( - "INSERT INTO enclave_keys (ek_address, ek_sealed, mrenclave) VALUES (?1, ?2, ?3)", + r#" + INSERT INTO enclave_keys(ek_address, ek_sealed, mrenclave, report) + VALUES (?1, ?2, ?3, ?4) + "#, )?; + let rd = ReportData::from(report.body.report_data); let _ = stmt.execute(params![ - address.to_hex_string(), + rd.enclave_key().to_hex_string(), sealed_ek.to_vec(), - mrenclave.deref() + Mrenclave::from(report.body.mr_enclave).to_hex_string(), + serialize_bytes(&report), ])?; Ok(()) } @@ -126,22 +149,24 @@ impl EnclaveKeyManager { pub fn save_avr( &self, address: Address, - avr: EndorsedAttestationVerificationReport, + signed_avr: SignedAttestationVerificationReport, ) -> Result<(), Error> { let conn = self .conn .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; - let attested_at = avr.get_avr()?.attestation_time()?; + let attested_at = signed_avr.get_avr()?.attestation_time()?; // update avr and attested_at and signature and sigining_cert let mut stmt = conn.prepare( - "UPDATE enclave_keys SET avr = ?1, attested_at = ?2, signature = ?3, signing_cert = ?4 WHERE ek_address = ?5", + r#" + UPDATE enclave_keys + SET signed_avr = ?1, attested_at = ?2 + WHERE ek_address = ?3 + "#, )?; stmt.execute(params![ - avr.avr, + signed_avr.to_json()?, attested_at.as_unix_timestamp_secs(), - avr.signature, - avr.signing_cert, address.to_hex_string() ])?; Ok(()) @@ -155,28 +180,58 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, avr, signature, signing_cert + SELECT ek_address, ek_sealed, mrenclave, report, signed_avr FROM enclave_keys WHERE attested_at IS NOT NULL AND mrenclave = ?1 ORDER BY attested_at DESC "#, )?; let key_infos = stmt - .query_map(params![mrenclave.deref()], |row| { + .query_map(params![mrenclave.to_hex_string()], |row| { Ok(SealedEnclaveKeyInfo { - address: Address::from_hex_string(&row.get::<_, String>(0)?).unwrap(), + address: Address::from_hex_string(&row.get::<_, String>(0)?).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 0, + Type::Text, + anyhow!("address: {:?}", e).into(), + ) + })?, sealed_ek: SealedEnclaveKey::new_from_bytes( row.get::<_, Vec>(1)?.as_slice(), ) .map_err(|e| { - rusqlite::Error::FromSqlConversionFailure(1, Type::Blob, e.into()) + rusqlite::Error::FromSqlConversionFailure( + 1, + Type::Blob, + anyhow!("sealed_ek: {:?}", e).into(), + ) })?, - mrenclave: Mrenclave(row.get(2)?), - avr: Some(EndorsedAttestationVerificationReport { - avr: row.get(3)?, - signature: row.get(4)?, - signing_cert: row.get(5)?, - }), + mrenclave: Mrenclave::from_hex_string(&row.get::<_, String>(2)?).map_err( + |e| { + rusqlite::Error::FromSqlConversionFailure( + 2, + Type::Text, + anyhow!("mrenclave: {:?}", e).into(), + ) + }, + )?, + report: deserialize_bytes(&row.get::<_, Vec>(3)?).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + Type::Blob, + anyhow!("report: {:?}", e).into(), + ) + })?, + signed_avr: Some( + SignedAttestationVerificationReport::from_json(&row.get::<_, String>(4)?) + .map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 4, + Type::Text, + anyhow!("signed_avr: {:?}", e).into(), + ) + })?, + ), }) })? .collect::, _>>()?; @@ -190,32 +245,60 @@ impl EnclaveKeyManager { .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( - "SELECT ek_address, ek_sealed, mrenclave, avr, signature, signing_cert FROM enclave_keys ORDER BY updated_at DESC", + r#" + SELECT ek_address, ek_sealed, mrenclave, report, signed_avr + FROM enclave_keys + ORDER BY updated_at DESC + "#, )?; let key_infos = stmt .query_map(params![], |row| { Ok(SealedEnclaveKeyInfo { - address: Address::from_hex_string(&row.get::<_, String>(0)?).unwrap(), + address: Address::from_hex_string(&row.get::<_, String>(0)?).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 0, + Type::Text, + anyhow!("address: {:?}", e).into(), + ) + })?, sealed_ek: SealedEnclaveKey::new_from_bytes( row.get::<_, Vec>(1)?.as_slice(), ) .map_err(|e| { - rusqlite::Error::FromSqlConversionFailure(1, Type::Blob, e.into()) + rusqlite::Error::FromSqlConversionFailure( + 1, + Type::Blob, + anyhow!("sealed_ek: {:?}", e).into(), + ) })?, - mrenclave: Mrenclave(row.get(2)?), - avr: match (row.get(3), row.get(4), row.get(5)) { - (Ok(None), Ok(None), Ok(None)) => None, - (Ok(Some(avr)), Ok(Some(signature)), Ok(Some(signing_cert))) => { - Some(EndorsedAttestationVerificationReport { - avr, - signature, - signing_cert, - }) - } - (e0, e1, e2) => [e0.err(), e1.err(), e2.err()] - .into_iter() - .find_map(|e| e.map(Err)) - .unwrap()?, + mrenclave: Mrenclave::from_hex_string(&row.get::<_, String>(2)?).map_err( + |e| { + rusqlite::Error::FromSqlConversionFailure( + 2, + Type::Text, + anyhow!("mrenclave: {:?}", e).into(), + ) + }, + )?, + report: deserialize_bytes(&row.get::<_, Vec>(3)?).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + Type::Blob, + anyhow!("report: {:?}", e).into(), + ) + })?, + signed_avr: match row.get::<_, Option>(4) { + Ok(None) => None, + Ok(Some(avr)) => Some( + SignedAttestationVerificationReport::from_json(&avr).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 4, + Type::Text, + anyhow!("signed_avr: {:?}", e).into(), + ) + })?, + ), + Err(e) => return Err(e), }, }) })? @@ -236,27 +319,30 @@ impl EnclaveKeyManager { } } +#[serde_as] #[derive(Debug, Serialize, Deserialize)] pub struct SealedEnclaveKeyInfo { - pub address: Address, pub sealed_ek: SealedEnclaveKey, + pub address: Address, pub mrenclave: Mrenclave, - pub avr: Option, + #[serde_as(as = "BytesTransmuter")] + pub report: sgx_report_t, + pub signed_avr: Option, } impl TryFrom for ProtoEnclaveKeyInfo { type Error = Error; fn try_from(value: SealedEnclaveKeyInfo) -> Result { - let eavr = value - .avr + let signed_avr = value + .signed_avr .ok_or_else(|| Error::unattested_enclave_key(format!("address={}", value.address)))?; - let attestation_time = eavr.get_avr()?.parse_quote()?.attestation_time; + let attestation_time = signed_avr.get_avr()?.parse_quote()?.attestation_time; Ok(Self { enclave_key_address: value.address.into(), attestation_time: attestation_time.as_unix_timestamp_secs(), - report: eavr.avr, - signature: eavr.signature, - signing_cert: eavr.signing_cert, + report: signed_avr.avr, + signature: signed_avr.signature, + signing_cert: signed_avr.signing_cert, extension: Default::default(), }) } @@ -275,24 +361,32 @@ mod tests { let mrenclave = create_mrenclave(); let address_0 = { let address = create_address(); + let report = create_report(mrenclave, address); let sealed_ek = create_sealed_sk(); - km.save(address, sealed_ek, mrenclave).unwrap(); + assert_eq!(km.all_keys().unwrap().len(), 0); + km.save(sealed_ek, report).unwrap(); + assert!(km.load(address).unwrap().signed_avr.is_none()); assert_eq!(km.all_keys().unwrap().len(), 1); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 0); - let avr = create_eavr(get_time(Duration::zero())); + let avr = create_signed_avr(get_time(Duration::zero())); km.save_avr(address, avr).unwrap(); + assert!(km.load(address).unwrap().signed_avr.is_some()); assert_eq!(km.all_keys().unwrap().len(), 1); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 1); address }; { let address = create_address(); + let report = create_report(mrenclave, address); let sealed_ek = create_sealed_sk(); - km.save(address, sealed_ek, mrenclave).unwrap(); + assert_eq!(km.all_keys().unwrap().len(), 1); + km.save(sealed_ek, report).unwrap(); + assert!(km.load(address).unwrap().signed_avr.is_none()); assert_eq!(km.all_keys().unwrap().len(), 2); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 1); - let avr = create_eavr(get_time(Duration::minutes(1))); + let avr = create_signed_avr(get_time(Duration::minutes(1))); km.save_avr(address, avr).unwrap(); + assert!(km.load(address).unwrap().signed_avr.is_some()); assert_eq!(km.all_keys().unwrap().len(), 2); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 2); } @@ -324,14 +418,21 @@ mod tests { SealedEnclaveKey::new_from_bytes(&sealed_sk).unwrap() } + fn create_report(mrenclave: Mrenclave, ek_addr: Address) -> sgx_report_t { + let mut report = sgx_report_t::default(); + report.body.mr_enclave = mrenclave.into(); + report.body.report_data = ReportData::new(ek_addr, None).into(); + report + } + fn create_address() -> Address { let bz: [u8; 20] = rand::random(); let addr = Address::try_from(bz.as_slice()).unwrap(); addr } - fn create_eavr(timestamp: DateTime) -> EndorsedAttestationVerificationReport { - EndorsedAttestationVerificationReport { + fn create_signed_avr(timestamp: DateTime) -> SignedAttestationVerificationReport { + SignedAttestationVerificationReport { avr: AttestationVerificationReport { version: 4, timestamp: format!( diff --git a/modules/lcp-client/src/client_def.rs b/modules/lcp-client/src/client_def.rs index e89fdce1..715ab2a5 100644 --- a/modules/lcp-client/src/client_def.rs +++ b/modules/lcp-client/src/client_def.rs @@ -5,7 +5,7 @@ use crate::message::{ ClientMessage, CommitmentProofs, RegisterEnclaveKeyMessage, UpdateOperatorsMessage, }; use alloy_sol_types::{sol, SolValue}; -use attestation_report::{EndorsedAttestationVerificationReport, ReportData}; +use attestation_report::{ReportData, SignedAttestationVerificationReport}; use crypto::{verify_signature_address, Address, Keccak256}; use hex_literal::hex; use light_client::commitments::{ @@ -527,14 +527,14 @@ pub fn compute_eip712_update_operators_hash( fn verify_report( current_timestamp: Time, client_state: &ClientState, - eavr: &EndorsedAttestationVerificationReport, + signed_avr: &SignedAttestationVerificationReport, ) -> Result<(ReportData, Time), Error> { // verify AVR with Intel SGX Attestation Report Signing CA // NOTE: This verification is skipped in tests because the CA is not available in the test environment #[cfg(not(test))] - attestation_report::verify_report(current_timestamp, eavr)?; + attestation_report::verify_report(current_timestamp, signed_avr)?; - let quote = eavr.get_avr()?.parse_quote()?; + let quote = signed_avr.get_avr()?.parse_quote()?; // check if attestation report's timestamp is not expired let key_expiration = (quote.attestation_time + client_state.key_expiration)?; @@ -675,7 +675,7 @@ mod tests { { let mut ctx = Context::new(registry.clone(), ibc_store.clone(), &ek); ctx.set_timestamp(Time::now()); - let report = generate_dummy_eavr(&ek.get_pubkey()); + let report = generate_dummy_signed_avr(&ek.get_pubkey()); let operator_signature = op_key .sign(compute_eip712_register_enclave_key(report.avr.as_str()).as_slice()) .unwrap(); @@ -811,7 +811,7 @@ mod tests { Arc::new(registry) } - fn generate_dummy_eavr(key: &EnclavePublicKey) -> EndorsedAttestationVerificationReport { + fn generate_dummy_signed_avr(key: &EnclavePublicKey) -> SignedAttestationVerificationReport { let quote = sgx_quote_t { version: 4, report_body: sgx_report_body_t { @@ -846,7 +846,7 @@ mod tests { ..Default::default() }; - EndorsedAttestationVerificationReport { + SignedAttestationVerificationReport { avr: attr.to_canonical_json().unwrap(), ..Default::default() } diff --git a/modules/lcp-client/src/message.rs b/modules/lcp-client/src/message.rs index 0a71fc56..a71d5836 100644 --- a/modules/lcp-client/src/message.rs +++ b/modules/lcp-client/src/message.rs @@ -1,7 +1,7 @@ use crate::errors::Error; use crate::prelude::*; use alloy_sol_types::{sol, SolValue}; -use attestation_report::EndorsedAttestationVerificationReport; +use attestation_report::SignedAttestationVerificationReport; use crypto::Address; use light_client::commitments::{Error as CommitmentError, EthABIEncoder, ProxyMessage}; use light_client::types::proto::ibc::lightclients::lcp::v1::{ @@ -68,7 +68,7 @@ impl From for Any { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct RegisterEnclaveKeyMessage { - pub report: EndorsedAttestationVerificationReport, + pub report: SignedAttestationVerificationReport, pub operator_signature: Option>, } @@ -78,7 +78,7 @@ impl TryFrom for RegisterEnclaveKeyMessage { type Error = Error; fn try_from(value: RawRegisterEnclaveKeyMessage) -> Result { Ok(RegisterEnclaveKeyMessage { - report: EndorsedAttestationVerificationReport { + report: SignedAttestationVerificationReport { avr: String::from_utf8(value.report)?, signature: value.signature, signing_cert: value.signing_cert, diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 138e458b..0a3f1366 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -21,9 +21,9 @@ chrono = { version = "0.4.38", features = ["now"], optional = true } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } attestation-report = { path = "../attestation-report" } -ecall-commands = { path = "../ecall-commands" } enclave-api = { path = "../enclave-api" } store = { path = "../store", features = ["rocksdbstore"] } +keymanager = { path = "../keymanager" } [features] default = [] diff --git a/modules/remote-attestation/src/errors.rs b/modules/remote-attestation/src/errors.rs index a59ab549..a580de80 100644 --- a/modules/remote-attestation/src/errors.rs +++ b/modules/remote-attestation/src/errors.rs @@ -84,6 +84,15 @@ define_error! { [attestation_report::Error] |_| { "AttestationReport error" }, + KeyManager + { + descr: String + } + [keymanager::Error] + |e| { + format_args!("KeyManager error: descr={}", e.descr) + }, + UnexpectedIasReportResponse { descr: String } diff --git a/modules/remote-attestation/src/ias.rs b/modules/remote-attestation/src/ias.rs index 51053aa2..14080d60 100644 --- a/modules/remote-attestation/src/ias.rs +++ b/modules/remote-attestation/src/ias.rs @@ -3,33 +3,33 @@ use crate::ias_utils::{ decode_spid, get_quote, get_report_from_intel, get_sigrl_from_intel, init_quote, validate_qe_report, IASMode, SGX_QUOTE_SIGN_TYPE, }; -use attestation_report::EndorsedAttestationVerificationReport; +use attestation_report::SignedAttestationVerificationReport; use crypto::Address; -use ecall_commands::{CreateReportInput, CreateReportResponse}; use enclave_api::EnclaveCommandAPI; use store::transaction::CommitStore; pub fn run_ias_ra, S: CommitStore>( enclave: &E, target_enclave_key: Address, - operator: Option
, mode: IASMode, spid: String, ias_key: String, -) -> Result { +) -> Result { + let ek_info = enclave + .get_key_manager() + .load(target_enclave_key) + .map_err(|e| { + Error::key_manager( + format!("cannot load enclave key: {}", target_enclave_key), + e, + ) + })?; + let spid = decode_spid(&spid)?; let (target_info, epid_group_id) = init_quote()?; - let CreateReportResponse { report } = enclave - .create_report(CreateReportInput { - target_info, - target_enclave_key, - operator, - }) - .map_err(Error::enclave_api)?; - // Now sigrl is the revocation list, a vec let sigrl = get_sigrl_from_intel(mode, epid_group_id, &ias_key)?; - let (quote, qe_report) = get_quote(sigrl, report, SGX_QUOTE_SIGN_TYPE, spid)?; + let (quote, qe_report) = get_quote(sigrl, ek_info.report, SGX_QUOTE_SIGN_TYPE, spid)?; validate_qe_report(&target_info, &qe_report)?; get_report_from_intel(mode, quote, &ias_key) diff --git a/modules/remote-attestation/src/ias_simulation.rs b/modules/remote-attestation/src/ias_simulation.rs index 43822933..11983b1a 100644 --- a/modules/remote-attestation/src/ias_simulation.rs +++ b/modules/remote-attestation/src/ias_simulation.rs @@ -1,9 +1,8 @@ use crate::errors::Error; use crate::ias_utils::{get_quote, init_quote, validate_qe_report, SGX_QUOTE_SIGN_TYPE}; -use attestation_report::{AttestationVerificationReport, EndorsedAttestationVerificationReport}; +use attestation_report::{AttestationVerificationReport, SignedAttestationVerificationReport}; use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; use crypto::Address; -use ecall_commands::{CreateReportInput, CreateReportResponse}; use enclave_api::EnclaveCommandAPI; use rsa::signature::{SignatureEncoding, Signer}; use store::transaction::CommitStore; @@ -11,22 +10,28 @@ use store::transaction::CommitStore; pub fn run_ias_ra_simulation, S: CommitStore>( enclave: &E, target_enclave_key: Address, - operator: Option
, advisory_ids: Vec, isv_enclave_quote_status: String, signing_key: rsa::pkcs1v15::SigningKey, signing_cert: Vec, -) -> Result { +) -> Result { let (target_info, _) = init_quote()?; - let CreateReportResponse { report } = enclave - .create_report(CreateReportInput { - target_info, - target_enclave_key, - operator, - }) - .map_err(Error::enclave_api)?; + let ek_info = enclave + .get_key_manager() + .load(target_enclave_key) + .map_err(|e| { + Error::key_manager( + format!("cannot load enclave key: {}", target_enclave_key), + e, + ) + })?; - let (quote, qe_report) = get_quote(vec![], report, SGX_QUOTE_SIGN_TYPE, Default::default())?; + let (quote, qe_report) = get_quote( + vec![], + ek_info.report, + SGX_QUOTE_SIGN_TYPE, + Default::default(), + )?; validate_qe_report(&target_info, &qe_report)?; create_simulate_avr( quote, @@ -43,7 +48,7 @@ fn create_simulate_avr( isv_enclave_quote_status: String, signing_key: rsa::pkcs1v15::SigningKey, signing_cert: Vec, -) -> Result { +) -> Result { let now = chrono::Utc::now(); // TODO more configurable via simulation command let avr = AttestationVerificationReport { @@ -67,7 +72,7 @@ fn create_simulate_avr( }; let avr_json = avr.to_canonical_json().unwrap(); let signature = signing_key.sign(avr_json.as_bytes()).to_vec(); - Ok(EndorsedAttestationVerificationReport { + Ok(SignedAttestationVerificationReport { avr: avr_json, signature, signing_cert, diff --git a/modules/remote-attestation/src/ias_utils.rs b/modules/remote-attestation/src/ias_utils.rs index 97e1e35c..c5793799 100644 --- a/modules/remote-attestation/src/ias_utils.rs +++ b/modules/remote-attestation/src/ias_utils.rs @@ -1,5 +1,5 @@ use crate::errors::Error; -use attestation_report::EndorsedAttestationVerificationReport; +use attestation_report::SignedAttestationVerificationReport; use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; use log::*; use rand::RngCore; @@ -51,7 +51,7 @@ impl IASMode { } } -pub(crate) fn init_quote() -> Result<(sgx_target_info_t, sgx_epid_group_id_t), Error> { +pub fn init_quote() -> Result<(sgx_target_info_t, sgx_epid_group_id_t), Error> { let mut target_info = sgx_target_info_t::default(); let mut epid_group_id = sgx_epid_group_id_t::default(); match unsafe { sgx_init_quote(&mut target_info, &mut epid_group_id) } { @@ -174,7 +174,7 @@ pub(crate) fn get_report_from_intel( mode: IASMode, quote: Vec, ias_key: &str, -) -> Result { +) -> Result { info!("using IAS mode: {}", mode); let config = make_ias_client_config(); let encoded_quote = Base64Std.encode("e[..]); @@ -207,7 +207,7 @@ pub(crate) fn get_report_from_intel( parse_response_attn_report(&plaintext) } -pub(crate) fn validate_qe_report( +pub fn validate_qe_report( target_info: &sgx_target_info_t, qe_report: &sgx_report_t, ) -> Result<(), Error> { @@ -223,7 +223,7 @@ pub(crate) fn validate_qe_report( Ok(()) } -fn parse_response_attn_report(resp: &[u8]) -> Result { +fn parse_response_attn_report(resp: &[u8]) -> Result { trace!("parse_response_attn_report"); let mut headers = [httparse::EMPTY_HEADER; 16]; let mut respp = httparse::Response::new(&mut headers); @@ -305,7 +305,7 @@ fn parse_response_attn_report(resp: &[u8]) -> Result for Mrenclave { } } +impl From for sgx_measurement_t { + fn from(mrenclave: Mrenclave) -> Self { + sgx_measurement_t { m: mrenclave.0 } + } +} + impl From<[u8; SGX_HASH_SIZE]> for Mrenclave { fn from(bytes: [u8; SGX_HASH_SIZE]) -> Self { Self(bytes) @@ -47,7 +53,7 @@ impl Mrenclave { pub fn to_hex_string(&self) -> String { format!("0x{}", hex::encode(self.0)) } - pub fn from_hex_string(&self, s: &str) -> Result { + pub fn from_hex_string(s: &str) -> Result { let s = s.strip_prefix("0x").unwrap_or(s); let mut bytes = [0u8; SGX_HASH_SIZE]; hex::decode_to_slice(s, &mut bytes)?; diff --git a/modules/types/src/transmuter.rs b/modules/types/src/transmuter.rs new file mode 100644 index 00000000..000adddc --- /dev/null +++ b/modules/types/src/transmuter.rs @@ -0,0 +1,59 @@ +use crate::prelude::*; +use alloc::string::ToString; +use core::marker::PhantomData; +use serde::Deserialize; +use serde_with::{DeserializeAs, SerializeAs}; +use sgx_types::marker::ContiguousMemory; + +pub struct BytesTransmuter(PhantomData); + +impl SerializeAs for BytesTransmuter +where + [(); core::mem::size_of::()]:, + T: ContiguousMemory, +{ + fn serialize_as(source: &T, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_bytes(&serialize_bytes(source)) + } +} + +impl<'de, T> DeserializeAs<'de, T> for BytesTransmuter +where + [(); core::mem::size_of::()]:, + T: ContiguousMemory, +{ + fn deserialize_as(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let bz = <&[u8]>::deserialize(deserializer).map_err(serde::de::Error::custom)?; + deserialize_bytes(bz).map_err(|(len, size)| { + serde::de::Error::invalid_length(len, &size.to_string().as_str()) + }) + } +} + +pub fn serialize_bytes(source: &T) -> [u8; core::mem::size_of::()] +where + [(); core::mem::size_of::()]:, + T: ContiguousMemory, +{ + unsafe { core::mem::transmute_copy::<_, [u8; core::mem::size_of::()]>(source) } +} + +pub fn deserialize_bytes(bz: &[u8]) -> Result +where + [(); core::mem::size_of::()]:, + T: ContiguousMemory, +{ + let mut array = [0; core::mem::size_of::()]; + if bz.len() == array.len() { + array.copy_from_slice(bz); + Ok(unsafe { core::mem::transmute_copy(&array) }) + } else { + Err((bz.len(), array.len())) + } +} diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index d288af86..3cbe5656 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -70,35 +70,7 @@ mod tests { } } - #[test] - fn test_elc_state_verification() { - let tmp_dir = TempDir::new().unwrap(); - let home = tmp_dir.path().to_str().unwrap().to_string(); - host::set_environment(Environment::new( - home.into(), - Arc::new(RwLock::new(HostStore::Memory(MemStore::default()))), - )) - .unwrap(); - - let env = host::get_environment().unwrap(); - let km = EnclaveKeyManager::new(&env.home).unwrap(); - let enclave = Enclave::create(ENCLAVE_FILE, true, km, env.store.clone()).unwrap(); - - match std::env::var(ENV_SETUP_NODES).map(|v| v.to_lowercase()) { - Ok(v) if v == "false" => run_test(&enclave).unwrap(), - _ => run_binary_channel_test(&ELCStateVerificationTest { enclave }).unwrap(), - } - } - - fn run_test(enclave: &Enclave) -> Result<(), anyhow::Error> { - env_logger::init(); - let rt = Arc::new(TokioRuntime::new()?); - let rly = config::create_relayer(rt).unwrap(); - verify(rly, enclave) - } - - fn verify( - mut rly: Relayer, + fn test_remote_attestation( enclave: &Enclave, ) -> Result<(), anyhow::Error> { if cfg!(feature = "sgx-sw") { @@ -107,21 +79,33 @@ mod tests { info!("this test is running in HW mode"); } - let signer = match enclave.generate_enclave_key(GenerateEnclaveKeyInput) { + let (target_info, _) = remote_attestation::init_quote()?; + let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; + let op_ek_addr = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { + operator: Some(operator), + target_info, + }) { + Ok(res) => res.pub_key.as_address(), + Err(e) => { + bail!("failed to generate an enclave key: {:?}!", e); + } + }; + let ek_addr = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { + operator: None, + target_info, + }) { Ok(res) => res.pub_key.as_address(), Err(e) => { bail!("failed to generate an enclave key: {:?}!", e); } }; - let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; #[cfg(not(feature = "sgx-sw"))] { use remote_attestation::ias::run_ias_ra; let res = match run_ias_ra( enclave, - signer, - Some(operator), + op_ek_addr, remote_attestation::IASMode::Production, std::env::var("SPID")?, std::env::var("IAS_KEY")?, @@ -132,24 +116,23 @@ mod tests { } }; let report_data = res.get_avr()?.parse_quote()?.report_data(); - assert_eq!(report_data.enclave_key(), signer); + assert_eq!(report_data.enclave_key(), op_ek_addr); assert_eq!(report_data.operator(), operator); let res = match run_ias_ra( enclave, - signer, - None, + ek_addr, remote_attestation::IASMode::Production, std::env::var("SPID")?, std::env::var("IAS_KEY")?, ) { Ok(res) => res, Err(e) => { - bail!("IAS Remote Attestation Failed {:?}!", e); + panic!("IAS Remote Attestation Failed {:?}!", e); } }; let report_data = res.get_avr()?.parse_quote()?.report_data(); - assert_eq!(report_data.enclave_key(), signer); + assert_eq!(report_data.enclave_key(), ek_addr); assert!(report_data.operator().is_zero()); } #[cfg(feature = "sgx-sw")] @@ -157,10 +140,10 @@ mod tests { use remote_attestation::ias_simulation::run_ias_ra_simulation; use remote_attestation::rsa::{pkcs1v15::SigningKey, rand_core::OsRng}; use remote_attestation::sha2::Sha256; + let res = match run_ias_ra_simulation( enclave, - signer, - Some(operator), + op_ek_addr, vec![], "OK".to_string(), SigningKey::::random(&mut OsRng, 3072)?, @@ -172,13 +155,12 @@ mod tests { } }; let report_data = res.parse_quote()?.report_data(); - assert_eq!(report_data.enclave_key(), signer); + assert_eq!(report_data.enclave_key(), op_ek_addr); assert_eq!(report_data.operator(), operator); let res = match run_ias_ra_simulation( enclave, - signer, - None, + ek_addr, vec![], "OK".to_string(), SigningKey::::random(&mut OsRng, 3072)?, @@ -190,10 +172,58 @@ mod tests { } }; let report_data = res.parse_quote()?.report_data(); - assert_eq!(report_data.enclave_key(), signer); + assert_eq!(report_data.enclave_key(), ek_addr); assert!(report_data.operator().is_zero()); } + Ok(()) + } + + #[test] + fn test_lcp() { + let tmp_dir = TempDir::new().unwrap(); + let home = tmp_dir.path().to_str().unwrap().to_string(); + host::set_environment(Environment::new( + home.into(), + Arc::new(RwLock::new(HostStore::Memory(MemStore::default()))), + )) + .unwrap(); + + let env = host::get_environment().unwrap(); + let km = EnclaveKeyManager::new(&env.home).unwrap(); + let enclave = Enclave::create(ENCLAVE_FILE, true, km, env.store.clone()).unwrap(); + + test_remote_attestation(&enclave).unwrap(); + + match std::env::var(ENV_SETUP_NODES).map(|v| v.to_lowercase()) { + Ok(v) if v == "false" => run_test(&enclave).unwrap(), + _ => run_binary_channel_test(&ELCStateVerificationTest { enclave }).unwrap(), + } + } + + fn run_test(enclave: &Enclave) -> Result<(), anyhow::Error> { + env_logger::init(); + let rt = Arc::new(TokioRuntime::new()?); + let rly = config::create_relayer(rt).unwrap(); + verify(rly, enclave) + } + + fn verify( + mut rly: Relayer, + enclave: &Enclave, + ) -> Result<(), anyhow::Error> { + let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; + let (target_info, _) = remote_attestation::init_quote()?; + let signer = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { + operator: Some(operator), + target_info, + }) { + Ok(res) => res.pub_key.as_address(), + Err(e) => { + bail!("failed to generate an enclave key: {:?}!", e); + } + }; + let (client_id, last_height) = { // XXX use non-latest height here let initial_height = rly.query_latest_height()?.decrement()?.decrement()?;