use std::collections::HashMap;
use std::error::Error;
use std::time::Duration;
use http::{Request, Response, StatusCode};
use http_body_util::BodyExt;
use http_body_util::Empty;
use http_body_util::Full;
use hyper::body::Bytes;
use hyper::body::Incoming;
use hyper::service::service_fn;
use hyper_util::rt::TokioIo;
use libsodium_sys::{
crypto_sign_ed25519_pk_to_curve25519, crypto_sign_ed25519_sk_to_curve25519, crypto_sign_keypair,
};
use std::convert::Infallible;
use tokio::net::{TcpListener, TcpStream};
use tokio::time::sleep;
pub use marlin::scallop::*;
type Pcrs = [[u8; 48]; 3];
#[derive(Default)]
struct AuthStore {
store: HashMap<Key, Pcrs>,
}
impl ScallopAuthStore for AuthStore {
type State = Pcrs;
fn contains(&mut self, key: &Key) -> ContainsResponse<Pcrs> {
if let Some(pcrs) = self.store.get(key) {
ContainsResponse::Approved(pcrs.to_owned())
} else {
ContainsResponse::NotFound
}
}
fn verify(&mut self, attestation: &[u8], key: Key) -> Option<Pcrs> {
if attestation == b"good auth" {
self.store.insert(key, [[1u8; 48], [2u8; 48], [3u8; 48]]);
Some([[1u8; 48], [2u8; 48], [3u8; 48]])
} else {
None
}
}
}
struct Auther {}
impl ScallopAuther for Auther {
type Error = ();
async fn new_auth(&mut self) -> Result<Box<[u8]>, ()> {
Ok(b"good auth".to_owned().into())
}
}
async fn hello(_req: Request<Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
println!("server: hello");
Ok(Response::new("Hello World!".into()))
}
async fn server_task(key: Key) -> Result<(), Box<dyn Error + Send + Sync>> {
let server = TcpListener::bind("127.0.0.1:21000").await?;
let mut auth_store = AuthStore::default();
let mut auther = Auther {};
loop {
let (stream, _) = server.accept().await?;
let stream = new_server_async_Noise_IX_25519_ChaChaPoly_BLAKE2b(
stream,
&key,
Some(&mut auth_store),
Some(&mut auther),
)
.await?;
println!("Client key: {:?}", stream.get_remote_static());
let stream = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(http_err) = hyper::server::conn::http1::Builder::new()
.keep_alive(true)
.serve_connection(stream, service_fn(hello))
.await
{
eprintln!("Error while serving HTTP connection: {}", http_err);
}
});
}
}
async fn client_task(key: Key) -> Result<(), Box<dyn Error + Send + Sync>> {
let mut auth_store = AuthStore::default();
let mut auther = Auther {};
loop {
let stream = TcpStream::connect("127.0.0.1:21000").await?;
let stream = new_client_async_Noise_IX_25519_ChaChaPoly_BLAKE2b(
stream,
&key,
Some(&mut auth_store),
Some(&mut auther),
)
.await?;
println!("Server key: {:?}", stream.get_remote_static());
let stream = TokioIo::new(stream);
let (mut request_sender, connection) =
hyper::client::conn::http1::handshake(stream).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("Error in connection: {}", e);
}
});
let request = Request::builder()
.method("GET")
.body(Empty::<Bytes>::new())?;
let response = request_sender.send_request(request).await?;
assert!(response.status() == StatusCode::OK);
println!("{:?}", response.collect().await?.to_bytes());
request_sender.ready().await?;
let request = Request::builder()
.method("GET")
.body(Empty::<Bytes>::new())?;
let response = request_sender.send_request(request).await?;
assert!(response.status() == StatusCode::OK);
println!("{:?}", response.collect().await?.to_bytes());
sleep(Duration::from_secs(5)).await;
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let mut sign_pk = [0u8; 32];
let mut sign_sk = [0u8; 64];
let mut pk = [0u8; 32];
let mut sk = [0u8; 32];
unsafe { crypto_sign_keypair(sign_pk.as_mut_ptr(), sign_sk.as_mut_ptr()) };
unsafe { crypto_sign_ed25519_pk_to_curve25519(pk.as_mut_ptr(), sign_pk.as_ptr()) };
unsafe { crypto_sign_ed25519_sk_to_curve25519(sk.as_mut_ptr(), sign_sk.as_ptr()) };
tokio::spawn(server_task(sk));
sleep(Duration::from_secs(5)).await;
client_task(sk).await?;
Ok(())
}