Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding native_submitPlainRequest RPC method #3245

Merged
merged 12 commits into from
Feb 5, 2025
Merged
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 aes_request = request.clone();
silva-fj marked this conversation as resolved.
Show resolved Hide resolved
|| handle_plain_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);
silva-fj marked this conversation as resolved.
Show resolved Hide resolved
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