Skip to content

Commit

Permalink
Vc.issuer.id should be the enclave account (#2843)
Browse files Browse the repository at this point in the history
* small refactor

* use enclave account as issuer

* adjust ts test

* add test

* bump sgx runtime version

* bump runtime version
  • Loading branch information
Kailai-Wang committed Jun 29, 2024
1 parent d82691b commit 0f6d532
Show file tree
Hide file tree
Showing 12 changed files with 65 additions and 64 deletions.
2 changes: 1 addition & 1 deletion tee-worker/app-libs/sgx-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node-template"),
impl_name: create_runtime_str!("node-template"),
authoring_version: 1,
spec_version: 107,
spec_version: 108,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down
12 changes: 3 additions & 9 deletions tee-worker/core-primitives/stf-executor/src/enclave_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ use itp_stf_primitives::{
use itp_stf_state_observer::traits::ObserveState;
use itp_top_pool_author::traits::AuthorApi;
use itp_types::{Index, ShardIdentifier};
use log::*;
use sp_core::{ed25519::Pair as Ed25519Pair, Pair};
use std::{boxed::Box, sync::Arc, vec::Vec};

Expand Down Expand Up @@ -113,8 +112,7 @@ where
G: PartialEq + Encode + Decode + Debug + Send + Sync,
{
fn get_enclave_account(&self) -> Result<AccountId> {
let enclave_call_signing_key = self.get_enclave_call_signing_key()?;
Ok(enclave_call_signing_key.public().into())
self.get_enclave_call_signing_key().map(|key| key.public().into())
}

fn sign_call_with_self<TC: Encode + Debug + TrustedCallSigning<TCS>>(
Expand Down Expand Up @@ -143,11 +141,7 @@ where
))
}

fn sign(&self, payload: &[u8]) -> Result<(AccountId, Vec<u8>)> {
let enclave_account = self.get_enclave_account()?;
let enclave_call_signing_key = self.get_enclave_call_signing_key()?;

debug!(" [EnclaveSigner] VC pubkey: {:?}", enclave_call_signing_key.public().to_vec());
Ok((enclave_account, enclave_call_signing_key.sign(payload).0.to_vec()))
fn sign(&self, payload: &[u8]) -> Result<Vec<u8>> {
self.get_enclave_call_signing_key().map(|key| key.sign(payload).0.to_vec())
}
}
4 changes: 2 additions & 2 deletions tee-worker/core-primitives/stf-executor/src/mocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ impl<TCS: PartialEq + Encode + Debug> StfEnclaveSigning<TCS> for StfEnclaveSigne
Ok(trusted_call.sign(&KeyPair::Ed25519(Box::new(self.signer)), 1, &self.mr_enclave, shard))
}

fn sign(&self, _payload: &[u8]) -> Result<(AccountId, Vec<u8>)> {
Ok((self.signer.public().into(), [0u8; 32].to_vec()))
fn sign(&self, _payload: &[u8]) -> Result<Vec<u8>> {
Ok([0u8; 32].to_vec())
}
}

Expand Down
4 changes: 2 additions & 2 deletions tee-worker/core-primitives/stf-executor/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ where
shard: &ShardIdentifier,
) -> Result<TCS>;

// litentry
fn sign(&self, payload: &[u8]) -> Result<(AccountId, Vec<u8>)>;
// litentry: sign an opaque payload
fn sign(&self, payload: &[u8]) -> Result<Vec<u8>>;
}

/// Proposes a state update to `Externalities`.
Expand Down
6 changes: 6 additions & 0 deletions tee-worker/enclave-runtime/src/initialization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,13 @@ fn run_stf_task_handler() -> Result<(), Error> {
author_api.clone(),
));

let enclave_account = Arc::new(GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?);

let stf_task_context = StfTaskContext::new(
shielding_key_repository,
author_api,
stf_enclave_signer,
enclave_account,
state_handler,
ocall_api,
data_provider_config,
Expand All @@ -296,10 +299,13 @@ fn run_vc_issuance() -> Result<(), Error> {
author_api.clone(),
));

let enclave_account = Arc::new(GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?);

