From 33db450c301ac4f9275305c7ac108d952a85579f Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Mon, 31 Jul 2023 15:24:41 +0200 Subject: [PATCH] [tls-ra] provision light-client state too --- .../light-client/src/concurrent_access.rs | 2 +- core/parentchain/light-client/src/io.rs | 12 ++-- core/parentchain/light-client/src/lib.rs | 8 ++- .../src/mocks/validator_mock_seal.rs | 4 +- .../src/initialization/global_components.rs | 8 ++- enclave-runtime/src/tls_ra/mocks.rs | 13 ++++- enclave-runtime/src/tls_ra/seal_handler.rs | 56 +++++++++++-------- enclave-runtime/src/tls_ra/tests.rs | 12 +++- enclave-runtime/src/tls_ra/tls_ra_client.rs | 19 ++++++- enclave-runtime/src/tls_ra/tls_ra_server.rs | 26 ++++++++- 10 files changed, 119 insertions(+), 41 deletions(-) diff --git a/core/parentchain/light-client/src/concurrent_access.rs b/core/parentchain/light-client/src/concurrent_access.rs index ac61f60f4e..590e4b7b99 100644 --- a/core/parentchain/light-client/src/concurrent_access.rs +++ b/core/parentchain/light-client/src/concurrent_access.rs @@ -85,7 +85,7 @@ where Validator: ValidatorTrait + LightClientState + ExtrinsicSenderTrait, - Seal: LightClientSealing>, + Seal: LightClientSealing>, ParentchainBlock: ParentchainBlockTrait, NumberFor: BlockNumberOps, { diff --git a/core/parentchain/light-client/src/io.rs b/core/parentchain/light-client/src/io.rs index 74476a7a7a..9937729c15 100644 --- a/core/parentchain/light-client/src/io.rs +++ b/core/parentchain/light-client/src/io.rs @@ -87,9 +87,11 @@ impl LightClientStateSeal { } } -impl LightClientSealing +impl LightClientSealing for LightClientStateSeal { + type LightClientState = LightClientState; + fn seal(&self, unsealed: &LightClientState) -> Result<()> { trace!("Backup light client state"); @@ -128,9 +130,11 @@ impl LightClientStateSealSync { } } -impl LightClientSealing +impl LightClientSealing for LightClientStateSealSync { + type LightClientState = LightClientState; + fn seal(&self, unsealed: &LightClientState) -> Result<()> { let _lock = self._rw_lock.write().map_err(|_| Error::PoisonedLock)?; self.seal.seal(unsealed) @@ -161,7 +165,7 @@ where B: Block, NumberFor: finality_grandpa::BlockNumberOps, OCallApi: EnclaveOnChainOCallApi, - LightClientSeal: LightClientSealing>, + LightClientSeal: LightClientSealing>, { check_validator_set_proof::( params.genesis_header.state_root(), @@ -210,7 +214,7 @@ where B: Block, NumberFor: finality_grandpa::BlockNumberOps, OCallApi: EnclaveOnChainOCallApi, - LightClientSeal: LightClientSealing>, + LightClientSeal: LightClientSealing>, { if !seal.exists() { info!("[Enclave] ChainRelay DB not found, creating new! {}", seal.path().display()); diff --git a/core/parentchain/light-client/src/lib.rs b/core/parentchain/light-client/src/lib.rs index dda3cd557b..29f235ab82 100644 --- a/core/parentchain/light-client/src/lib.rs +++ b/core/parentchain/light-client/src/lib.rs @@ -95,9 +95,11 @@ pub trait LightClientState { fn penultimate_finalized_block_header(&self) -> Result; } -pub trait LightClientSealing { - fn seal(&self, state: &LightClientState) -> Result<(), Error>; - fn unseal(&self) -> Result; +pub trait LightClientSealing { + type LightClientState; + + fn seal(&self, state: &Self::LightClientState) -> Result<(), Error>; + fn unseal(&self) -> Result; fn exists(&self) -> bool; fn path(&self) -> &Path; } diff --git a/core/parentchain/light-client/src/mocks/validator_mock_seal.rs b/core/parentchain/light-client/src/mocks/validator_mock_seal.rs index 6a5f895bd3..4c7e4f25d3 100644 --- a/core/parentchain/light-client/src/mocks/validator_mock_seal.rs +++ b/core/parentchain/light-client/src/mocks/validator_mock_seal.rs @@ -40,7 +40,9 @@ impl Default for LightValidationStateSealMock { } } -impl LightClientSealing> for LightValidationStateSealMock { +impl LightClientSealing for LightValidationStateSealMock { + type LightClientState = LightValidationState; + fn unseal(&self) -> Result, Error> { Ok(LightValidationState::new(RelayState::new( ParentchainHeaderBuilder::default().build(), diff --git a/enclave-runtime/src/initialization/global_components.rs b/enclave-runtime/src/initialization/global_components.rs index 71ca1c47e5..67934d926b 100644 --- a/enclave-runtime/src/initialization/global_components.rs +++ b/enclave-runtime/src/initialization/global_components.rs @@ -215,8 +215,12 @@ pub type EnclaveSidechainBlockImportQueueWorker = BlockImportQueueWorker< EnclaveSidechainBlockImportQueue, EnclaveSidechainBlockSyncer, >; -pub type EnclaveSealHandler = - SealHandler; +pub type EnclaveSealHandler = SealHandler< + EnclaveShieldingKeyRepository, + EnclaveStateKeyRepository, + EnclaveStateHandler, + EnclaveLightClientSeal, +>; pub type EnclaveOffchainWorkerExecutor = itc_offchain_worker_executor::executor::Executor< ParentchainBlock, EnclaveTopPoolAuthor, diff --git a/enclave-runtime/src/tls_ra/mocks.rs b/enclave-runtime/src/tls_ra/mocks.rs index 2a918f48e0..e7f6900a0f 100644 --- a/enclave-runtime/src/tls_ra/mocks.rs +++ b/enclave-runtime/src/tls_ra/mocks.rs @@ -28,6 +28,7 @@ pub struct SealHandlerMock { pub shielding_key: Arc>>, pub state_key: Arc>>, pub state: Arc>>, + pub light_client_state: Arc>>, } impl SealHandlerMock { @@ -35,8 +36,9 @@ impl SealHandlerMock { shielding_key: Arc>>, state_key: Arc>>, state: Arc>>, + light_client_state: Arc>>, ) -> Self { - Self { shielding_key, state_key, state } + Self { shielding_key, state_key, state, light_client_state } } } @@ -59,6 +61,11 @@ impl SealStateAndKeys for SealHandlerMock { fn seal_new_empty_state(&self, _shard: &ShardIdentifier) -> EnclaveResult<()> { Ok(()) } + + fn seal_light_client_state(&self, bytes: &[u8]) -> EnclaveResult<()> { + *self.light_client_state.write().unwrap() = bytes.to_vec(); + Ok(()) + } } impl UnsealStateAndKeys for SealHandlerMock { @@ -73,4 +80,8 @@ impl UnsealStateAndKeys for SealHandlerMock { fn unseal_state(&self, _shard: &ShardIdentifier) -> EnclaveResult> { Ok(self.state.read().unwrap().clone()) } + + fn unseal_light_client_state(&self) -> EnclaveResult> { + Ok(self.light_client_state.read().unwrap().clone()) + } } diff --git a/enclave-runtime/src/tls_ra/seal_handler.rs b/enclave-runtime/src/tls_ra/seal_handler.rs index e00aa95ef4..bb7828dd57 100644 --- a/enclave-runtime/src/tls_ra/seal_handler.rs +++ b/enclave-runtime/src/tls_ra/seal_handler.rs @@ -35,33 +35,23 @@ use std::{sync::Arc, vec::Vec}; /// Handles the sealing and unsealing of the shielding key, state key and the state. #[derive(Default)] -pub struct SealHandler -where - ShieldingKeyRepository: AccessKey + MutateKey, - StateKeyRepository: AccessKey + MutateKey, - // Constraint StateT = StfState currently necessary because SgxExternalities Encode/Decode does not work. - // See https://github.com/integritee-network/sgx-runtime/issues/46. - StateHandler: HandleState, -{ +pub struct SealHandler { state_handler: Arc, state_key_repository: Arc, shielding_key_repository: Arc, - light_client_seal: LightClientSealing, + light_client_seal: Arc, } -impl - SealHandler -where - ShieldingKeyRepository: AccessKey + MutateKey, - StateKeyRepository: AccessKey + MutateKey, - StateHandler: HandleState, +impl + SealHandler { pub fn new( state_handler: Arc, state_key_repository: Arc, shielding_key_repository: Arc, + light_client_seal: Arc, ) -> Self { - Self { state_handler, state_key_repository, shielding_key_repository } + Self { state_handler, state_key_repository, shielding_key_repository, light_client_seal } } } @@ -70,20 +60,24 @@ pub trait SealStateAndKeys { fn seal_state_key(&self, bytes: &[u8]) -> EnclaveResult<()>; fn seal_state(&self, bytes: &[u8], shard: &ShardIdentifier) -> EnclaveResult<()>; fn seal_new_empty_state(&self, shard: &ShardIdentifier) -> EnclaveResult<()>; + fn seal_light_client_state(&self, bytes: &[u8]) -> EnclaveResult<()>; } pub trait UnsealStateAndKeys { fn unseal_shielding_key(&self) -> EnclaveResult>; fn unseal_state_key(&self) -> EnclaveResult>; fn unseal_state(&self, shard: &ShardIdentifier) -> EnclaveResult>; + fn unseal_light_client_state(&self) -> EnclaveResult>; } -impl SealStateAndKeys - for SealHandler +impl SealStateAndKeys + for SealHandler where ShieldingKeyRepository: AccessKey + MutateKey, StateKeyRepository: AccessKey + MutateKey, StateHandler: HandleState, + LightClientSeal: LightClientSealing, + LightClientSeal::LightClientState: Decode, { fn seal_shielding_key(&self, bytes: &[u8]) -> EnclaveResult<()> { let key: Rsa3072KeyPair = serde_json::from_slice(bytes).map_err(|e| { @@ -111,6 +105,13 @@ where Ok(()) } + fn seal_light_client_state(&self, mut bytes: &[u8]) -> EnclaveResult<()> { + let state = ::LightClientState::decode(&mut bytes)?; + self.light_client_seal.seal(&state)?; + info!("Successfully sealed light client state"); + Ok(()) + } + /// Seal an empty, newly initialized state. /// /// Requires the shielding key to be sealed and updated before calling this. @@ -125,12 +126,14 @@ where } } -impl UnsealStateAndKeys - for SealHandler +impl UnsealStateAndKeys + for SealHandler where ShieldingKeyRepository: AccessKey + MutateKey, StateKeyRepository: AccessKey + MutateKey, StateHandler: HandleState, + LightClientSeal: LightClientSealing, + LightClientSeal::LightClientState: Encode, { fn unseal_shielding_key(&self) -> EnclaveResult> { let shielding_key = self @@ -150,19 +153,28 @@ where fn unseal_state(&self, shard: &ShardIdentifier) -> EnclaveResult> { Ok(self.state_handler.execute_on_current(shard, |state, _| state.state.encode())?) } + + fn unseal_light_client_state(&self) -> EnclaveResult> { + Ok(self.light_client_seal.unseal()?.encode()) + } } #[cfg(feature = "test")] pub mod test { use super::*; + use itc_parentchain::light_client::mocks::validator_mock_seal::LightValidationStateSealMock; use itp_sgx_crypto::mocks::KeyRepositoryMock; use itp_test::mock::handle_state_mock::HandleStateMock; type StateKeyRepositoryMock = KeyRepositoryMock; type ShieldingKeyRepositoryMock = KeyRepositoryMock; - type SealHandlerMock = - SealHandler; + type SealHandlerMock = SealHandler< + ShieldingKeyRepositoryMock, + StateKeyRepositoryMock, + HandleStateMock, + LightValidationStateSealMock, + >; pub fn seal_shielding_key_works() { let seal_handler = SealHandlerMock::default(); diff --git a/enclave-runtime/src/tls_ra/tests.rs b/enclave-runtime/src/tls_ra/tests.rs index 1540279b17..beae945656 100644 --- a/enclave-runtime/src/tls_ra/tests.rs +++ b/enclave-runtime/src/tls_ra/tests.rs @@ -26,6 +26,7 @@ use crate::{ tls_ra::seal_handler::{SealHandler, SealStateAndKeys, UnsealStateAndKeys}, }; use ita_stf::State; +use itc_parentchain::light_client::mocks::validator_mock_seal::LightValidationStateSealMock; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode, WorkerModeProvider}; use itp_sgx_crypto::{mocks::KeyRepositoryMock, Aes}; use itp_stf_interface::InitState; @@ -74,22 +75,28 @@ pub fn test_tls_ra_server_client_networking() { let shielding_key_encoded = vec![1, 2, 3]; let state_key_encoded = vec![5, 2, 3, 7]; let state_encoded = Vec::from([1u8; 26000]); // Have a decently sized state, so read() must be called multiple times. + let light_client_state_encoded = Vec::from([1u8; 10000]); // Have a decently sized state, so read() must be called multiple times. let server_seal_handler = SealHandlerMock::new( Arc::new(RwLock::new(shielding_key_encoded.clone())), Arc::new(RwLock::new(state_key_encoded.clone())), Arc::new(RwLock::new(state_encoded.clone())), + Arc::new(RwLock::new(light_client_state_encoded.clone())), ); let initial_client_state = vec![0, 0, 1]; let initial_client_state_key = vec![0, 0, 2]; + let initial_client_light_client_state = vec![0, 0, 3]; let client_shielding_key = Arc::new(RwLock::new(Vec::new())); let client_state_key = Arc::new(RwLock::new(initial_client_state_key.clone())); let client_state = Arc::new(RwLock::new(initial_client_state.clone())); + let client_light_client_state = + Arc::new(RwLock::new(initial_client_light_client_state.clone())); let client_seal_handler = SealHandlerMock::new( client_shielding_key.clone(), client_state_key.clone(), client_state.clone(), + client_light_client_state.clone(), ); let port: u16 = 3149; @@ -118,6 +125,7 @@ pub fn test_tls_ra_server_client_networking() { assert!(result.is_ok()); assert_eq!(*client_shielding_key.read().unwrap(), shielding_key_encoded); + assert_eq!(*client_light_client_state.read().unwrap(), light_client_state_encoded); // State and state-key are provisioned only in sidechain mode if WorkerModeProvider::worker_mode() == WorkerMode::Sidechain { @@ -179,5 +187,7 @@ fn create_seal_handler( Arc::new(KeyRepositoryMock::::new(shielding_key)); let state_handler = Arc::new(HandleStateMock::default()); state_handler.reset(state, shard).unwrap(); - SealHandler::new(state_handler, state_key_repository, shielding_key_repository) + let seal = Arc::new(LightValidationStateSealMock::new()); + + SealHandler::new(state_handler, state_key_repository, shielding_key_repository, seal) } diff --git a/enclave-runtime/src/tls_ra/tls_ra_client.rs b/enclave-runtime/src/tls_ra/tls_ra_client.rs index aa1f71651a..9eb1546b2a 100644 --- a/enclave-runtime/src/tls_ra/tls_ra_client.rs +++ b/enclave-runtime/src/tls_ra/tls_ra_client.rs @@ -22,7 +22,7 @@ use crate::{ attestation::create_ra_report_and_signature, error::{Error as EnclaveError, Result as EnclaveResult}, initialization::global_components::{ - EnclaveSealHandler, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, + EnclaveSealHandler, GLOBAL_LIGHT_CLIENT_SEAL, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_KEY_REPOSITORY_COMPONENT, }, ocall::OcallApi, @@ -128,6 +128,7 @@ where Opcode::ShieldingKey => self.seal_handler.seal_shielding_key(&bytes)?, Opcode::StateKey => self.seal_handler.seal_state_key(&bytes)?, Opcode::State => self.seal_handler.seal_state(&bytes, &self.shard)?, + Opcode::LightClient => self.seal_handler.seal_light_client_state(&bytes)?, }; Ok(Some(header.opcode)) } @@ -192,8 +193,20 @@ pub unsafe extern "C" fn request_state_provisioning( }, }; - let seal_handler = - EnclaveSealHandler::new(state_handler, state_key_repository, shielding_key_repository); + let light_client_seal = match GLOBAL_LIGHT_CLIENT_SEAL.get() { + Ok(s) => s, + Err(e) => { + error!("{:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; + + let seal_handler = EnclaveSealHandler::new( + state_handler, + state_key_repository, + shielding_key_repository, + light_client_seal, + ); if let Err(e) = request_state_provisioning_internal( socket_fd, diff --git a/enclave-runtime/src/tls_ra/tls_ra_server.rs b/enclave-runtime/src/tls_ra/tls_ra_server.rs index ff39d491cc..836b146b9d 100644 --- a/enclave-runtime/src/tls_ra/tls_ra_server.rs +++ b/enclave-runtime/src/tls_ra/tls_ra_server.rs @@ -22,7 +22,7 @@ use crate::{ attestation::create_ra_report_and_signature, error::{Error as EnclaveError, Result as EnclaveResult}, initialization::global_components::{ - EnclaveSealHandler, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, + EnclaveSealHandler, GLOBAL_LIGHT_CLIENT_SEAL, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_KEY_REPOSITORY_COMPONENT, }, ocall::OcallApi, @@ -107,9 +107,11 @@ where self.write_shielding_key()?; self.write_state_key()?; self.write_state(shard)?; + self.write_light_client_state()?; }, ProvisioningPayload::ShieldingKeyAndLightClient => { self.write_shielding_key()?; + self.write_light_client_state()?; }, } @@ -135,6 +137,12 @@ where Ok(()) } + fn write_light_client_state(&mut self) -> EnclaveResult<()> { + let state = self.seal_handler.unseal_light_client_state()?; + self.write(Opcode::LightClient, &state)?; + Ok(()) + } + /// Sends the header followed by the payload. fn write(&mut self, opcode: Opcode, bytes: &[u8]) -> EnclaveResult<()> { let payload_length = bytes.len() as u64; @@ -190,8 +198,20 @@ pub unsafe extern "C" fn run_state_provisioning_server( }, }; - let seal_handler = - EnclaveSealHandler::new(state_handler, state_key_repository, shielding_key_repository); + let light_client_seal = match GLOBAL_LIGHT_CLIENT_SEAL.get() { + Ok(s) => s, + Err(e) => { + error!("{:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; + + let seal_handler = EnclaveSealHandler::new( + state_handler, + state_key_repository, + shielding_key_repository, + light_client_seal, + ); if let Err(e) = run_state_provisioning_server_internal::<_, WorkerModeProvider>( socket_fd,