Skip to content

Commit

Permalink
feat(call verify): support call msg prefixes for user signature (#2609)
Browse files Browse the repository at this point in the history
Signed-off-by: Jonathan Alvarez <jonathan@litentry.com>
  • Loading branch information
jonalvarezz committed Mar 30, 2024
1 parent 3560fb5 commit 9bdd719
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 135 deletions.
140 changes: 70 additions & 70 deletions tee-worker/Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tee-worker/app-libs/stf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ sp-std = { default-features = false, git = "https://github.com/paritytech/substr
# litentry
itp-node-api-metadata-provider = { path = "../../core-primitives/node-api/metadata-provider", default-features = false }
lc-stf-task-sender = { path = "../../litentry/core/stf-task/sender", default-features = false }
litentry-hex-utils = { path = "../../../primitives/hex", default-features = false }
litentry-macros = { path = "../../../primitives/core/macros", default-features = false }
litentry-primitives = { path = "../../litentry/primitives", default-features = false }
pallet-parentchain = { path = "../../../pallets/parentchain", default-features = false }
Expand Down
42 changes: 35 additions & 7 deletions tee-worker/app-libs/stf/src/getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use ita_sgx_runtime::{IdentityManagement, System};
use itp_stf_interface::ExecuteGetter;
use itp_stf_primitives::{traits::GetterAuthorization, types::KeyPair};
use itp_utils::stringify::account_id_to_string;
use litentry_hex_utils::hex_encode;
use litentry_macros::if_development_or;
use litentry_primitives::{Identity, LitentryMultiSignature};
use log::*;
Expand Down Expand Up @@ -146,6 +147,13 @@ impl TrustedGetter {
let signature = pair.sign(&blake2_256(self.encode().as_slice()));
TrustedGetterSigned { getter: self.clone(), signature }
}

pub fn signature_message_prefix(&self) -> String {
match self {
Self::id_graph(..) => "Our team is ready to support you in retrieving your on-chain identity securely. Please be assured, this process is safe and involves no transactions of your assets. Token: ".to_string(),
_ => "Token: ".to_string(),
}
}
}

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
Expand All @@ -160,19 +168,39 @@ impl TrustedGetterSigned {
}

pub fn verify_signature(&self) -> bool {
// The signature should be valid in either case:
// 1. payload
// 2. blake2_256(payload)
// 3. Signature Prefix + payload
// 4. Signature Prefix + blake2_256payload
//
// @TODO P-639: Remove 1 and 3.

let payload = self.getter.encode();
let hashed = blake2_256(&payload);

let prettified_msg_raw = self.getter.signature_message_prefix() + &hex_encode(&payload);
let prettified_msg_raw = prettified_msg_raw.as_bytes();

let prettified_msg_hash = self.getter.signature_message_prefix() + &hex_encode(&hashed);
let prettified_msg_hash = prettified_msg_hash.as_bytes();

// Most common signatures variants by clients are verified first (4 and 2).
let is_valid = self.signature.verify(prettified_msg_hash, self.getter.sender_identity())
|| self.signature.verify(&hashed, self.getter.sender_identity())
|| self.signature.verify(&payload, self.getter.sender_identity())
|| self.signature.verify(prettified_msg_raw, self.getter.sender_identity());

// in non-prod, we accept signature from Alice too
if_development_or!(
{
self.signature.verify(&payload, self.getter.sender_identity())
|| self.signature.verify(&blake2_256(&payload), self.getter.sender_identity())
is_valid
|| self.signature.verify(&payload, &ALICE_ACCOUNTID32.into())
|| self.signature.verify(&blake2_256(&payload), &ALICE_ACCOUNTID32.into())
|| self.signature.verify(&hashed, &ALICE_ACCOUNTID32.into())
|| self.signature.verify(prettified_msg_raw, &ALICE_ACCOUNTID32.into())
|| self.signature.verify(prettified_msg_hash, &ALICE_ACCOUNTID32.into())
},
{
self.signature.verify(&payload, self.getter.sender_identity())
|| self.signature.verify(&blake2_256(&payload), self.getter.sender_identity())
}
{ is_valid }
)
}
}
Expand Down
34 changes: 32 additions & 2 deletions tee-worker/app-libs/stf/src/trusted_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use itp_types::{
Address, Moment, OpaqueCall, H256,
};
use itp_utils::stringify::account_id_to_string;
use litentry_hex_utils::hex_encode;
pub use litentry_primitives::{
aes_encrypt_default, all_evm_web3networks, all_substrate_web3networks, AesOutput, Assertion,
ErrorDetail, IMPError, Identity, LitentryMultiSignature, ParentchainBlockNumber, RequestAesKey,
Expand Down Expand Up @@ -257,6 +258,17 @@ impl TrustedCall {
_ => "unsupported_trusted_call",
}
}