let stf_task_context = StfTaskContext::new(
shielding_key_repository,
author_api,
stf_enclave_signer,
enclave_account,
state_handler,
ocall_api,
data_provider_config,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use itp_stf_primitives::{
use itp_stf_state_observer::mock::ObserveStateMock;
use itp_test::mock::onchain_mock::OnchainMock;
use itp_top_pool_author::{mocks::AuthorApiMock, traits::AuthorApi};
use itp_types::{parentchain::ParentchainId, RsaRequest};
use itp_types::RsaRequest;
use litentry_primitives::Identity;
use sgx_crypto_helper::{rsa3072::Rsa3072KeyPair, RsaKeyPair};
use sp_core::Pair;
Expand Down
2 changes: 1 addition & 1 deletion tee-worker/enclave-runtime/src/test/tests_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use itp_stf_primitives::{
use itp_stf_state_handler::handle_state::HandleState;
use itp_test::mock::handle_state_mock;
use itp_top_pool_author::{test_utils::submit_operation_to_top_pool, traits::AuthorApi};
use itp_types::{parentchain::ParentchainId, AccountId, Balance, Block, Header};
use itp_types::{AccountId, Balance, Block, Header};
use its_primitives::{
traits::{
Block as BlockTrait, BlockData, Header as SidechainHeaderTrait,
Expand Down
20 changes: 8 additions & 12 deletions tee-worker/litentry/core/credentials/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam
use codec::{Decode, Encode};
use itp_stf_primitives::types::ShardIdentifier;
use itp_time_utils::{from_iso8601, now_as_iso8601};
use itp_types::{AccountId, BlockNumber as SidechainBlockNumber};
use itp_utils::stringify::account_id_to_string;
use itp_types::BlockNumber as SidechainBlockNumber;
use litentry_primitives::{Identity, ParentchainBlockNumber, Web3Network};
use log::*;
use scale_info::TypeInfo;
Expand Down Expand Up @@ -123,7 +122,6 @@ pub struct IssuerRuntimeVersion {
#[derive(Serialize, Deserialize, Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)]
#[serde(rename_all = "camelCase")]
pub struct Issuer {
/// ID of the TEE Worker
pub id: String,
pub name: String,
pub mrenclave: String,
Expand All @@ -134,10 +132,6 @@ impl Issuer {
pub fn is_empty(&self) -> bool {
self.mrenclave.is_empty() || self.mrenclave.is_empty()
}

pub fn set_id(&mut self, id: &AccountId) {
self.id = account_id_to_string(id);
}
}

#[derive(Serialize, Deserialize, Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)]
Expand Down Expand Up @@ -191,19 +185,20 @@ pub struct Proof {
/// Purpose of this proof, generally it is expected as a fixed value, such as 'assertionMethod'
pub proof_purpose: String,
/// The digital signature value(signature of hash)
/// TODO: it should be base-encoded value according to https://www.w3.org/TR/vc-data-integrity/#proofs
pub proof_value: String,
/// The public key from Issuer
/// Verification method, here it's the public key of the VC signer
pub verification_method: String,
}

impl Proof {
pub fn new(sig: &Vec<u8>, issuer: &AccountId) -> Self {
pub fn new(sig: &Vec<u8>, verification_method: String) -> Self {
Proof {
created: now_as_iso8601(),
proof_type: ProofType::Ed25519Signature2020,
proof_purpose: PROOF_PURPOSE.to_string(),
proof_value: format!("{}", HexDisplay::from(sig)),
verification_method: account_id_to_string(issuer),
verification_method,
}
}

Expand Down Expand Up @@ -274,8 +269,8 @@ impl Credential {
Ok(vc)
}

pub fn add_proof(&mut self, sig: &Vec<u8>, issuer: &AccountId) {
self.proof = Some(Proof::new(sig, issuer));
pub fn add_proof(&mut self, sig: &Vec<u8>, verification_method: String) {
self.proof = Some(Proof::new(sig, verification_method));
}

fn generate_id(&mut self) {
Expand Down Expand Up @@ -571,6 +566,7 @@ pub fn format_assertion_to_date() -> String {
#[cfg(test)]
mod tests {
use super::*;
use itp_types::AccountId;

#[test]
fn eval_simple_success() {
Expand Down
22 changes: 11 additions & 11 deletions tee-worker/litentry/core/stf-task/receiver/src/handler/assertion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use itp_stf_executor::traits::StfEnclaveSigning;
use itp_stf_state_handler::handle_state::HandleState;
use itp_top_pool_author::traits::AuthorApi;
use itp_types::ShardIdentifier;
use itp_utils::stringify::account_id_to_string;
use lc_credentials::credential_schema;
use lc_data_providers::DataProviderConfig;
use lc_dynamic_assertion::AssertionLogicRepository;
Expand All @@ -35,7 +36,7 @@ use litentry_primitives::{
VCMPError,
};
use log::*;
use sp_core::H160;
use sp_core::{Pair, H160};
use std::{format, string::ToString, sync::Arc, vec::Vec};

pub(crate) struct AssertionHandler<
Expand Down Expand Up @@ -83,9 +84,9 @@ where
// we shouldn't have the maximum text length limit in normal RSA3072 encryption, as the payload
// using enclave's shielding key is encrypted in chunks
let vc_payload = result;
if let Ok(enclave_signer) = self.context.enclave_signer.get_enclave_account() {
if let Ok(enclave_signer_account) = self.context.enclave_signer.get_enclave_account() {
let c = TrustedCall::request_vc_callback(
enclave_signer.into(),
enclave_signer_account.into(),
self.req.who.clone(),
self.req.assertion.clone(),
vc_payload,
Expand All @@ -107,9 +108,9 @@ where
sender: std::sync::mpsc::Sender<(ShardIdentifier, H256, TrustedCall)>,
) {
error!("Assertion build error: {error:?}");
if let Ok(enclave_signer) = self.context.enclave_signer.get_enclave_account() {
if let Ok(enclave_signer_account) = self.context.enclave_signer.get_enclave_account() {
let c = TrustedCall::handle_vcmp_error(
enclave_signer.into(),
enclave_signer_account.into(),
Some(self.req.who.clone()),
error,
self.req.req_ext_hash,
Expand Down Expand Up @@ -286,8 +287,7 @@ where
}?;

// post-process the credential
let signer = context.enclave_signer.as_ref();
let enclave_account = signer.get_enclave_account().map_err(|e| {
let enclave_signer_account = context.enclave_signer.get_enclave_account().map_err(|e| {
VCMPError::RequestVCFailed(
req.assertion.clone(),
ErrorDetail::StfError(ErrorString::truncate_from(format!("{e:?}").into())),
Expand All @@ -304,7 +304,8 @@ where
credential.credential_schema.id = schema;
}

credential.issuer.id = Identity::Substrate(enclave_account.into()).to_did().map_err(|e| {
let issuer_identity: Identity = context.enclave_account.public().into();
credential.issuer.id = issuer_identity.to_did().map_err(|e| {
VCMPError::RequestVCFailed(
req.assertion.clone(),
ErrorDetail::StfError(ErrorString::truncate_from(format!("{e:?}").into())),
Expand All @@ -315,15 +316,14 @@ where
.to_json()
.map_err(|_| VCMPError::RequestVCFailed(req.assertion.clone(), ErrorDetail::ParseError))?;
let payload = json_string.as_bytes();
let (enclave_account, sig) = signer.sign(payload).map_err(|e| {
let sig = context.enclave_signer.sign(payload).map_err(|e| {
VCMPError::RequestVCFailed(
req.assertion.clone(),
ErrorDetail::StfError(ErrorString::truncate_from(format!("{e:?}").into())),
)
})?;
debug!("Credential Payload signature: {:?}", sig);

credential.add_proof(&sig, &enclave_account);
credential.add_proof(&sig, account_id_to_string(&enclave_signer_account));
credential.validate().map_err(|e| {
VCMPError::RequestVCFailed(
req.assertion.clone(),
Expand Down
6 changes: 5 additions & 1 deletion tee-worker/litentry/core/stf-task/receiver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use lc_dynamic_assertion::AssertionLogicRepository;
use lc_evm_dynamic_assertions::AssertionRepositoryItem;
use lc_stf_task_sender::{init_stf_task_sender_storage, RequestType};
use log::*;
use sp_core::H160;
use sp_core::{ed25519::Pair as Ed25519Pair, H160};
use std::{
boxed::Box,
format,
Expand Down Expand Up @@ -99,6 +99,7 @@ pub struct StfTaskContext<
pub shielding_key: Arc<ShieldingKeyRepository>,
pub author_api: Arc<A>,
pub enclave_signer: Arc<S>,
pub enclave_account: Arc<Ed25519Pair>,
pub state_handler: Arc<H>,
pub ocall_api: Arc<O>,
pub data_provider_config: Arc<DataProviderConfig>,
Expand All @@ -118,10 +119,12 @@ where
<ShieldingKeyRepository as AccessKey>::KeyType: ShieldingCryptoEncrypt + 'static,
H::StateT: SgxExternalitiesTrait,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
shielding_key: Arc<ShieldingKeyRepository>,
author_api: Arc<A>,
enclave_signer: Arc<S>,
enclave_account: Arc<Ed25519Pair>,
state_handler: Arc<H>,
ocall_api: Arc<O>,
data_provider_config: Arc<DataProviderConfig>,
Expand All @@ -131,6 +134,7 @@ where
shielding_key,
author_api,
enclave_signer,
enclave_account,
state_handler,
ocall_api,
data_provider_config,
Expand Down
3 changes: 3 additions & 0 deletions tee-worker/litentry/core/stf-task/receiver/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ use itp_top_pool_author::mocks::AuthorApiMock;
use lc_evm_dynamic_assertions::repository::EvmAssertionRepository;
use lc_stf_task_sender::{SendStfRequest, StfRequestSender};
use litentry_primitives::Assertion;
use sp_core::{ed25519::Pair as Ed25519Pair, Pair};

#[test]
fn test_threadpool_behaviour() {
let shielding_key = ShieldingCryptoMock::default();
let shielding_key_repository_mock = KeyRepositoryMock::new(shielding_key.clone());
let author_mock = AuthorApiMock::default();
let stf_enclave_signer_mock = StfEnclaveSignerMock::default();
let enclave_account = Ed25519Pair::from_string("//Alice", None).unwrap();
let handle_state_mock = HandleStateMock::default();
let onchain_mock = OnchainMock::default();
let data_provider_conifg = DataProviderConfig::new().unwrap();
Expand All @@ -28,6 +30,7 @@ fn test_threadpool_behaviour() {
Arc::new(shielding_key_repository_mock),
author_mock.into(),
stf_enclave_signer_mock.into(),
enclave_account.into(),
handle_state_mock.into(),
onchain_mock.into(),
data_provider_conifg.into(),
Expand Down
46 changes: 22 additions & 24 deletions tee-worker/ts-tests/integration-tests/common/utils/assertion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,51 +118,42 @@ export async function assertVc(context: IntegrationTestContext, subject: CorePri
const { proof, ...vcWithoutProof } = vcPayloadJson;

// step 5
// prepare teebag enclave registry data for further checks
const parachainBlockHash = await context.api.query.system.blockHash(vcPayloadJson.parachainBlockNumber);
const apiAtVcIssuedBlock = await context.api.at(parachainBlockHash);
const enclaveIdentifier = await apiAtVcIssuedBlock.query.teebag.enclaveIdentifier('Identity');
const lastRegisteredEnclave = (
await apiAtVcIssuedBlock.query.teebag.enclaveRegistry(enclaveIdentifier[enclaveIdentifier.length - 1])
).unwrap();

// step 6
// check vc signature
const signature = Buffer.from(hexToU8a(`0x${proof.proofValue}`));
const message = Buffer.from(JSON.stringify(vcWithoutProof));
const vcPubkeyBytes = context.api.createType('Option<Bytes>', lastRegisteredEnclave.vcPubkey).unwrap();
const vcPubkey = Buffer.from(hexToU8a(vcPubkeyBytes.toHex()));
const vcPubkey = Buffer.from(hexToU8a(proof.verificationMethod));
const signatureStatus = await ed.verify(signature, message, vcPubkey);

assert.isTrue(signatureStatus, 'Check Vc signature error: signature should be valid');

// step 7
// check VC mrenclave with enclave's mrenclave from registry
// step 6
// lookup the teebag enclave regsitry to check mrenclave and vcPubkey
const parachainBlockHash = await context.api.query.system.blockHash(vcPayloadJson.parachainBlockNumber);
const apiAtVcIssuedBlock = await context.api.at(parachainBlockHash);
const enclaveAccount = trimPrefix(vcPayloadJson.issuer.id, 'did:litentry:substrate:');
const registeredEnclave = (await apiAtVcIssuedBlock.query.teebag.enclaveRegistry(enclaveAccount)).unwrap();

assert.equal(
vcPayloadJson.issuer.mrenclave,
base58.encode(lastRegisteredEnclave.mrenclave),
base58.encode(registeredEnclave.mrenclave),
"Check VC mrenclave: it should equal enclave's mrenclave from parachains enclave registry"
);

// step 8
// check vc issuer id
assert.equal(
vcPayloadJson.issuer.id,
`did:litentry:substrate:${vcPubkeyBytes.toHex()}`,
"Check VC id: it should equal enclave's pubkey from parachains enclave registry"
proof.verificationMethod,
registeredEnclave.vcPubkey,
"Check VC pubkey: it should equal enclave's vcPubkey from parachains enclave registry"
);

// step 9
// step 7
// check runtime version is present
assert.deepEqual(
vcPayloadJson.issuer.runtimeVersion,
{ parachain: 9181, sidechain: 107 },
{ parachain: 9181, sidechain: 108 },
'Check VC runtime version: it should equal the current defined versions'
);

// step 10
// step 8
// validate VC against schema

const schemaResult = await validateVcSchema(vcPayloadJson);

if (schemaResult.errors) console.log('Schema Validation errors: ', schemaResult.errors);
Expand Down Expand Up @@ -198,3 +189,10 @@ export async function assertIdGraphHash(
console.log('queried id graph hash: ', queriedIdGraphHash);
assert.equal(computedIdGraphHash, queriedIdGraphHash);
}

function trimPrefix(str: string, prefix: string): string {
if (str.startsWith(prefix)) {
return str.substring(prefix.length);
}
return str;
}

0 comments on commit 0f6d532

Please sign in to comment.