Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ecdf920
add design document with some mermaid diagrams
brenzi Oct 11, 2023
347e187
support enclave signing with changing keypairs at runtime
brenzi Oct 11, 2023
81e94dd
tame nervous polling of not yet finalized block
brenzi Oct 11, 2023
6ddd043
shard vault account creation works
brenzi Oct 11, 2023
156aac3
prepare vault account getter. not working yet
brenzi Oct 11, 2023
f1d3d77
fix build and add trusted_call dummy for unshielding
brenzi Oct 12, 2023
9911098
fix transfer call indexes
brenzi Oct 12, 2023
ead3662
unshieldind dummy with real vault account and proxy call
brenzi Oct 12, 2023
b20d978
await vault account creation before registering proxy
brenzi Oct 12, 2023
4524b9f
proxied unshielding call encodes correctly and would be executed if t…
brenzi Oct 12, 2023
6587f1b
start MU_RA doc diagrams and refactor namings for improved readability
brenzi Oct 12, 2023
d5ce0c7
refactoring MU RA functions for better readability. try to extract cl…
brenzi Oct 12, 2023
cd3562d
logging pubkey of counterparty now during MU RA. but seems skip_ra wo…
brenzi Oct 12, 2023
36bdc5c
add client account to MU RA request
brenzi Oct 13, 2023
b5da3a2
starting to modularize vault logic
brenzi Oct 13, 2023
ed26be7
secondary worker is registered as a vault proxy now
brenzi Oct 13, 2023
da6bea0
Merge remote-tracking branch 'origin/master' into ab/proxied-vault-ac…
brenzi Oct 13, 2023
b72c063
cleanup
brenzi Oct 13, 2023
4d2c000
clippy
brenzi Oct 13, 2023
9bc2e60
doc cleanup
brenzi Oct 13, 2023
757c07a
doc pimp
brenzi Oct 13, 2023
2b7ed16
cleanup
brenzi Oct 13, 2023
bb69ebd
reverting polling fix which is solved in another PR
brenzi Oct 24, 2023
42fac49
fix diagram bug
brenzi Oct 24, 2023
f5acb2d
fix mock test
brenzi Oct 24, 2023
6e03fff
avoid panic if add_shard_vault_proxy fails
brenzi Oct 25, 2023
2109bd2
skip shard vault stuff for offchain-worker
brenzi Oct 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3692,6 +3692,7 @@ dependencies = [
name = "itp-stf-executor"
version = "0.9.0"
dependencies = [
"hex",
"ita-stf",
"itc-parentchain-test",
"itp-node-api",
Expand Down
72 changes: 72 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# sidechain startup internal view
```mermaid
sequenceDiagram
participant integritee_network
participant service
participant slotworker
participant parentsync
participant enclave
participant enclave_rpc
participant provisioningserver
participant isinitializedserver
participant metrics
service ->> enclave: EnclaveBase.get_mrenclave
service ->> provisioningserver: spawn (`--mu-ra-port` | 3443)
activate provisioningserver
service ->> enclave: get_ecc_signing_pubkey
service ->> isinitializedserver: spawn (`--untrusted-http-port | 4545)
activate isinitializedserver
service ->> metrics: spawn (`--metrics-port`| 8787)
activate metrics
service ->> enclave_rpc: spawn (`--trusted-worker-port`| 2000)
activate enclave_rpc

service ->> enclave: generate_dcap_ra_extrinsic
service ->> integritee_network: send register_sgx_enclave extrinsic
service ->> integritee_network: get ShardStatus
service ->> isinitializedserver: registered_on_parentchain
# schedule teeracle re-registration and updates
loop while blocks to sync
service ->> integritee_network: get_block
service ->> enclave: sync_parentchain(blocks, events, proofs)
end
service ->> enclave: init_enclave_sidechain_components
service ->> slotworker: spawn
loop forever
slotworker ->> enclave: execute_trusted_calls
activate enclave
enclave ->> enclave: propose_sidechain_block
enclave ->> integritee_network: send_extrinsics
deactivate enclave
end
service ->> parentsync: spawn
loop forever
parentsync ->> integritee_network: subscribe new headers
parentsync ->> enclave: sync_parentchain
end
service ->> service: poll worker_for_shard
service ->> isinitializedserver: worker_for_shard_registered

deactivate enclave_rpc
deactivate metrics
deactivate isinitializedserver
deactivate provisioningserver
```

# sidechain lifetime external view

```mermaid
sequenceDiagram
participant integritee_network
participant validateer_1
participant validateer_2
actor alice

validateer_1 ->> integritee_network: register_sgx_enclave()

validateer_2 ->> integritee_network: register_sgx_enclave()

validateer_2 ->> validateer_1: sidechain_fetchBlocksFromPeer()

validateer_1 ->> validateer_2: sidechain_importBlock()
```
41 changes: 33 additions & 8 deletions app-libs/stf/src/trusted_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,29 @@ use sp_core::{H160, H256, U256};
use std::vec::Vec;

use crate::{helpers::ensure_enclave_signer_account, StfError, TrustedOperation};
use codec::{Decode, Encode};
use codec::{Compact, Decode, Encode};
use frame_support::{ensure, traits::UnfilteredDispatchable};
#[cfg(feature = "evm")]
use ita_sgx_runtime::{AddressMapping, HashedAddressMapping};
pub use ita_sgx_runtime::{Balance, Index};
use ita_sgx_runtime::{Runtime, System};
use itp_node_api::metadata::{provider::AccessNodeMetadata, NodeMetadataTrait};
use itp_node_api_metadata::pallet_enclave_bridge::EnclaveBridgeCallIndexes;
use itp_stf_interface::ExecuteCall;
use itp_node_api_metadata::{
pallet_balances::BalancesCallIndexes, pallet_enclave_bridge::EnclaveBridgeCallIndexes,
pallet_proxy::ProxyCallIndexes,
};
use itp_stf_interface::{ExecuteCall, SHARD_VAULT_KEY};
use itp_stf_primitives::types::{AccountId, KeyPair, ShardIdentifier, Signature};
use itp_types::OpaqueCall;
use itp_types::{parentchain::ProxyType, Address, OpaqueCall};
use itp_utils::stringify::account_id_to_string;
use log::*;
use sp_io::hashing::blake2_256;
use sp_runtime::{traits::Verify, MultiAddress};
use std::{format, prelude::v1::*, sync::Arc};

#[cfg(feature = "evm")]
use ita_sgx_runtime::{AddressMapping, HashedAddressMapping};

#[cfg(feature = "evm")]
use crate::evm_helpers::{create_code_hash, evm_create2_address, evm_create_address};
use crate::helpers::get_storage_by_key_hash;

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -242,13 +245,35 @@ where
shard
);
unshield_funds(account_incognito, value)?;

calls.push(OpaqueCall::from_tuple(&(
node_metadata_repo.get_from_metadata(|m| m.unshield_funds_call_indexes())??,
shard,
beneficiary,
beneficiary.clone(),
value,
call_hash,
)));
// todo: the following is a placeholder dummy which will replace the above with #1257.
// the extrinsic will be sent and potentially deplete the vault at the current state which
// is nothing to worry about before we solve mentioned issue.
let vault_pubkey: [u8; 32] = get_storage_by_key_hash(SHARD_VAULT_KEY.into())
.ok_or_else(|| {
StfError::Dispatch("shard vault key hasn't been set".to_string())
})?;
let vault_address = Address::from(AccountId::from(vault_pubkey));
let vault_transfer_call = OpaqueCall::from_tuple(&(
node_metadata_repo
.get_from_metadata(|m| m.transfer_keep_alive_call_indexes())??,
Address::from(beneficiary),
Compact(value),
));
let proxy_call = OpaqueCall::from_tuple(&(
node_metadata_repo.get_from_metadata(|m| m.proxy_call_indexes())??,
vault_address,
None::<ProxyType>,
vault_transfer_call,
));
calls.push(proxy_call);
Ok(())
},
TrustedCall::balance_shield(enclave_account, who, value) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ where
let _result = ecc_handle.open();
let (prv_k, pub_k) = ecc_handle.create_key_pair()?;
info!("Enclave Attestation] Generated ephemeral ECDSA keypair:");
debug!(" pubkey X is {:02x}", pub_k.gx.iter().format(""));
debug!(" pubkey Y is {:02x}", pub_k.gy.iter().format(""));

let qe_quote = if !skip_ra {
let qe_quote = match self.retrieve_qe_dcap_quote(
Expand Down
26 changes: 26 additions & 0 deletions core-primitives/attestation-handler/src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,31 @@ pub fn percent_decode(orig: String) -> EnclaveResult<String> {
Ok(ret)
}

pub fn parse_cert_issuer(cert_der: &[u8]) -> SgxResult<Vec<u8>> {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is currently not used. I wrote it because I tried to derive the MU RA client from the TLS certificate. fell back to passing it as a payload instead. Still, I think this fn might be useful on its own. webpki and rustls hide the issuer all too well behind private fields

// Before we reach here, Webpki already verified the cert is properly signed

// Search for Public Key prime256v1 OID
let prime256v1_oid = &[0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
let mut offset = cert_der
.windows(prime256v1_oid.len())
.position(|window| window == prime256v1_oid)
.ok_or(sgx_status_t::SGX_ERROR_UNEXPECTED)?;
offset += 11; // 10 + TAG (0x03)

// Obtain Public Key length
let mut len = cert_der[offset] as usize;
if len > 0x80 {
len = (cert_der[offset + 1] as usize) * 0x100 + (cert_der[offset + 2] as usize);
offset += 2;
}

// Obtain Public Key
offset += 1;
let pub_k = cert_der[offset + 2..offset + len].to_vec(); // skip "00 04"

Ok(pub_k)
}

// FIXME: This code is redundant with the host call of the integritee-node
pub fn verify_mra_cert<A>(
cert_der: &[u8],
Expand Down Expand Up @@ -346,6 +371,7 @@ where
verify_attn_report(attn_report_raw, pub_k, attestation_ocall)
} else {
// TODO Refactor state provisioning to not use MURA #1385
// TODO DCAP is currently just passed through! SECURITY!!!
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware that our MU RA is insecure for DCAP. Increases the urgency for #1385

Ok(())
}
}
Expand Down
16 changes: 16 additions & 0 deletions core-primitives/enclave-api/ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ extern "C" {
shard_size: u32,
) -> sgx_status_t;

pub fn init_proxied_shard_vault(
eid: sgx_enclave_id_t,
retval: *mut sgx_status_t,
shard: *const u8,
shard_size: u32,
) -> sgx_status_t;

pub fn trigger_parentchain_block_import(
eid: sgx_enclave_id_t,
retval: *mut sgx_status_t,
Expand Down Expand Up @@ -110,6 +117,15 @@ extern "C" {
pubkey_size: u32,
) -> sgx_status_t;

pub fn get_ecc_vault_pubkey(
eid: sgx_enclave_id_t,
retval: *mut sgx_status_t,
shard: *const u8,
shard_size: u32,
pubkey: *mut u8,
pubkey_size: u32,
) -> sgx_status_t;

pub fn get_mrenclave(
eid: sgx_enclave_id_t,
retval: *mut sgx_status_t,
Expand Down
47 changes: 47 additions & 0 deletions core-primitives/enclave-api/src/enclave_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use itp_enclave_api_ffi as ffi;
use itp_settings::worker::{
HEADER_MAX_SIZE, MR_ENCLAVE_SIZE, SHIELDING_KEY_SIZE, SIGNING_KEY_SIZE,
};
use itp_types::ShardIdentifier;
use log::*;
use sgx_crypto_helper::rsa3072::Rsa3072PubKey;
use sgx_types::*;
Expand Down Expand Up @@ -56,6 +57,9 @@ pub trait EnclaveBase: Send + Sync + 'static {
/// Initialize a new shard.
fn init_shard(&self, shard: Vec<u8>) -> EnclaveResult<()>;

/// Initialize a new shard vault account and register enclave signer as its proxy.
fn init_proxied_shard_vault(&self, shard: &ShardIdentifier) -> EnclaveResult<()>;

/// Trigger the import of parentchain block explicitly. Used when initializing a light-client
/// with a triggered import dispatcher.
fn trigger_parentchain_block_import(&self, parentchain_id: &ParentchainId)
Expand All @@ -73,6 +77,9 @@ pub trait EnclaveBase: Send + Sync + 'static {

fn get_ecc_signing_pubkey(&self) -> EnclaveResult<ed25519::Public>;

/// retrieve vault account from shard state
fn get_ecc_vault_pubkey(&self, shard: &ShardIdentifier) -> EnclaveResult<ed25519::Public>;

fn get_fingerprint(&self) -> EnclaveResult<EnclaveFingerprint>;
}

Expand Down Expand Up @@ -164,6 +171,24 @@ impl EnclaveBase for Enclave {
Ok(())
}

fn init_proxied_shard_vault(&self, shard: &ShardIdentifier) -> EnclaveResult<()> {
let mut retval = sgx_status_t::SGX_SUCCESS;

let shard_bytes = shard.encode();
let result = unsafe {
ffi::init_proxied_shard_vault(
self.eid,
&mut retval,
shard_bytes.as_ptr(),
shard_bytes.len() as u32,
)
};

ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result));
ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval));

Ok(())
}
fn trigger_parentchain_block_import(
&self,
parentchain_id: &ParentchainId,
Expand Down Expand Up @@ -276,6 +301,28 @@ impl EnclaveBase for Enclave {
Ok(ed25519::Public::from_raw(pubkey))
}

fn get_ecc_vault_pubkey(&self, shard: &ShardIdentifier) -> EnclaveResult<ed25519::Public> {
let mut retval = sgx_status_t::SGX_SUCCESS;
let mut pubkey = [0u8; SIGNING_KEY_SIZE];
let shard_bytes = shard.encode();

let result = unsafe {
ffi::get_ecc_vault_pubkey(
self.eid,
&mut retval,
shard_bytes.as_ptr(),
shard_bytes.len() as u32,
pubkey.as_mut_ptr(),
pubkey.len() as u32,
)
};

ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result));
ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval));

Ok(ed25519::Public::from_raw(pubkey))
}

fn get_fingerprint(&self) -> EnclaveResult<EnclaveFingerprint> {
let mut retval = sgx_status_t::SGX_SUCCESS;
let mut mr_enclave = [0u8; MR_ENCLAVE_SIZE];
Expand Down
40 changes: 40 additions & 0 deletions core-primitives/extrinsics-factory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ where
) -> Self {
ExtrinsicsFactory { genesis_hash, signer, nonce_cache, node_metadata_repository }
}

pub fn with_signer(&self, signer: Signer, nonce_cache: Arc<NonceCache>) -> Self {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this allows the enclave to send extrinsics using arbitrary signers (closes #1466)

ExtrinsicsFactory {
genesis_hash: self.genesis_hash,
signer,
nonce_cache,
node_metadata_repository: self.node_metadata_repository.clone(),
}
}
}

impl<Signer, NonceCache, NodeMetadataRepository> CreateExtrinsics
Expand Down Expand Up @@ -170,6 +179,33 @@ pub mod tests {
assert_eq!(nonce_cache.get_nonce().unwrap(), Nonce(opaque_calls.len() as NonceValue));
}

#[test]
pub fn with_signer_works() {
let nonce_cache1 = Arc::new(NonceCache::default());
*nonce_cache1.load_for_mutation().unwrap() = Nonce(42);

let node_metadata_repo = Arc::new(NodeMetadataRepository::new(NodeMetadata::default()));
let extrinsics_factory = ExtrinsicsFactory::new(
test_genesis_hash(),
StaticExtrinsicSigner::<_, PairSignature>::new(test_account()),
nonce_cache1.clone(),
node_metadata_repo,
);

let nonce_cache2 = Arc::new(NonceCache::default());
let extrinsics_factory = extrinsics_factory.with_signer(
StaticExtrinsicSigner::<_, PairSignature>::new(test_account2()),
nonce_cache2.clone(),
);

let opaque_calls = [OpaqueCall(vec![3u8; 42]), OpaqueCall(vec![12u8, 78])];
let xts = extrinsics_factory.create_extrinsics(&opaque_calls, None).unwrap();

assert_eq!(opaque_calls.len(), xts.len());
assert_eq!(nonce_cache2.get_nonce().unwrap(), Nonce(opaque_calls.len() as NonceValue));
assert_eq!(nonce_cache1.get_nonce().unwrap(), Nonce(42));
}

// #[test]
// pub fn xts_have_increasing_nonce() {
// let nonce_cache = Arc::new(NonceCache::default());
Expand All @@ -194,6 +230,10 @@ pub mod tests {
ed25519::Pair::from_seed(b"42315678901234567890123456789012")
}

fn test_account2() -> ed25519::Pair {
ed25519::Pair::from_seed(b"12315678901234567890123456789012")
}

fn test_genesis_hash() -> H256 {
H256::from_slice(&[56u8; 32])
}
Expand Down
Loading