pub fn signature_message_prefix(&self) -> String {
match self {
Self::link_identity(..) => "By linking your identity to our platform, you're taking a step towards a more integrated experience. Please be assured, this process is safe and involves no transactions of your assets. Token: ".to_string(),
Self::request_batch_vc(_, _, assertions, ..) => match assertions.len() {
1 => "We are going to help you generate 1 secure credential. Please be assured, this process is safe and involves no transactions of your assets. Token: ".to_string(),
n => format!("We are going to help you generate {n} secure credentials. Please be assured, this process is safe and involves no transactions of your assets. Token: "),
},
_ => "Token: ".to_string(),
}
}
}

impl TrustedCallSigning<TrustedCallSigned> for TrustedCall {
Expand Down Expand Up @@ -326,9 +338,27 @@ impl TrustedCallVerification for TrustedCallSigned {
payload.append(&mut mrenclave.encode());
payload.append(&mut shard.encode());

// make it backwards compatible for now - will deprecate the old way later
self.signature.verify(&blake2_256(&payload), self.call.sender_identity())
// The signature should be valid in either case:
// 1. payload
// 2. blake2_256(payload)
// 3. Signature Prefix + payload
// 4. Signature Prefix + blake2_256(payload)
//
// @TODO P-639: Remove 1 and 3.

let hashed = blake2_256(&payload);

let prettified_msg_raw = self.call.signature_message_prefix() + &hex_encode(&payload);
let prettified_msg_raw = prettified_msg_raw.as_bytes();

let prettified_msg_hash = self.call.signature_message_prefix() + &hex_encode(&hashed);
let prettified_msg_hash = prettified_msg_hash.as_bytes();

// Most common signatures variants by clients are verified first (4 and 2).
self.signature.verify(prettified_msg_hash, self.call.sender_identity())
|| self.signature.verify(&hashed, self.call.sender_identity())
|| self.signature.verify(&payload, self.call.sender_identity())
|| self.signature.verify(prettified_msg_raw, self.call.sender_identity())
}

fn metric_name(&self) -> &'static str {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,7 @@ export default {
Sr25519: "Sr25519Signature",
Ecdsa: "EcdsaSignature",
Ethereum: "EthereumSignature",
EthereumPrettified: "EthereumSignature",
Bitcoin: "BitcoinSignature",
BitcoinPrettified: "BitcoinSignature",
},
},
Ed25519Signature: "([u8; 64])",
Expand Down
2 changes: 1 addition & 1 deletion tee-worker/enclave-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion tee-worker/litentry/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git", branch = "m
# internal dependencies
itp-sgx-crypto = { path = "../../core-primitives/sgx/crypto", default-features = false }
itp-utils = { path = "../../core-primitives/utils", default-features = false }
litentry-hex-utils = { path = "../../../primitives/hex", default-features = false }
pallet-teebag = { path = "../../../pallets/teebag", default-features = false }
parentchain-primitives = { package = "core-primitives", path = "../../../primitives/core", default-features = false }

Expand Down
29 changes: 6 additions & 23 deletions tee-worker/litentry/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ pub use validation_data::*;
use bitcoin::sign_message::{signed_msg_hash, MessageSignature};
use codec::{Decode, Encode, MaxEncodedLen};
use itp_sgx_crypto::ShieldingCryptoDecrypt;
use litentry_hex_utils::hex_encode;
use log::error;
pub use pallet_teebag::{
decl_rsa_request, extract_tcb_info_from_raw_dcap_quote, AttestationType, Enclave,
Expand Down Expand Up @@ -90,8 +89,6 @@ use std::string::{String, ToString};
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};

