Skip to content

Commit

Permalink
Adding native_submitPlainRequest RPC method (#3245)
Browse files Browse the repository at this point in the history
  • Loading branch information
silva-fj authored Feb 5, 2025
1 parent 005845e commit a2f2fb9
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 77 deletions.
4 changes: 3 additions & 1 deletion tee-worker/omni-executor/executor-primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ pub mod signature;
pub mod utils;
pub use heima_primitives::{
omni_account::{MemberAccount, OmniAccountAuthType},
AccountId, BlockNumber, Hash, Identity, Nonce, ShardIdentifier, Web2IdentityType,
AccountId, BlockNumber, Hash, Identity, Nonce, Web2IdentityType,
};

pub type MrEnclave = Hash;

use parity_scale_codec::{Decode, Encode};
use std::fmt::Debug;

Expand Down
8 changes: 3 additions & 5 deletions tee-worker/omni-executor/rpc-server/src/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::server::RpcContext;
use executor_core::native_call::NativeCall;
use executor_crypto::hashing::blake2_256;
use executor_primitives::{
signature::HeimaMultiSignature, utils::hex::hex_encode, Identity, OmniAccountAuthType,
ShardIdentifier, Web2IdentityType,
signature::HeimaMultiSignature, utils::hex::hex_encode, Identity, MrEnclave,
OmniAccountAuthType, Web2IdentityType,
};
use executor_storage::{OAuth2StateVerifierStorage, Storage, VerificationCodeStorage};
use heima_authentication::auth_token::{AuthTokenValidator, Validation};
Expand Down Expand Up @@ -89,13 +89,11 @@ pub fn verify_web3_authentication(
signature: &HeimaMultiSignature,
call: &NativeCall,
nonce: u32,
mrenclave: &[u8; 32],
shard: &ShardIdentifier,
mrenclave: MrEnclave,
) -> Result<(), AuthenticationError> {
let mut payload = call.encode();
payload.append(&mut nonce.encode());
payload.append(&mut mrenclave.encode());
payload.append(&mut shard.encode());

// The signature should be valid in either case:
// 1. blake2_256(payload)
Expand Down
10 changes: 6 additions & 4 deletions tee-worker/omni-executor/rpc-server/src/error_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// see https://www.jsonrpc.org/specification#error_object

pub const INVALID_AES_REQUEST_CODE: i32 = -32000;
pub const INVALID_SHARD_CODE: i32 = -32001;
pub const REQUEST_DECRYPTION_FAILED_CODE: i32 = -32002;
pub const INVALID_AUTHENTICATED_CALL_CODE: i32 = -32003;
pub const AUTHENTICATION_FAILED_CODE: i32 = -32004;
pub const INVALID_PLAIN_REQUEST_CODE: i32 = -32001;
pub const INVALID_MRENCLAVE_CODE: i32 = -32002;
pub const REQUEST_DECRYPTION_FAILED_CODE: i32 = -32003;
pub const INVALID_AUTHENTICATED_CALL_CODE: i32 = -32004;
pub const AUTHENTICATION_FAILED_CODE: i32 = -32005;
pub const INVALID_NATIVE_CALL_AUTHENTICATED_CODE: i32 = -32006;
1 change: 1 addition & 0 deletions tee-worker/omni-executor/rpc-server/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod authentication;
mod error_code;
mod methods;
mod native_call_authenticated;
mod request;
mod server;
mod shielding_key;
Expand Down
3 changes: 3 additions & 0 deletions tee-worker/omni-executor/rpc-server/src/methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod get_oauth2_google_authorization_url;
mod get_shielding_key;
mod request_email_verification_code;
mod submit_aes_request;
mod submit_plain_request;

use crate::server::RpcContext;
use get_oauth2_google_authorization_url::register_get_oauth2_google_authorization_url;
Expand All @@ -10,6 +11,7 @@ use jsonrpsee::RpcModule;
use parentchain_rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory};
use request_email_verification_code::register_request_email_verification_code;
use submit_aes_request::register_submit_aes_request;
use submit_plain_request::register_submit_plain_request;

pub fn register_methods<
AccountId: Send + Sync + 'static,
Expand All @@ -23,4 +25,5 @@ pub fn register_methods<
register_submit_aes_request(module);
register_request_email_verification_code(module);
register_get_oauth2_google_authorization_url(module);
register_submit_plain_request(module);
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
use crate::{
authentication::{
verify_auth_token_authentication, verify_email_authentication,
verify_oauth2_authentication, verify_web3_authentication, Authentication,
},
error_code::*,
native_call_authenticated::{verify_native_call_authenticated, NativeCallAuthenticated},
request::{AesRequest, DecryptableRequest},
server::RpcContext,
};
use executor_core::native_call::NativeCall;
use executor_primitives::{
utils::hex::{FromHexPrefixed, ToHexPrefixed},
Nonce, OmniAccountAuthType,
OmniAccountAuthType,
};
use jsonrpsee::{
types::{ErrorCode, ErrorObject},
RpcModule,
};
use native_task_handler::NativeTask;
use parentchain_rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory};
use parity_scale_codec::{Decode, Encode};
use std::{fmt::Debug, sync::Arc};
use parity_scale_codec::Decode;
use std::sync::Arc;
use tokio::{runtime::Handle, sync::oneshot, task};

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
pub struct AuthenticatedCall {
pub call: NativeCall,
pub nonce: Nonce,
pub authentication: Authentication,
}

