tests/clib_ffi.rs
// clib_ffi.rs
//
// Tests the C FFI interface from Rust.
// Performs handshake and exchanges a few messages.
//
use ossuary::clib::{
ossuary_create_connection,
ossuary_destroy_connection,
ossuary_set_secret_key,
ossuary_add_authorized_keys,
ossuary_send_handshake,
ossuary_recv_handshake,
ossuary_handshake_done,
ossuary_send_data,
ossuary_recv_data,
ossuary_remote_public_key,
ossuary_add_authorized_key,
OSSUARY_ERR_UNTRUSTED_SERVER,
};
use std::thread;
use std::net::{TcpListener, TcpStream};
use std::io::{Write};
use std::io::BufRead;
fn server() -> Result<(), std::io::Error> {
let listener = TcpListener::bind("127.0.0.1:9989").unwrap();
for stream in listener.incoming() {
let mut stream: TcpStream = stream.unwrap();
let mut reader = std::io::BufReader::new(stream.try_clone().unwrap());
let mut conn = ossuary_create_connection(1, ::std::ptr::null_mut());
let key: &[u8; 32] = &[0xbe, 0x1c, 0xa0, 0x74, 0xf4, 0xa5, 0x8b, 0xbb,
0xd2, 0x62, 0xa7, 0xf9, 0x52, 0x3b, 0x6f, 0xb0,
0xbb, 0x9e, 0x86, 0x62, 0x28, 0x7c, 0x33, 0x89,
0xa2, 0xe1, 0x63, 0xdc, 0x55, 0xde, 0x28, 0x1f];
let keys: &[*const u8; 1] = &[key as *const u8];
ossuary_add_authorized_keys(conn, keys as *const *const u8, keys.len() as u8);
let out_buf: [u8; 512] = [0; 512];
while ossuary_handshake_done(conn) == 0 {
let mut out_len = out_buf.len() as u16;
let wrote = ossuary_send_handshake(conn,
(&out_buf) as *const u8 as *mut u8,
&mut out_len);
if wrote >= 0 {
let _ = stream.write_all(&out_buf[0..wrote as usize]).unwrap();
let in_buf = reader.fill_buf().unwrap();
let mut in_len = in_buf.len() as u16;
if in_len > 0 {
let len = ossuary_recv_handshake(conn, in_buf as *const [u8] as *const u8, &mut in_len);
reader.consume(len as usize);
}
}
}
let mut plaintext: [u8; 256] = [0; 256];
plaintext[0..13].copy_from_slice("from server 1".as_bytes());
let mut out_len: u16 = out_buf.len() as u16;
let sz = ossuary_send_data(
conn,
(&plaintext) as *const u8 as *mut u8, 13 as u16,
(&out_buf) as *const u8 as *mut u8,
&mut out_len);
let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
plaintext[0..13].copy_from_slice("from server 2".as_bytes());
let mut out_len: u16 = out_buf.len() as u16;
let sz = ossuary_send_data(
conn,
(&plaintext) as *const u8 as *mut u8, 13 as u16,
(&out_buf) as *const u8 as *mut u8,
&mut out_len);
let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
let mut msgs = Vec::<String>::new();
let in_buf = reader.fill_buf().unwrap();
if in_buf.len() > 0 {
let mut out_len = out_buf.len() as u16;
let mut in_len = in_buf.len() as u16;
let len = ossuary_recv_data(
conn,
(in_buf) as *const [u8] as *mut u8, &mut in_len,
(&out_buf) as *const u8 as *mut u8, &mut out_len);
if len != -1 {
println!("CLIB READ: {:?}",
std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap());
msgs.push(std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap().into());
reader.consume(len as usize);
}
}
assert_eq!(msgs, vec!("from client".to_string()));
ossuary_destroy_connection(&mut conn);
break;
}
Ok(())
}
fn client() -> Result<(), std::io::Error> {
let mut stream = TcpStream::connect("127.0.0.1:9989").unwrap();
let mut conn = ossuary_create_connection(0, ::std::ptr::null_mut());
let key: &[u8; 32] = &[0x10, 0x86, 0x6e, 0xc4, 0x8a, 0x11, 0xf3, 0xc5,
0x6d, 0x77, 0xa6, 0x4b, 0x2f, 0x54, 0xaa, 0x06,
0x6c, 0x0c, 0xb4, 0x75, 0xd8, 0xc8, 0x7d, 0x35,
0xb4, 0x91, 0xee, 0xd6, 0xac, 0x0b, 0xde, 0xbc];
ossuary_set_secret_key(conn, key as *const u8);
let out_buf: [u8; 512] = [0; 512];
let mut reader = std::io::BufReader::new(stream.try_clone().unwrap());
loop {
match ossuary_handshake_done(conn) {
0 => {},
x if x > 0 => break,
OSSUARY_ERR_UNTRUSTED_SERVER => {
let key = [0u8; 32];
ossuary_remote_public_key(conn, &key as *const u8 as *mut u8, key.len() as u16);
ossuary_add_authorized_key(conn, &key as *const u8);
continue;
},
x => panic!("handshake failed: {}", x),
}
let mut out_len = out_buf.len() as u16;
let wrote = ossuary_send_handshake(conn,
(&out_buf) as *const u8 as *mut u8,
&mut out_len);
if wrote >= 0 {
let _ = stream.write_all(&out_buf[0.. wrote as usize]).unwrap();
let in_buf = reader.fill_buf().unwrap();
let mut in_len = in_buf.len() as u16;
let len = ossuary_recv_handshake(conn,
in_buf as *const [u8] as *const u8,
&mut in_len);
reader.consume(len as usize);
}
}
let out_buf: [u8; 256] = [0; 256];
let mut plaintext: [u8; 256] = [0; 256];
plaintext[0..11].copy_from_slice("from client".as_bytes());
let mut out_len: u16 = out_buf.len() as u16;
let sz = ossuary_send_data(
conn,
(&plaintext) as *const u8 as *mut u8, 11 as u16,
(&out_buf) as *const u8 as *mut u8,
&mut out_len);
let _ = stream.write_all(&out_buf[0..sz as usize]).unwrap();
//let mut stream = std::io::BufReader::new(stream);
let mut count = 0;
let mut msgs = Vec::<String>::new();
loop {
let in_buf = reader.fill_buf().unwrap();
if in_buf.len() == 0 || count == 2 {
break;
}
let mut out_len = out_buf.len() as u16;
let mut in_len = in_buf.len() as u16;
let len = ossuary_recv_data(
conn,
in_buf as *const [u8] as *mut u8, &mut in_len,
(&out_buf) as *const u8 as *mut u8, &mut out_len);
if len == -1 {
break;
}
if len > 0 {
println!("CLIB READ: {:?}",
std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap());
msgs.push(std::str::from_utf8(&out_buf[0..out_len as usize]).unwrap().into());
reader.consume(len as usize);
count += 1;
}
}
assert_eq!(msgs, vec!("from server 1".to_string(), "from server 2".to_string()));
ossuary_destroy_connection(&mut conn);
Ok(())
}
#[test]
fn test_clib() {
let server = thread::spawn(move || { let _ = server(); });
std::thread::sleep(std::time::Duration::from_millis(500));
let child = thread::spawn(move || { let _ = client(); });
let _ = child.join();
let _ = server.join();
}