pub const LITENTRY_PRETTIFIED_MESSAGE_PREFIX: &str = "Litentry authorization token: ";

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum LitentryMultiSignature {
Expand All @@ -107,15 +104,9 @@ pub enum LitentryMultiSignature {
/// An ECDSA/keccak256 signature. An Ethereum signature. hash message with keccak256
#[codec(index = 3)]
Ethereum(EthereumSignature),
/// Same as above, but the payload bytes are prepended with a readable prefix and `0x`
#[codec(index = 4)]
EthereumPrettified(EthereumSignature),
/// Bitcoin signed message, a hex-encoded string of original &[u8] message, without `0x` prefix
#[codec(index = 5)]
#[codec(index = 4)]
Bitcoin(BitcoinSignature),
/// Same as above, but the payload bytes are prepended with a readable prefix and `0x`
#[codec(index = 6)]
BitcoinPrettified(BitcoinSignature),
}

impl LitentryMultiSignature {
Expand Down Expand Up @@ -157,26 +148,18 @@ impl LitentryMultiSignature {
Self::Ethereum(ref sig) =>
return verify_evm_signature(evm_eip191_wrap(msg).as_slice(), sig, signer)
|| verify_evm_signature(msg, sig, signer),
Self::EthereumPrettified(ref sig) => {
let prettified_msg =
LITENTRY_PRETTIFIED_MESSAGE_PREFIX.to_string() + &hex_encode(msg);
let msg = prettified_msg.as_bytes();
return verify_evm_signature(evm_eip191_wrap(msg).as_slice(), sig, signer)
|| verify_evm_signature(msg, sig, signer)
},
_ => false,
}
}

fn verify_bitcoin(&self, msg: &[u8], signer: &Address33) -> bool {
match self {
Self::Bitcoin(ref sig) =>
verify_bitcoin_signature(hex::encode(msg).as_str(), sig, signer),
Self::BitcoinPrettified(ref sig) => {
let prettified_msg =
LITENTRY_PRETTIFIED_MESSAGE_PREFIX.to_string() + &hex_encode(msg);
verify_bitcoin_signature(prettified_msg.as_str(), sig, signer)
},
verify_bitcoin_signature(hex::encode(msg).as_str(), sig, signer)
|| match std::str::from_utf8(msg) {
Err(_) => false,
Ok(prettified) => verify_bitcoin_signature(prettified, sig, signer),
},
_ => false,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export async function buildValidations(
signerIdentitity: CorePrimitivesIdentity,
linkIdentity: CorePrimitivesIdentity,
startingSidechainNonce: number,
network: 'ethereum' | 'substrate' | 'twitter' | 'bitcoin' | 'bitcoinPrettified',
network: 'ethereum' | 'substrate' | 'twitter' | 'bitcoin',
signer?: Signer
): Promise<LitentryValidationData> {
let evmSignature: HexString;
Expand Down Expand Up @@ -128,32 +128,6 @@ export async function buildValidations(
'LitentryValidationData',
bitcoinValidationData
);
validation = encodedVerifyIdentityValidation;
} else if (network === 'bitcoinPrettified') {
const bitcoinValidationData = {
Web3Validation: {
Bitcoin: {
message: '' as HexString,
signature: {
BitcoinPrettified: '' as HexString,
},
},
},
};
console.log('post verification msg to bitcoin: ', msg);
bitcoinValidationData.Web3Validation.Bitcoin.message = msg;
bitcoinSignature = await signer!.sign('Litentry authorization token: ' + msg);

bitcoinValidationData!.Web3Validation.Bitcoin.signature.BitcoinPrettified = u8aToHex(bitcoinSignature);
console.log('bitcoin pubkey: ', u8aToHex(signer!.getAddressRaw()));
console.log('bitcoin sig (base64): ', Buffer.from(bitcoinSignature).toString('base64'));

console.log('bitcoin sig (hex): ', u8aToHex(bitcoinSignature));
const encodedVerifyIdentityValidation: LitentryValidationData = context.api.createType(
'LitentryValidationData',
bitcoinValidationData
);

validation = encodedVerifyIdentityValidation;
} else if (network === 'twitter') {
console.log('post verification msg to twitter: ', msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,14 @@ describe('Test Identity (bitcoin direct invocation)', function () {
networks: aliceEvmNetworks,
});

// link another bitcoin account with prettified signature
// link another bitcoin account
const bobBitcoinNonce = currentNonce++;
const bobBitcoinValidation = await buildValidations(
context,
aliceBitcoinIdentity,
bobBitcoinIdentity,
bobBitcoinNonce,
'bitcoinPrettified',
'bitcoin',
context.web3Wallets.bitcoin.Bob
);
const bobBitcoinNetowrks = context.api.createType('Vec<Web3Network>', ['BitcoinP2tr']);
Expand Down

0 comments on commit 9bdd719

Please sign in to comment.