#![cfg_attr(feature = "sgx", no_std)]
#[cfg(feature = "sgx")]
extern crate sgx_tstd as std;
#[cfg(feature = "sgx")]
use sgx_types::*;
use super::SgxError;
pub struct SgxNetworking {
#[cfg(feature = "sgx")]
secure_channels: Vec<SecureChannel>,
}
pub struct SecureChannel {
channel_id: [u8; 16],
remote_public_key: Option<[u8; 64]>,
session_key: Option<[u8; 32]>,
nonce: u64,
}
impl SgxNetworking {
pub fn new() -> Self {
Self {
#[cfg(feature = "sgx")]
secure_channels: Vec::new(),
}
}
#[cfg(feature = "sgx")]
pub fn establish_channel(&mut self, remote_id: &[u8; 16]) -> Result<SecureChannel, SgxError> {
use super::crypto::SgxCrypto;
let crypto = SgxCrypto::new()?;
let private_key = crypto.random_bytes(32)?;
let mut private_key_array = [0u8; 32];
private_key_array.copy_from_slice(&private_key);
let channel = SecureChannel {
channel_id: *remote_id,
remote_public_key: None,
session_key: None,
nonce: 0,
};
self.secure_channels.push(channel.clone());
Ok(channel)
}
#[cfg(not(feature = "sgx"))]
pub fn establish_channel(&mut self, remote_id: &[u8; 16]) -> Result<SecureChannel, SgxError> {
Ok(SecureChannel {
channel_id: *remote_id,
remote_public_key: None,
session_key: None,
nonce: 0,
})
}
pub fn send_secure(
&mut self,
channel: &mut SecureChannel,
data: &[u8],
) -> Result<Vec<u8>, SgxError> {
let encrypted = self.encrypt_message(channel, data)?;
channel.nonce += 1;
Ok(encrypted)
}
pub fn receive_secure(
&mut self,
channel: &mut SecureChannel,
encrypted_data: &[u8],
) -> Result<Vec<u8>, SgxError> {
let decrypted = self.decrypt_message(channel, encrypted_data)?;
channel.nonce += 1;
Ok(decrypted)
}
fn encrypt_message(&self, channel: &SecureChannel, data: &[u8]) -> Result<Vec<u8>, SgxError> {
let session_key = channel
.session_key
.ok_or_else(|| SgxError::NetworkError("No session key established".into()))?;
#[cfg(feature = "sgx")]
{
use sgx_tcrypto::*;
let mut encrypted = vec![0u8; data.len() + 16]; let mut mac = sgx_aes_gcm_128bit_tag_t::default();
let mut iv = [0u8; 12];
iv[..8].copy_from_slice(&channel.nonce.to_le_bytes());
let result = unsafe {
sgx_rijndael128GCM_encrypt(
&session_key as *const _ as *const sgx_aes_gcm_128bit_key_t,
data.as_ptr(),
data.len() as u32,
encrypted.as_mut_ptr(),
&iv as *const u8,
12,
std::ptr::null(),
0,
&mut mac as *mut _,
)
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::NetworkError("Encryption failed".into()));
}
encrypted.extend_from_slice(&mac);
Ok(encrypted)
}
#[cfg(not(feature = "sgx"))]
{
let _ = (data, session_key); Err(SgxError::NetworkError(
"Secure channel encryption requires SGX. Use SGX-enabled build for production."
.into(),
))
}
}
fn decrypt_message(
&self,
channel: &SecureChannel,
encrypted_data: &[u8],
) -> Result<Vec<u8>, SgxError> {
let session_key = channel
.session_key
.ok_or_else(|| SgxError::NetworkError("No session key established".into()))?;
#[cfg(feature = "sgx")]
{
use sgx_tcrypto::*;
if encrypted_data.len() < 16 {
return Err(SgxError::NetworkError("Invalid encrypted data".into()));
}
let data_len = encrypted_data.len() - 16;
let mut decrypted = vec![0u8; data_len];
let mut mac = sgx_aes_gcm_128bit_tag_t::default();
mac.copy_from_slice(&encrypted_data[data_len..]);
let mut iv = [0u8; 12];
iv[..8].copy_from_slice(&channel.nonce.to_le_bytes());
let result = unsafe {
sgx_rijndael128GCM_decrypt(
&session_key as *const _ as *const sgx_aes_gcm_128bit_key_t,
encrypted_data.as_ptr(),
data_len as u32,
decrypted.as_mut_ptr(),
&iv as *const u8,
12,
std::ptr::null(),
0,
&mac as *const _,
)
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::NetworkError("Decryption failed".into()));
}
Ok(decrypted)
}
#[cfg(not(feature = "sgx"))]
{
let _ = (encrypted_data, session_key); Err(SgxError::NetworkError(
"Secure channel decryption requires SGX. Use SGX-enabled build for production."
.into(),
))
}
}
}
impl SecureChannel {
#[cfg(feature = "sgx")]
fn clone(&self) -> Self {
Self {
channel_id: self.channel_id,
remote_public_key: self.remote_public_key,
session_key: self.session_key,
nonce: self.nonce,
}
}
pub fn complete_handshake(&mut self, remote_public_key: &[u8; 64]) -> Result<(), SgxError> {
#[cfg(feature = "sgx")]
{
use super::crypto::SgxCrypto;
self.remote_public_key = Some(*remote_public_key);
let crypto = SgxCrypto::new()?;
let shared_secret = if let Some(private_key) = &self.enclave_private_key {
crypto.compute_shared_secret(private_key, remote_public_key)?
} else {
return Err(SgxError::NetworkingError("Local enclave private key is missing".to_string()));
};
let mut session_key = [0u8; 32];
session_key.copy_from_slice(&shared_secret);
self.session_key = Some(session_key);
Ok(())
}
#[cfg(not(feature = "sgx"))]
{
let _ = remote_public_key; Err(SgxError::NetworkError(
"Secure channel handshake requires SGX. Use SGX-enabled build for production."
.into(),
))
}
}
pub fn is_established(&self) -> bool {
self.session_key.is_some()
}
}
#[cfg(feature = "sgx")]
pub fn ocall_network_request(request: &[u8]) -> Result<Vec<u8>, SgxError> {
let mut response = vec![0u8; 4096];
let mut actual_len = 0usize;
let result = unsafe {
ocall_neo_rpc_request(
request.as_ptr(),
request.len(),
response.as_mut_ptr(),
response.len(),
&mut actual_len as *mut _,
)
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::NetworkError("OCALL failed".into()));
}
response.truncate(actual_len);
Ok(response)
}
#[cfg(feature = "sgx")]
extern "C" {
fn ocall_neo_rpc_request(
request: *const u8,
request_len: usize,
response: *mut u8,
response_len: usize,
actual_response_len: *mut usize,
) -> sgx_status_t;
}
#[cfg(not(feature = "sgx"))]
pub fn ocall_network_request(_request: &[u8]) -> Result<Vec<u8>, SgxError> {
Err(SgxError::NetworkError(
"SGX network requests require SGX. Use SGX-enabled build for production.".into(),
))
}