migrate hacker challenge on ratls

This commit is contained in:
Valentyn Faychuk 2024-10-06 13:28:18 +03:00
parent e361eba2ca
commit 9f7a8fb602
10 changed files with 973 additions and 343 deletions

1049
rewrite/Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -4,23 +4,44 @@ version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = "4.9.0"
async-stream = "0.3.5"
chrono = "0.4.38"
dashmap = "6.1.0"
prost = "0.13.2"
prost-types = "0.13.2"
rand = "0.8.5"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
solana-client = "2.0.11"
solana-program = "2.0.11"
solana-sdk = "2.0.10"
spl-associated-token-account = "5.0.1"
spl-token = "6.0.0"
tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread", "fs"] }
tokio-stream = { version = "0.1.16", features = ["sync"] }
tonic = "0.12.1"
actix-web = "4.9"
async-stream = "0.3"
chrono = "0.4"
dashmap = "6.1"
prost = "0.13"
prost-types = "0.13"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
solana-client = "2.0"
solana-program = "2.0"
solana-sdk = "2.0"
spl-associated-token-account = "5.0"
spl-token = "6.0"
tokio = { version = "1.40", features = ["macros", "rt-multi-thread", "fs"] } # this can be "full"
tokio-stream = { version = "0.1", features = ["sync"] }
tonic = "0.12"
# sgx poc dependencies
rustls = "0.23"
x509-parser = "0.16"
ring = "0.17" # hash256
rcgen = "0.13"
log = "0.4"
hex = "0.4"
tokio-rustls = "0.26"
tower = { version = "0.5", features = ["full"] }
tower-http = { version = "0.5", features = ["full"] }
hyper = "1.4.1"
hyper-util = "0.1.7"
hyper-rustls = { version = "0.27", features = ["http2"] }
base64 = "0.22"
lazy_static = "1.5"
# TODO: create a feature for testing, make occlum feature optional and added only if not compiling for testing
occlum-ratls = { git = "ssh://git@gitea.detee.cloud/vfaychuk/occlum-ratls", features = ["tonic", "occlum"] }
[build-dependencies]
tonic-build = "0.12.1"
tonic-build = "0.12"
[patch.crates-io.curve25519-dalek]
git = "https://github.com/anza-xyz/curve25519-dalek.git"
rev = "b500cdc2a920cd5bff9e2dd974d7b97349d61464"

@ -1,9 +1,6 @@
fn main() {
tonic_build::configure()
.build_server(true)
.compile(
&["proto/challenge.proto"],
&["proto"],
)
.compile_protos(&["proto/challenge.proto"], &["proto"])
.unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
}

@ -1,3 +1,3 @@
reorder_impl_items = true
use_small_heuristics = "Max"
merge_imports = true
imports_granularity = "Crate"

@ -48,8 +48,48 @@ impl ConnManager {
}
async fn connect(&self, node_ip: String) -> Result<(), Box<dyn std::error::Error>> {
use hyper::Uri;
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
use occlum_ratls::{prelude::*, RaTlsConfigBuilder};
use tokio_rustls::rustls::ClientConfig;
println!("Connecting to {node_ip}...");
let mut client = UpdateClient::connect(format!("http://{node_ip}:31373")).await?;
let mrsigner_hex = "83E8A0C3ED045D9747ADE06C3BFC70FCA661A4A65FF79A800223621162A88B76";
let mrsigner =
crate::sgx::mrsigner_from_hex(mrsigner_hex).expect("mrsigner decoding failed");
let config = RaTlsConfig::new()
.allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner]));
let tls = ClientConfig::from_ratls_config(config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?;
let mut http = HttpConnector::new();
http.enforce_http(false);
let cloned_node_ip = node_ip.clone();
let connector = tower::ServiceBuilder::new()
.layer_fn(move |s| {
let tls = tls.clone();
hyper_rustls::HttpsConnectorBuilder::new()
.with_tls_config(tls)
.https_or_http()
.enable_http2()
.wrap_connector(s)
})
.map_request(move |_| {
Uri::from_str(&format!("https://{cloned_node_ip}:31373"))
.expect("Could not parse URI")
})
.service(http);
let client =
hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector);
let uri = Uri::from_static("https://example.com");
let mut client = UpdateClient::with_origin(client, uri);
let rx = self.tx.subscribe();
let rx_stream = BroadcastStream::new(rx).filter_map(|n| n.ok());

