From 19ef29c95b993c7b9d47913297aff3d00a1a2e7c Mon Sep 17 00:00:00 2001 From: "Bill.W" <0xbillw@gmail.com> Date: Wed, 8 May 2024 14:41:01 +0000 Subject: [PATCH] refactor: change the `measurement` of `ceseal` to its corresponding hash value (H256 type) and improve the display of version information --- Cargo.lock | 1 + crates/ces-types/Cargo.toml | 5 +- crates/ces-types/src/attestation.rs | 64 +++++++++++++++---- crates/ces-types/src/attestation/legacy.rs | 22 +++---- crates/cestory/pal/src/lib.rs | 15 ++--- crates/cestory/src/ceseal_service.rs | 23 ++++++- crates/cestory/src/lib.rs | 14 +++- crates/cestory/src/storage.rs | 12 ++-- pallets/tee-worker/src/lib.rs | 9 +-- standalone/teeworker/ceseal/Cargo.lock | 1 + standalone/teeworker/ceseal/src/main.rs | 5 +- .../teeworker/ceseal/src/pal_gramine.rs | 41 +++++------- 12 files changed, 132 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7f480f6..0e780890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1576,6 +1576,7 @@ dependencies = [ "chrono", "frame-support", "hex", + "log", "parity-scale-codec", "scale-info", "serde", diff --git a/crates/ces-types/Cargo.toml b/crates/ces-types/Cargo.toml index e026aeb2..c44841ae 100644 --- a/crates/ces-types/Cargo.toml +++ b/crates/ces-types/Cargo.toml @@ -7,10 +7,11 @@ edition = "2021" [dependencies] chrono = { workspace = true } hex = { workspace = true, features = ["alloc"] } -serde = { workspace = true, optional = true } -serde_json = { workspace = true, features = ["alloc"] } +log ={ workspace = true } parity-scale-codec = { workspace = true, features = ["full"] } scale-info = { workspace = true, features = ["derive"] } +serde = { workspace = true, optional = true } +serde_json = { workspace = true, features = ["alloc"] } sp-core = { workspace = true } sp-std = { workspace = true } diff --git a/crates/ces-types/src/attestation.rs b/crates/ces-types/src/attestation.rs index e7740a0f..277f6d30 100644 --- a/crates/ces-types/src/attestation.rs +++ b/crates/ces-types/src/attestation.rs @@ -13,6 +13,7 @@ pub mod ias_quote_consts { use ias_quote_consts::*; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; +use sp_core::H256; use sp_std::vec::Vec; #[cfg(feature = "enable_serde")] @@ -49,7 +50,45 @@ pub enum Error { pub struct ConfidentialReport { pub confidence_level: u8, pub provider: Option, - pub runtime_hash: Vec, + pub measurement_hash: H256, +} + +fn fixed_measurement(mr_enclave: &[u8], isv_prod_id: &[u8], isv_svn: &[u8], mr_signer: &[u8]) -> Vec { + let mut data = Vec::new(); + data.extend_from_slice(mr_enclave); + data.extend_from_slice(isv_prod_id); + data.extend_from_slice(isv_svn); + data.extend_from_slice(mr_signer); + data +} + +#[cfg(feature = "full_crypto")] +fn fixed_measurement_hash(data: &[u8]) -> H256 { + H256(sp_core::blake2_256(data)) +} + +#[cfg(not(feature = "full_crypto"))] +fn fixed_measurement_hash(data: &[u8]) -> H256 { + log::error!("The measurement hash must be in SGX enviroment with \"full_crypto\" feature, now return zero"); + H256::default() +} + +#[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] +pub struct ExtendMeasurement { + pub mr_enclave: [u8; 32], + pub mr_signer: [u8; 32], + pub isv_prod_id: [u8; 2], + pub isv_svn: [u8; 2], +} + +impl ExtendMeasurement { + pub fn measurement(&self) -> Vec { + fixed_measurement(&self.mr_enclave, &self.isv_prod_id, &self.isv_svn, &self.mr_signer) + } + + pub fn measurement_hash(&self) -> H256 { + fixed_measurement_hash(&self.measurement()[..]) + } } #[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] @@ -121,13 +160,12 @@ impl IasFields { )) } - pub fn extend_mrenclave(&self) -> Vec { - let mut t_mrenclave = Vec::new(); - t_mrenclave.extend_from_slice(&self.mr_enclave); - t_mrenclave.extend_from_slice(&self.isv_prod_id); - t_mrenclave.extend_from_slice(&self.isv_svn); - t_mrenclave.extend_from_slice(&self.mr_signer); - t_mrenclave + pub fn measurement(&self) -> Vec { + fixed_measurement(&self.mr_enclave, &self.isv_prod_id, &self.isv_svn, &self.mr_signer) + } + + pub fn measurement_hash(&self) -> H256 { + fixed_measurement_hash(&self.measurement()[..]) } } @@ -136,7 +174,7 @@ pub fn validate( user_data_hash: &[u8; 32], now: u64, verify_ceseal_hash: bool, - ceseal_bin_allowlist: Vec>, + ceseal_bin_allowlist: Vec, opt_out_enabled: bool, ) -> Result { match attestation { @@ -151,7 +189,7 @@ pub fn validate( ), None => if opt_out_enabled { - Ok(ConfidentialReport { provider: None, runtime_hash: Vec::new(), confidence_level: 128u8 }) + Ok(ConfidentialReport { provider: None, measurement_hash: Default::default(), confidence_level: 128u8 }) } else { Err(Error::NoneAttestationDisabled) }, @@ -165,7 +203,7 @@ pub fn validate_ias_report( raw_signing_cert: &[u8], now: u64, verify_ceseal_hash: bool, - ceseal_bin_allowlist: Vec>, + ceseal_bin_allowlist: Vec, ) -> Result { // Validate report sgx_attestation::ias::verify_signature(report, signature, raw_signing_cert, core::time::Duration::from_secs(now)) @@ -174,7 +212,7 @@ pub fn validate_ias_report( let (ias_fields, report_timestamp) = IasFields::from_ias_report(report)?; // Validate Ceseal - let ceseal_hash = ias_fields.extend_mrenclave(); + let ceseal_hash = ias_fields.measurement_hash(); if verify_ceseal_hash && !ceseal_bin_allowlist.contains(&ceseal_hash) { return Err(Error::CesealRejected) } @@ -192,7 +230,7 @@ pub fn validate_ias_report( // Check the following fields Ok(ConfidentialReport { provider: Some(AttestationProvider::Ias), - runtime_hash: ceseal_hash, + measurement_hash: ceseal_hash, confidence_level: ias_fields.confidence_level, }) } diff --git a/crates/ces-types/src/attestation/legacy.rs b/crates/ces-types/src/attestation/legacy.rs index ca5bf3d4..a8e37734 100644 --- a/crates/ces-types/src/attestation/legacy.rs +++ b/crates/ces-types/src/attestation/legacy.rs @@ -1,6 +1,7 @@ use super::{ias_quote_consts::*, Error}; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; +use sp_core::H256; use sp_std::vec::Vec; #[derive(Encode, Decode, TypeInfo, Debug, Clone, PartialEq, Eq)] @@ -15,7 +16,7 @@ pub trait AttestationValidator { user_data_hash: &[u8; 32], now: u64, verify_ceseal_hash: bool, - ceseal_bin_allowlist: Vec>, + ceseal_bin_allowlist: Vec, ) -> Result; } @@ -86,13 +87,12 @@ impl IasFields { )) } - pub fn extend_mrenclave(&self) -> Vec { - let mut t_mrenclave = Vec::new(); - t_mrenclave.extend_from_slice(&self.mr_enclave); - t_mrenclave.extend_from_slice(&self.isv_prod_id); - t_mrenclave.extend_from_slice(&self.isv_svn); - t_mrenclave.extend_from_slice(&self.mr_signer); - t_mrenclave + pub fn measurement(&self) -> Vec { + super::fixed_measurement(&self.mr_enclave, &self.isv_prod_id, &self.isv_svn, &self.mr_signer) + } + + pub fn measurement_hash(&self) -> H256 { + super::fixed_measurement_hash(&self.measurement()[..]) } } @@ -104,7 +104,7 @@ impl AttestationValidator for IasValidator { user_data_hash: &[u8; 32], now: u64, verify_ceseal: bool, - ceseal_bin_allowlist: Vec>, + ceseal_bin_allowlist: Vec, ) -> Result { let fields = match attestation { Attestation::SgxIas { ra_report, signature, raw_signing_cert } => @@ -125,7 +125,7 @@ pub fn validate_ias_report( raw_signing_cert: &[u8], now: u64, verify_ceseal: bool, - ceseal_bin_allowlist: Vec>, + ceseal_bin_allowlist: Vec, ) -> Result { // Validate report sgx_attestation::ias::verify_signature(report, signature, raw_signing_cert, core::time::Duration::from_secs(now)) @@ -135,7 +135,7 @@ pub fn validate_ias_report( // Validate Ceseal if verify_ceseal { - let t_mrenclave = ias_fields.extend_mrenclave(); + let t_mrenclave = ias_fields.measurement_hash(); if !ceseal_bin_allowlist.contains(&t_mrenclave) { return Err(Error::CesealRejected) } diff --git a/crates/cestory/pal/src/lib.rs b/crates/cestory/pal/src/lib.rs index 6ef5fc04..966b453e 100644 --- a/crates/cestory/pal/src/lib.rs +++ b/crates/cestory/pal/src/lib.rs @@ -1,11 +1,10 @@ //! Platform abstraction layer for Trusted Execution Environments -use std::fmt::Debug; -use std::path::Path; -use core::time::Duration; - use ces_types::AttestationProvider; +use core::time::Duration; +use std::{fmt::Debug, path::Path}; +pub use ces_types::attestation::ExtendMeasurement; pub use cestory_api::crpc::MemoryUsage; pub trait ErrorType: Debug + Into {} @@ -28,7 +27,8 @@ pub trait RA { timeout: Duration, ) -> Result, Self::Error>; fn quote_test(&self, provider: Option) -> Result<(), Self::Error>; - fn measurement(&self) -> Option>; + fn mr_enclave(&self) -> Option>; + fn extend_measurement(&self) -> Result; } pub trait MemoryStats { @@ -51,8 +51,5 @@ pub trait AppInfo { fn app_version() -> AppVersion; } -pub trait Platform: - Sealing + RA + Machine + MemoryStats + AppInfo + Clone + Send + 'static -{ -} +pub trait Platform: Sealing + RA + Machine + MemoryStats + AppInfo + Clone + Send + 'static {} impl Platform for T {} diff --git a/crates/cestory/src/ceseal_service.rs b/crates/cestory/src/ceseal_service.rs index e692ef08..25f5515e 100644 --- a/crates/cestory/src/ceseal_service.rs +++ b/crates/cestory/src/ceseal_service.rs @@ -344,7 +344,7 @@ impl CesealApi for RpcSe report_data: [0; 64], confidence_level: 0, }; - ias_fields.extend_mrenclave() + ias_fields.measurement_hash() }; let runtime_state = cestory.runtime_state()?; let my_runtime_timestamp = runtime_state @@ -358,7 +358,7 @@ impl CesealApi for RpcSe AttestationReport::SgxIas { ra_report, signature: _, raw_signing_cert: _ } => { let (ias_fields, _) = IasFields::from_ias_report(&ra_report).map_err(|_| from_display("Invalid client RA report"))?; - ias_fields.extend_mrenclave() + ias_fields.measurement_hash() }, }; let req_runtime_timestamp = runtime_state @@ -877,6 +877,25 @@ impl Ceseal { self.args.ra_timeout, self.args.ra_max_retries, )?; + { + let mut encoded_report = &report.encoded_report[..]; + let report: Option = Decode::decode(&mut encoded_report)?; + if let Some(report) = report { + match report { + AttestationReport::SgxIas { ra_report, .. } => { + match IasFields::from_ias_report(&ra_report[..]) { + Ok((ias_fields, _)) => { + info!("measurement :{}", hex::encode(ias_fields.measurement())); + info!("measurement hash :{}", ias_fields.measurement_hash()); + }, + Err(e) => { + error!("deserial ias report to IasFields failed: {:?}", e); + }, + } + }, + } + } + } cached_resp.attestation = Some(report); } diff --git a/crates/cestory/src/lib.rs b/crates/cestory/src/lib.rs index 1d8e9cb2..b1148ab7 100644 --- a/crates/cestory/src/lib.rs +++ b/crates/cestory/src/lib.rs @@ -490,8 +490,18 @@ impl Ceseal

{ let chain_storage = &self.runtime_state.as_ref().expect("BUG: no runtime state").chain_storage.read(); let min_version = chain_storage.minimum_ceseal_version(); - let measurement = self.platform.measurement().unwrap_or_else(|| vec![0; 32]); - let in_whitelist = chain_storage.is_ceseal_bin_in_whitelist(&measurement); + let in_whitelist: bool; + if cfg!(feature = "verify-cesealbin") { + in_whitelist = match self.platform.extend_measurement() { + Ok(em) => chain_storage.is_ceseal_bin_in_whitelist(&em.measurement_hash()), + Err(_) => { + warn!("The verify-cesealbin feature enabled, but not in SGX enviroment, ignore whitelist check"); + true + }, + }; + } else { + in_whitelist = true; + } if (ver.major, ver.minor, ver.patch) < min_version && !in_whitelist { error!("This ceseal is outdated. Please update to the latest version."); diff --git a/crates/cestory/src/storage.rs b/crates/cestory/src/storage.rs index 419e2b78..bece90e1 100644 --- a/crates/cestory/src/storage.rs +++ b/crates/cestory/src/storage.rs @@ -36,6 +36,7 @@ mod storage_ext { use log::error; use parity_scale_codec::{Decode, Error}; use serde::{Deserialize, Serialize}; + use sp_core::H256; use sp_state_machine::{Ext, OverlayedChanges}; #[derive(Serialize, Deserialize, Default)] @@ -141,7 +142,7 @@ mod storage_ext { } /// Return `None` if given ceseal hash is not allowed on-chain - pub(crate) fn get_ceseal_bin_added_at(&self, runtime_hash: &[u8]) -> Option { + pub(crate) fn get_ceseal_bin_added_at(&self, runtime_hash: &H256) -> Option { self.execute_with(|| pallet_tee_worker::CesealBinAddedAt::::get(runtime_hash)) } @@ -165,14 +166,9 @@ mod storage_ext { self.execute_with(pallet_tee_worker::MinimumCesealVersion::::get) } - pub(crate) fn is_ceseal_bin_in_whitelist(&self, measurement: &[u8]) -> bool { + pub(crate) fn is_ceseal_bin_in_whitelist(&self, measurement: &H256) -> bool { let list = self.execute_with(pallet_tee_worker::CesealBinAllowList::::get); - for hash in list.iter() { - if hash.starts_with(measurement) { - return true - } - } - false + list.contains(measurement) } } } diff --git a/pallets/tee-worker/src/lib.rs b/pallets/tee-worker/src/lib.rs index b284c92f..43014024 100644 --- a/pallets/tee-worker/src/lib.rs +++ b/pallets/tee-worker/src/lib.rs @@ -47,6 +47,7 @@ pub mod pallet { use codec::{Decode, Encode}; use frame_support::dispatch::DispatchResult; use scale_info::TypeInfo; + use sp_core::H256; use ces_pallet_mq::MessageOriginInfo; use ces_types::{ @@ -238,11 +239,11 @@ pub mod pallet { /// Only ceseal within the list can register. #[pallet::storage] #[pallet::getter(fn ceseal_bin_allowlist)] - pub type CesealBinAllowList = StorageValue<_, Vec>, ValueQuery>; + pub type CesealBinAllowList = StorageValue<_, Vec, ValueQuery>; /// The effective height of ceseal binary #[pallet::storage] - pub type CesealBinAddedAt = StorageMap<_, Twox64Concat, Vec, BlockNumberFor>; + pub type CesealBinAddedAt = StorageMap<_, Twox64Concat, H256, BlockNumberFor>; /// Mapping from worker pubkey to CESS Network identity #[pallet::storage] @@ -673,7 +674,7 @@ pub mod pallet { /// Can only be called by `GovernanceOrigin`. #[pallet::call_index(19)] #[pallet::weight({0})] - pub fn add_ceseal(origin: OriginFor, ceseal_hash: Vec) -> DispatchResult { + pub fn add_ceseal(origin: OriginFor, ceseal_hash: H256) -> DispatchResult { T::GovernanceOrigin::ensure_origin(origin)?; let mut allowlist = CesealBinAllowList::::get(); @@ -693,7 +694,7 @@ pub mod pallet { /// Can only be called by `GovernanceOrigin`. #[pallet::call_index(110)] #[pallet::weight({0})] - pub fn remove_ceseal(origin: OriginFor, ceseal_hash: Vec) -> DispatchResult { + pub fn remove_ceseal(origin: OriginFor, ceseal_hash: H256) -> DispatchResult { T::GovernanceOrigin::ensure_origin(origin)?; let mut allowlist = CesealBinAllowList::::get(); diff --git a/standalone/teeworker/ceseal/Cargo.lock b/standalone/teeworker/ceseal/Cargo.lock index 58194a29..01f012e1 100644 --- a/standalone/teeworker/ceseal/Cargo.lock +++ b/standalone/teeworker/ceseal/Cargo.lock @@ -913,6 +913,7 @@ dependencies = [ "ces-mq", "chrono", "hex", + "log", "parity-scale-codec", "scale-info", "serde", diff --git a/standalone/teeworker/ceseal/src/main.rs b/standalone/teeworker/ceseal/src/main.rs index 4b50e1fa..bbe84f77 100644 --- a/standalone/teeworker/ceseal/src/main.rs +++ b/standalone/teeworker/ceseal/src/main.rs @@ -20,7 +20,7 @@ const VERSION: &str = const_str::format!( ); #[derive(Parser, Debug, Clone)] -#[clap(about = "The CESS TEE worker app.", version, author)] +#[clap(about = "The CESS TEE worker app.", version = VERSION, author)] struct Args { /// Number of CPU cores to be used for PODR2 thread-pool. #[arg(short, long)] @@ -106,9 +106,8 @@ fn main() -> Result<()> { let args = Args::parse(); match args.command { Some(Commands::Version) => { - use hex_fmt::HexFmt; if let Some(em) = pal_gramine::get_extend_measurement().unwrap() { - println!("{} {:?}", VERSION, HexFmt(em.measurement())); + println!("{} {:?}", VERSION, em.measurement_hash()); } else { println!("{} [No measurement in non-SGX environments]", VERSION); } diff --git a/standalone/teeworker/ceseal/src/pal_gramine.rs b/standalone/teeworker/ceseal/src/pal_gramine.rs index f2021f70..efae73e0 100644 --- a/standalone/teeworker/ceseal/src/pal_gramine.rs +++ b/standalone/teeworker/ceseal/src/pal_gramine.rs @@ -1,16 +1,16 @@ +use crate::ias; use anyhow::anyhow; use ces_allocator::StatSizeAllocator; -use cestory_pal::{AppInfo, AppVersion, Machine, MemoryStats, MemoryUsage, Sealing, RA}; +use ces_types::AttestationProvider; +use cestory_pal::{ + AppInfo, AppVersion, ExtendMeasurement, Machine, MemoryStats, MemoryUsage, Sealing, RA, +}; use parity_scale_codec::Encode; use std::alloc::System; use std::io::ErrorKind; use std::time::Duration; use tracing::info; -use crate::ias; - -use ces_types::AttestationProvider; - #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] pub(crate) struct GraminePlatform; @@ -75,7 +75,7 @@ impl RA for GraminePlatform { } } - fn measurement(&self) -> Option> { + fn mr_enclave(&self) -> Option> { if is_gramine() { sgx_api_lite::target_info() .map(|info| info.mr_enclave.m.to_vec()) @@ -84,11 +84,18 @@ impl RA for GraminePlatform { None } } + + fn extend_measurement(&self) -> Result { + if is_gramine() { + Ok(get_extend_measurement()?.expect("must in gramine enviroment")) + } else { + Err(anyhow!("no measurement in native mode")) + } + } } impl Machine for GraminePlatform { fn machine_id(&self) -> Vec { - // TODO.kevin.must vec![] } @@ -185,31 +192,13 @@ pub(crate) fn print_target_info() { println!("isv_svn : 0x{:?}", HexFmt(em.isv_svn)); println!("isv_prod_id : 0x{:?}", HexFmt(em.isv_prod_id)); println!("measurement : 0x{:?}", HexFmt(em.measurement())); + println!("measurement hash : {:?}", em.measurement_hash()); } else { println!("Running in Native mode"); } println!("git revision: {}", env!("VERGEN_GIT_SHA")); } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExtendMeasurement { - pub mr_enclave: [u8; 32], - pub mr_signer: [u8; 32], - pub isv_prod_id: [u8; 2], - pub isv_svn: [u8; 2], -} - -impl ExtendMeasurement { - pub fn measurement(&self) -> Vec { - let mut data = Vec::new(); - data.extend_from_slice(&self.mr_enclave); - data.extend_from_slice(&self.isv_prod_id); - data.extend_from_slice(&self.isv_svn); - data.extend_from_slice(&self.mr_signer); - data - } -} - pub(crate) fn get_extend_measurement() -> anyhow::Result> { if !is_gramine() { return Ok(None);