pub fn register_submit_aes_request<
AccountId: Send + Sync + 'static,
Header: Send + Sync + 'static,
Expand All @@ -45,11 +35,11 @@ pub fn register_submit_aes_request<
let Ok(request) = AesRequest::from_hex(&hex_request) else {
return Err(ErrorCode::ServerError(INVALID_AES_REQUEST_CODE).into());
};
let context = ctx.clone();
let aes_request = request.clone();
let handle = Handle::current();
let join_handle =
task::spawn_blocking(|| handle_aes_request(aes_request, context, handle));
let join_handle = task::spawn_blocking({
let ctx = ctx.clone();
let aes_request = request.clone();
|| handle_aes_request(aes_request, ctx, Handle::current())
});
let (native_call, auth_type) = join_handle.await.map_err(|e| {
log::error!("Failed to handle AES request: {:?}", e);
ErrorCode::InternalError
Expand All @@ -64,7 +54,7 @@ pub fn register_submit_aes_request<
match response_receiver.await {
Ok(response) => Ok::<String, ErrorObject>(response.to_hex()),
Err(e) => {
log::error!("Failed to receive response from native call executor: {:?}", e);
log::error!("Failed to receive response from native call handler: {:?}", e);
Err(ErrorCode::InternalError.into())
},
}
Expand All @@ -83,50 +73,22 @@ fn handle_aes_request<
ctx: Arc<RpcContext<AccountId, Header, RpcClient, RpcClientFactory>>,
handle: Handle,
) -> Result<(NativeCall, OmniAccountAuthType), ErrorObject<'a>> {
if request.shard().encode() != ctx.mrenclave.encode() {
return Err(ErrorCode::ServerError(INVALID_SHARD_CODE).into());
if request.mrenclave() != ctx.mrenclave {
return Err(ErrorCode::ServerError(INVALID_MRENCLAVE_CODE).into());
}
let Ok(encoded_auth_call) = request.decrypt(Box::new(ctx.shielding_key.clone())) else {
let Ok(encoded_nca) = request.decrypt(Box::new(ctx.shielding_key.clone())) else {
return Err(ErrorCode::ServerError(REQUEST_DECRYPTION_FAILED_CODE).into());
};
let authenticated_call: AuthenticatedCall =
match AuthenticatedCall::decode(&mut encoded_auth_call.as_slice()) {
Ok(auth_call) => auth_call,
Err(e) => {
log::error!("Failed to decode authenticated call: {:?}", e);
return Err(ErrorCode::ServerError(INVALID_AUTHENTICATED_CALL_CODE).into());
},
};
let authentication_result = match authenticated_call.authentication {
Authentication::Web3(ref signature) => verify_web3_authentication(
signature,
&authenticated_call.call,
authenticated_call.nonce,
&ctx.mrenclave,
&request.shard,
),
Authentication::Email(ref verification_code) => verify_email_authentication(
ctx,
authenticated_call.call.sender_identity(),
verification_code,
),
Authentication::OAuth2(ref oauth2_data) => verify_oauth2_authentication(
ctx,
handle,
authenticated_call.call.sender_identity(),
oauth2_data,
),
Authentication::AuthToken(ref auth_token) => verify_auth_token_authentication(
ctx,
handle,
authenticated_call.call.sender_identity(),
auth_token,
),
let nca = match NativeCallAuthenticated::decode(&mut encoded_nca.as_slice()) {
Ok(nca) => nca,
Err(e) => {
log::error!("Failed to decode authenticated call: {:?}", e);
return Err(ErrorCode::ServerError(INVALID_AUTHENTICATED_CALL_CODE).into());
},
};

if authentication_result.is_err() {
if verify_native_call_authenticated(ctx, handle, &nca).is_err() {
return Err(ErrorCode::ServerError(AUTHENTICATION_FAILED_CODE).into());
}

Ok((authenticated_call.call, authenticated_call.authentication.into()))
Ok((nca.call, nca.authentication.into()))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::{
error_code::*,
native_call_authenticated::{verify_native_call_authenticated, NativeCallAuthenticated},
request::PlainRequest,
server::RpcContext,
};
use executor_core::native_call::NativeCall;
use executor_primitives::{
utils::hex::{FromHexPrefixed, ToHexPrefixed},
OmniAccountAuthType,
};
use jsonrpsee::{
types::{ErrorCode, ErrorObject},
RpcModule,
};
use native_task_handler::NativeTask;
use parentchain_rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory};
use parity_scale_codec::Decode;
use std::sync::Arc;
use tokio::{runtime::Handle, sync::oneshot, task};

pub fn register_submit_plain_request<
AccountId: Send + Sync + 'static,
Header: Send + Sync + 'static,
RpcClient: SubstrateRpcClient<AccountId, Header> + Send + Sync + 'static,
RpcClientFactory: SubstrateRpcClientFactory<AccountId, Header, RpcClient> + Send + Sync + 'static,
>(
module: &mut RpcModule<RpcContext<AccountId, Header, RpcClient, RpcClientFactory>>,
) {
module
.register_async_method("native_submitPlainRequest", |params, ctx, _| async move {
let Ok(hex_request) = params.one::<String>() else {
return Err(ErrorCode::ParseError.into());
};
let Ok(request) = PlainRequest::from_hex(&hex_request) else {
return Err(ErrorCode::ServerError(INVALID_PLAIN_REQUEST_CODE).into());
};
let join_handle = task::spawn_blocking({
let ctx = ctx.clone();
let plain_request = request.clone();
|| handle_plain_request(plain_request, ctx, Handle::current())
});
let (native_call, auth_type) = join_handle.await.map_err(|e| {
log::error!("Failed to handle Plain request: {:?}", e);
ErrorCode::InternalError
})??;
let (response_sender, response_receiver) = oneshot::channel();
let native_task = NativeTask { call: native_call, auth_type, response_sender };

if ctx.native_task_sender.send(native_task).await.is_err() {
log::error!("Failed to send request to native call executor");
return Err(ErrorCode::InternalError.into());
}
match response_receiver.await {
Ok(response) => Ok::<String, ErrorObject>(response.to_hex()),
Err(e) => {
log::error!("Failed to receive response from native call handler: {:?}", e);
Err(ErrorCode::InternalError.into())
},
}
})
.expect("Failed to register native_submitPlainRequest method");
}

fn handle_plain_request<
'a,
AccountId,
Header,
RpcClient: SubstrateRpcClient<AccountId, Header>,
RpcClientFactory: SubstrateRpcClientFactory<AccountId, Header, RpcClient>,
>(
request: PlainRequest,
ctx: Arc<RpcContext<AccountId, Header, RpcClient, RpcClientFactory>>,
handle: Handle,
) -> Result<(NativeCall, OmniAccountAuthType), ErrorObject<'a>> {
if request.mrenclave != ctx.mrenclave {
return Err(ErrorCode::ServerError(INVALID_MRENCLAVE_CODE).into());
}
let nca = NativeCallAuthenticated::decode(&mut request.payload.as_slice())
.map_err(|_| ErrorCode::ServerError(INVALID_NATIVE_CALL_AUTHENTICATED_CODE))?;

if verify_native_call_authenticated(ctx, handle, &nca).is_err() {
return Err(ErrorCode::ServerError(AUTHENTICATION_FAILED_CODE).into());
}

Ok((nca.call, nca.authentication.into()))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::{
authentication::{
verify_auth_token_authentication, verify_email_authentication,
verify_oauth2_authentication, verify_web3_authentication, Authentication,
AuthenticationError,
},
server::RpcContext,
};
use executor_core::native_call::NativeCall;
use executor_primitives::Nonce;
use parentchain_rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory};
use parity_scale_codec::{Decode, Encode};
use std::sync::Arc;
use tokio::runtime::Handle;

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
pub struct NativeCallAuthenticated {
pub call: NativeCall,
pub nonce: Nonce,
pub authentication: Authentication,
}

pub fn verify_native_call_authenticated<
AccountId,
Header,
RpcClient: SubstrateRpcClient<AccountId, Header>,
RpcClientFactory: SubstrateRpcClientFactory<AccountId, Header, RpcClient>,
>(
ctx: Arc<RpcContext<AccountId, Header, RpcClient, RpcClientFactory>>,
handle: Handle,
authenticated_call: &NativeCallAuthenticated,
) -> Result<(), AuthenticationError> {
let authentication_result = match authenticated_call.authentication {
Authentication::Web3(ref signature) => verify_web3_authentication(
signature,
&authenticated_call.call,
authenticated_call.nonce,
ctx.mrenclave,
),
Authentication::Email(ref verification_code) => verify_email_authentication(
ctx,
authenticated_call.call.sender_identity(),
verification_code,
),
Authentication::OAuth2(ref oauth2_data) => verify_oauth2_authentication(
ctx,
handle,
authenticated_call.call.sender_identity(),
oauth2_data,
),
Authentication::AuthToken(ref auth_token) => verify_auth_token_authentication(
ctx,
handle,
authenticated_call.call.sender_identity(),
auth_token,
),
};
authentication_result
}
Loading

0 comments on commit a2f2fb9

Please sign in to comment.