@ -1,17 +1,14 @@
pub mod client;
pub mod server;
use crate::datastore;
use crate::datastore::NodeInfo;
use crate::NodeUpdate;
use std::time::SystemTime;
use std::time::{Duration, UNIX_EPOCH};
use crate::{datastore::NodeInfo, NodeUpdate};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub mod challenge {
tonic::include_proto!("challenge");
}
impl From<(String, datastore::NodeInfo)> for NodeUpdate {
fn from((ip, info): (String, datastore::NodeInfo)) -> Self {
impl From<(String, NodeInfo)> for NodeUpdate {
fn from((ip, info): (String, NodeInfo)) -> Self {
NodeUpdate {
ip: ip.to_string(),
started_at: Some(prost_types::Timestamp::from(info.started_at)),
@ -25,24 +22,20 @@ impl From<(String, datastore::NodeInfo)> for NodeUpdate {
}
}
impl Into<(String, datastore::NodeInfo)> for NodeUpdate {
fn into(self) -> (String, datastore::NodeInfo) {
impl Into<(String, NodeInfo)> for NodeUpdate {
fn into(self) -> (String, NodeInfo) {
let ip = self.ip;
let started_at: SystemTime = match self.started_at {
Some(ts) => {
let duration = Duration::new(ts.seconds as u64, ts.nanos as u32);
UNIX_EPOCH
.checked_add(duration)
.unwrap_or(SystemTime::now())
UNIX_EPOCH.checked_add(duration).unwrap_or(SystemTime::now())
}
None => SystemTime::now(),
};
let keepalive: SystemTime = match self.keepalive {
Some(ts) => {
let duration = Duration::new(ts.seconds as u64, ts.nanos as u32);
UNIX_EPOCH
.checked_add(duration)
.unwrap_or(SystemTime::now())
UNIX_EPOCH.checked_add(duration).unwrap_or(SystemTime::now())
}
None => SystemTime::now(),
};

@ -5,7 +5,7 @@ use crate::{datastore::Store, grpc::challenge::update_server::Update};
use std::{pin::Pin, sync::Arc};
use tokio::sync::broadcast::Sender;
use tokio_stream::{Stream, StreamExt};
use tonic::{transport::Server, Request, Response, Status, Streaming};
use tonic::{Request, Response, Status, Streaming};
pub struct MyServer {
ds: Arc<Store>,
@ -18,10 +18,90 @@ impl MyServer {
}
pub async fn start(self) {
let addr = "0.0.0.0:31373".parse().unwrap();
if let Err(e) = Server::builder().add_service(UpdateServer::new(self)).serve(addr).await {
println!("gRPC server failed: {e:?}");
use hyper::server::conn::http2::Builder;
use hyper_util::{
rt::{TokioExecutor, TokioIo},
service::TowerToHyperService,
};
use std::sync::Arc;
use tokio::net::TcpListener;
use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
use tonic::{body::boxed, service::Routes};
use tower::{ServiceBuilder, ServiceExt};
use occlum_ratls::{prelude::*, RaTlsConfigBuilder};
// TODO: ratls config should be global
// TODO: error handling, shouldn't have expects
let mrsigner_hex = "83E8A0C3ED045D9747ADE06C3BFC70FCA661A4A65FF79A800223621162A88B76";
let mrsigner =
crate::sgx::mrsigner_from_hex(mrsigner_hex).expect("mrsigner decoding failed");
let config = RaTlsConfig::new()
.allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner]));
let mut tls = ServerConfig::from_ratls_config(config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))
.expect("failed to create server config");
tls.alpn_protocols = vec![b"h2".to_vec()];
let svc = Routes::new(UpdateServer::new(self)).prepare();
let http = Builder::new(TokioExecutor::new());
let listener = TcpListener::bind("0.0.0.0:31373").await.expect("failed to bind listener");
let tls_acceptor = TlsAcceptor::from(Arc::new(tls));
loop {
let (conn, addr) = match listener.accept().await {
Ok(incoming) => incoming,
Err(e) => {
eprintln!("Error accepting connection: {}", e);
continue;
}
};
let http = http.clone();
let tls_acceptor = tls_acceptor.clone();
let svc = svc.clone();
tokio::spawn(async move {
let mut certificates = Vec::new();
let conn = tls_acceptor
.accept_with(conn, |info| {
if let Some(certs) = info.peer_certificates() {
for cert in certs {
certificates.push(cert.clone());
}
}
})
.await
.unwrap();
#[derive(Debug)]
pub struct ConnInfo {
pub addr: std::net::SocketAddr,
pub certificates: Vec<rustls::pki_types::CertificateDer<'static>>,
}
let extension_layer =
tower_http::add_extension::AddExtensionLayer::new(Arc::new(ConnInfo {
addr,
certificates,
}));
let svc = ServiceBuilder::new().layer(extension_layer).service(svc);
http.serve_connection(
TokioIo::new(conn),
TowerToHyperService::new(
svc.map_request(|req: hyper::Request<_>| req.map(boxed)),
),
)
.await
.unwrap();
});
}
}
}

@ -2,7 +2,9 @@ mod datastore;
mod grpc;
mod http_server;
mod persistence;
mod sgx;
mod solana;
use crate::{datastore::LOCALHOST, grpc::challenge::NodeUpdate, solana::Client as SolClient};
use datastore::Store;
use solana_sdk::signer::Signer;

6
rewrite/src/sgx.rs Normal file

@ -0,0 +1,6 @@
// TODO: Use error types (define error types in error.rs, see occlum-ratls as an example)
pub fn mrsigner_from_hex(mrsigner_hex: &str) -> Result<[u8; 32], Box<dyn std::error::Error>> {
let mut mrsigner = [0u8; 32];
hex::decode_to_slice(mrsigner_hex, &mut mrsigner)?;
Ok(mrsigner)
}

@ -1,16 +1,17 @@
#![allow(dead_code)]
use solana_client::rpc_client::RpcClient;
use solana_program::program_pack::Pack;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::keypair::Keypair;
use solana_sdk::signer::Signer;
use solana_sdk::system_instruction;
use solana_sdk::transaction::Transaction;
use solana_sdk::{
pubkey::Pubkey, signature::keypair::Keypair, signer::Signer, system_instruction,
transaction::Transaction,
};
use spl_associated_token_account::{
get_associated_token_address, instruction::create_associated_token_account,
};
use spl_token::instruction::{initialize_mint, mint_to};
use spl_token::state::Mint;
use spl_token::{
instruction::{initialize_mint, mint_to},
state::Mint,
};
use std::error::Error;
use tokio::time::{sleep, Duration};
@ -27,19 +28,11 @@ impl Client {
let client = RpcClient::new(RPC_URL);
let keypair = Keypair::new();
let token = create_token(&client, &keypair).await;
Self {
client,
keypair,
token,
}
Self { client, keypair, token }
}
pub fn from(keypair: Keypair, token: Pubkey) -> Self {
Self {
client: RpcClient::new(RPC_URL),
keypair,
token,
}
Self { client: RpcClient::new(RPC_URL), keypair, token }
}
pub fn mint(&self, recipient: &Pubkey) -> Result<String, Box<dyn std::error::Error>> {
@ -118,9 +111,7 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey {
let mint_keypair = Keypair::new();
let payer = Keypair::from_base58_string(&keypair.to_base58_string());
let mint_rent = client
.get_minimum_balance_for_rent_exemption(Mint::LEN)
.unwrap();
let mint_rent = client.get_minimum_balance_for_rent_exemption(Mint::LEN).unwrap();
let create_mint_account_ix = system_instruction::create_account(
&payer.pubkey(),
@ -130,14 +121,9 @@ async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey {
&spl_token::id(),
);
let init_mint_ix = initialize_mint(
&spl_token::id(),
&mint_keypair.pubkey(),
&payer.pubkey(),
None,
9,
)
.unwrap();
let init_mint_ix =
initialize_mint(&spl_token::id(), &mint_keypair.pubkey(), &payer.pubkey(), None, 9)
.unwrap();
let recent_blockhash = client.get_latest_blockhash().unwrap();
let tx = Transaction::new_signed_with_payer(