diff --git a/tee-worker/app-libs/stf/src/trusted_call.rs b/tee-worker/app-libs/stf/src/trusted_call.rs index 367f7774b8..313ba5e533 100644 --- a/tee-worker/app-libs/stf/src/trusted_call.rs +++ b/tee-worker/app-libs/stf/src/trusted_call.rs @@ -508,11 +508,7 @@ where aes_encrypt_default(&key, &code.encode()), ))); } else { - add_call_from_imp_error( - calls, - node_metadata_repo, - IMPError::InvalidUserShieldingKey, - ); + error!("Can't create identity: InvalidUserShieldingKey"); } }, Err(e) => { @@ -544,11 +540,7 @@ where aes_encrypt_default(&key, &identity.encode()), ))); } else { - add_call_from_imp_error( - calls, - node_metadata_repo, - IMPError::InvalidUserShieldingKey, - ); + error!("Can't remove identity: InvalidUserShieldingKey"); } }, Err(e) => { @@ -608,11 +600,7 @@ where aes_encrypt_default(&key, &id_graph.encode()), ))); } else { - add_call_from_imp_error( - calls, - node_metadata_repo, - IMPError::InvalidUserShieldingKey, - ); + error!("Can't verify identity: InvalidUserShieldingKey"); } }, Err(e) => { diff --git a/tee-worker/litentry/core/data-providers/src/graphql.rs b/tee-worker/litentry/core/data-providers/src/graphql.rs index 47b3f22d69..bc2af341ed 100644 --- a/tee-worker/litentry/core/data-providers/src/graphql.rs +++ b/tee-worker/litentry/core/data-providers/src/graphql.rs @@ -65,6 +65,7 @@ impl From for VerifiedCredentialsNetwork { SubstrateNetwork::Polkadot => Self::Polkadot, SubstrateNetwork::Kusama => Self::Kusama, SubstrateNetwork::Khala => Self::Khala, + SubstrateNetwork::TestNet => todo!(), } } } diff --git a/tee-worker/litentry/pallets/identity-management/src/lib.rs b/tee-worker/litentry/pallets/identity-management/src/lib.rs index 1de2a63cb8..9996bef4a2 100644 --- a/tee-worker/litentry/pallets/identity-management/src/lib.rs +++ b/tee-worker/litentry/pallets/identity-management/src/lib.rs @@ -93,6 +93,8 @@ pub mod pallet { pub enum Error { /// challenge code doesn't exist ChallengeCodeNotExist, + /// Invalid user shielding Key + InvalidUserShieldingKey, /// the pair (litentry-account, identity) already verified when creating an identity IdentityAlreadyVerified, /// the pair (litentry-account, identity) doesn't exist @@ -200,6 +202,8 @@ pub mod pallet { parent_ss58_prefix: u16, ) -> DispatchResult { T::ManageOrigin::ensure_origin(origin)?; + ensure!(Self::user_shielding_keys(&who).is_some(), Error::::InvalidUserShieldingKey); + if let Some(c) = IDGraphs::::get(&who, &identity) { ensure!( !(c.is_verified && c.creation_request_block != Some(0)), @@ -218,7 +222,7 @@ pub mod pallet { } let prime_id = Identity::Substrate { - network: SubstrateNetwork::Litentry, + network: SubstrateNetwork::from_ss58_prefix(parent_ss58_prefix), address: prime_user_address, }; if IDGraphs::::get(&who, &prime_id).is_none() { @@ -250,6 +254,7 @@ pub mod pallet { identity: Identity, ) -> DispatchResult { T::ManageOrigin::ensure_origin(origin)?; + ensure!(Self::user_shielding_keys(&who).is_some(), Error::::InvalidUserShieldingKey); ensure!(IDGraphs::::contains_key(&who, &identity), Error::::IdentityNotExist); if let Some(IdentityContext:: { metadata, @@ -281,6 +286,7 @@ pub mod pallet { verification_request_block: ParentchainBlockNumber, ) -> DispatchResult { T::ManageOrigin::ensure_origin(origin)?; + ensure!(Self::user_shielding_keys(&who).is_some(), Error::::InvalidUserShieldingKey); IDGraphs::::try_mutate(&who, &identity, |context| -> DispatchResult { let mut c = context.take().ok_or(Error::::IdentityNotExist)?; diff --git a/tee-worker/litentry/pallets/identity-management/src/mock.rs b/tee-worker/litentry/pallets/identity-management/src/mock.rs index d754da2633..a458ce8775 100644 --- a/tee-worker/litentry/pallets/identity-management/src/mock.rs +++ b/tee-worker/litentry/pallets/identity-management/src/mock.rs @@ -15,13 +15,16 @@ // along with Litentry. If not, see . use crate as pallet_tee_identity_management; +use crate::UserShieldingKeyType; use frame_support::{ ord_parameter_types, parameter_types, traits::{ConstU128, ConstU16, ConstU32}, }; use frame_system as system; use frame_system::EnsureSignedBy; -use litentry_primitives::{Identity, IdentityString, SubstrateNetwork, Web2Network}; +use litentry_primitives::{ + Identity, IdentityString, SubstrateNetwork, Web2Network, USER_SHIELDING_KEY_LEN, +}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -102,6 +105,9 @@ impl pallet_tee_identity_management::Config for Test { const ALICE_KEY: &str = "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"; +pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); + pub fn alice_twitter_identity(suffix: u32) -> Identity { let address = IdentityString::try_from(format!("alice{}", suffix).as_bytes().to_vec()) .expect("convert to BoundedVec failed"); @@ -119,12 +125,21 @@ pub fn bob_web3_identity() -> Identity { Identity::Substrate { network: SubstrateNetwork::Litentry, address: bob_key_hex.into() } } -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext(set_shielding_key: bool) -> sp_io::TestExternalities { let t = system::GenesisConfig::default().build_storage::().unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { System::set_block_number(1); + + if set_shielding_key { + let shielding_key: UserShieldingKeyType = [0u8; USER_SHIELDING_KEY_LEN]; + let _ = IMT::set_user_shielding_key( + RuntimeOrigin::signed(ALICE), + BOB, + shielding_key.clone(), + ); + } }); ext } diff --git a/tee-worker/litentry/pallets/identity-management/src/tests.rs b/tee-worker/litentry/pallets/identity-management/src/tests.rs index 431c2f48bf..eac9b5a0fb 100644 --- a/tee-worker/litentry/pallets/identity-management/src/tests.rs +++ b/tee-worker/litentry/pallets/identity-management/src/tests.rs @@ -27,7 +27,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); #[test] fn set_user_shielding_key_works() { - new_test_ext().execute_with(|| { + new_test_ext(false).execute_with(|| { let shielding_key: UserShieldingKeyType = [0u8; USER_SHIELDING_KEY_LEN]; assert_eq!(IMT::user_shielding_keys(BOB), None); assert_ok!(IMT::set_user_shielding_key( @@ -45,7 +45,7 @@ fn set_user_shielding_key_works() { #[test] fn create_identity_works() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let ss58_prefix = 131_u16; let metadata: MetadataOf = vec![0u8; 16].try_into().unwrap(); assert_ok!(IMT::create_identity( @@ -70,9 +70,21 @@ fn create_identity_works() { #[test] fn remove_identity_works() { - new_test_ext().execute_with(|| { + new_test_ext(false).execute_with(|| { + assert_noop!( + IMT::remove_identity(RuntimeOrigin::signed(ALICE), BOB, alice_web3_identity()), + Error::::InvalidUserShieldingKey + ); + + let shielding_key: UserShieldingKeyType = [0u8; USER_SHIELDING_KEY_LEN]; + assert_ok!(IMT::set_user_shielding_key( + RuntimeOrigin::signed(ALICE), + BOB, + shielding_key.clone() + )); + let metadata: MetadataOf = vec![0u8; 16].try_into().unwrap(); - let ss58_prefix = 131_u16; + let ss58_prefix = 31_u16; assert_noop!( IMT::remove_identity(RuntimeOrigin::signed(ALICE), BOB, alice_web3_identity()), Error::::IdentityNotExist @@ -114,7 +126,7 @@ fn remove_identity_works() { #[test] fn verify_identity_works() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let metadata: MetadataOf = vec![0u8; 16].try_into().unwrap(); let ss58_prefix = 131_u16; assert_ok!(IMT::create_identity( @@ -145,7 +157,7 @@ fn verify_identity_works() { #[test] fn get_id_graph_works() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { let metadata3: MetadataOf = vec![0u8; 16].try_into().unwrap(); let ss58_prefix = 131_u16; assert_ok!(IMT::create_identity( @@ -191,7 +203,7 @@ fn get_id_graph_works() { #[test] fn verify_identity_fails_when_too_early() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { const CREATION_REQUEST_BLOCK: ParentchainBlockNumber = 2; const VERIFICATION_REQUEST_BLOCK: ParentchainBlockNumber = 1; @@ -228,7 +240,7 @@ fn verify_identity_fails_when_too_early() { #[test] fn verify_identity_fails_when_too_late() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { const CREATION_REQUEST_BLOCK: ParentchainBlockNumber = 1; const VERIFICATION_REQUEST_BLOCK: ParentchainBlockNumber = 5; @@ -265,7 +277,7 @@ fn verify_identity_fails_when_too_late() { #[test] fn get_id_graph_with_max_len_works() { - new_test_ext().execute_with(|| { + new_test_ext(true).execute_with(|| { // fill in 21 identities, starting from 1 to reserve place for prime_id for i in 1..22 { assert_ok!(IMT::create_identity( @@ -292,6 +304,6 @@ fn get_id_graph_with_max_len_works() { let id_graph = IMT::get_id_graph_with_max_len(&BOB, 30); assert_eq!(id_graph.len(), 22); assert_eq!(String::from_utf8(id_graph.get(0).unwrap().0.flat()).unwrap(), "did:twitter:web2:_:alice21"); - assert_eq!(String::from_utf8(id_graph.get(21).unwrap().0.flat()).unwrap(), "did:litentry:web3:substrate:0x0202020202020202020202020202020202020202020202020202020202020202"); + assert_eq!(String::from_utf8(id_graph.get(21).unwrap().0.flat()).unwrap(), "did:litmus:web3:substrate:0x0202020202020202020202020202020202020202020202020202020202020202"); }); } diff --git a/tee-worker/litentry/primitives/src/identity.rs b/tee-worker/litentry/primitives/src/identity.rs index f2abf3f12f..c7d58d11bd 100644 --- a/tee-worker/litentry/primitives/src/identity.rs +++ b/tee-worker/litentry/primitives/src/identity.rs @@ -73,6 +73,7 @@ pub enum SubstrateNetwork { Litentry, Litmus, Khala, + TestNet, } impl SubstrateNetwork { @@ -84,6 +85,18 @@ impl SubstrateNetwork { Self::Litentry => 31, Self::Litmus => 131, Self::Khala => 30, + Self::TestNet => 13, + } + } + + pub fn from_ss58_prefix(prefix: u16) -> Self { + match prefix { + 0 => Self::Polkadot, + 2 => Self::Kusama, + 31 => Self::Litentry, + 131 => Self::Litmus, + 30 => Self::Khala, + _ => Self::TestNet, } } } diff --git a/tee-worker/ts-tests/identity.test.ts b/tee-worker/ts-tests/identity.test.ts index 6ef4c14337..ce40db45c2 100644 --- a/tee-worker/ts-tests/identity.test.ts +++ b/tee-worker/ts-tests/identity.test.ts @@ -128,6 +128,18 @@ describeLitentry('Test Identity', (context) => { var signature_ethereum; var signature_substrate; + step('Invalid user shielding key', async function () { + const encode = context.api.createType('LitentryIdentity', substrateIdentity).toHex(); + const ciphertext = encryptWithTeeShieldingKey(context.teeShieldingKey, encode).toString('hex'); + const tx = context.api.tx.identityManagement.createIdentity(context.mrEnclave, context.defaultSigner[0].address, `0x${ciphertext}`, null); + await sendTxUntilInBlock(context.api, tx, context.defaultSigner[0]); + + const events = await listenEvent(context.api, 'identityManagement', ['StfError']); + expect(events.length).to.be.equal(1); + + await checkFailReason(events, 'InvalidUserShieldingKey', true); + }) + step('set user shielding key', async function () { const alice = await setUserShieldingKey(context, context.defaultSigner[0], aesKey, true); assert.equal(alice, u8aToHex(context.defaultSigner[0].addressRaw), 'check caller error'); @@ -331,7 +343,8 @@ describeLitentry('Test Identity', (context) => { const substratePrimeIdentity = { Substrate: { address: `0x${Buffer.from(context.defaultSigner[0].publicKey).toString('hex')}`, - network: 'Litentry', + // When testing with integritee-node, change network to: TestNet + network: 'Litmus', }, }; @@ -342,7 +355,8 @@ describeLitentry('Test Identity', (context) => { const events = await listenEvent(context.api, 'identityManagement', ['StfError']); expect(events.length).to.be.equal(1); - const result = events[0].method as string; + + await checkFailReason(events, 'RemovePrimeIdentityDisallowed', true); }); step('remove error identities', async function () { @@ -359,8 +373,9 @@ describeLitentry('Test Identity', (context) => { await checkFailReason(resp_not_exist_identities, 'IdentityNotExist', true); - //remove a challenge code before the code is set //context.defaultSigner[2] doesn't have a challenge code + const bob = await setUserShieldingKey(context, context.defaultSigner[2], aesKey, true); + assert.equal(bob, u8aToHex(context.defaultSigner[2].addressRaw), 'check caller error'); const resp_not_created_identities = (await removeErrorIdentities( context, context.defaultSigner[2], diff --git a/tee-worker/ts-tests/type-definitions.ts b/tee-worker/ts-tests/type-definitions.ts index 47b39bc367..cde9e2bb27 100644 --- a/tee-worker/ts-tests/type-definitions.ts +++ b/tee-worker/ts-tests/type-definitions.ts @@ -90,7 +90,7 @@ export const teeTypes = { _enum: ['Twitter', 'Discord', 'Github'], }, SubstrateNetwork: { - _enum: ['Polkadot', 'Kusama', 'Litentry', 'Litmus'], + _enum: ['Polkadot', 'Kusama', 'Litentry', 'Litmus', 'Khala', 'TestNet'], }, EvmNetwork: { _enum: ['Ethereum', 'BSC'], @@ -275,7 +275,7 @@ export type Web3Network = { }; export type Web2Network = 'Twitter' | 'Discord' | 'Github'; -export type SubstrateNetwork = 'Polkadot' | 'Kusama' | 'Litentry' | 'Litmus'; +export type SubstrateNetwork = 'Polkadot' | 'Kusama' | 'Litentry' | 'Litmus' | 'Khala' | 'TestNet'; export type EvmNetwork = 'Ethereum' | 'BSC'; export type IdentityGenericEvent = {