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
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_SHARD_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,16 +1,13 @@
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},
Expand All @@ -19,16 +16,9 @@ use jsonrpsee::{
use native_task_handler::NativeTask;
use parentchain_rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory};
use parity_scale_codec::{Decode, Encode};
use std::{fmt::Debug, sync::Arc};
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 @@ -86,47 +76,19 @@ fn handle_aes_request<
if request.shard().encode() != ctx.mrenclave.encode() {
return Err(ErrorCode::ServerError(INVALID_SHARD_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, &request.shard(), 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,74 @@
use crate::{
error_code::*,
native_call_authenticated::{verify_native_call_authenticated, NativeCallAuthenticated},
request::PlainRequest,
server::RpcContext,
};
use executor_primitives::utils::hex::{FromHexPrefixed, ToHexPrefixed};
use jsonrpsee::{
types::{ErrorCode, ErrorObject},
RpcModule,
};
use native_task_handler::NativeTask;
use parentchain_rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory};
use parity_scale_codec::Decode;
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 nca = NativeCallAuthenticated::decode(&mut request.payload.as_slice())
.map_err(|_| ErrorCode::ServerError(INVALID_NATIVE_CALL_AUTHENTICATED_CODE))?;

task::spawn_blocking({
let ctx = ctx.clone();
let nca = nca.clone();
move || {
verify_native_call_authenticated(ctx, &request.shard, Handle::current(), &nca)
}
})
.await
.map_err(|e| {
log::error!("Failed to verify native call authenticated: {:?}", e);
ErrorCode::InternalError
})?
.map_err(|e| {
log::error!("Failed to verify native call authenticated: {:?}", e);
ErrorCode::ServerError(AUTHENTICATION_FAILED_CODE)
})?;

let (response_sender, response_receiver) = oneshot::channel();

let native_task = NativeTask {
call: nca.call,
auth_type: nca.authentication.into(),
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");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
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, ShardIdentifier};
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>>,
shard: &ShardIdentifier,
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,
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,
),
};
authentication_result
}
6 changes: 6 additions & 0 deletions tee-worker/omni-executor/rpc-server/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ use executor_primitives::ShardIdentifier;
use parity_scale_codec::{Decode, Encode};
use std::fmt::Debug;

#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
pub struct PlainRequest {
pub shard: ShardIdentifier,
silva-fj marked this conversation as resolved.
Show resolved Hide resolved
pub payload: Vec<u8>,
}

// Represent a request that can be decrypted by the enclave
pub trait DecryptableRequest {
type Error;
Expand Down