src/clib.rs
//! Ossuary API exposed with a C FFI
//!
//! See `ossuary.h` for documentation.
//
// Copyright 2019 Trevor Bentley
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
use crate::{OssuaryConnection, ConnectionType, OssuaryError, KEY_LEN, generate_auth_keypair};
pub const OSSUARY_ERR_WOULD_BLOCK: i32 = -64;
pub const OSSUARY_ERR_UNTRUSTED_SERVER: i32 = -65;
#[no_mangle]
pub extern "C" fn ossuary_create_connection(conn_type: u8, auth_key: *const u8) -> *mut OssuaryConnection {
let conn_type: ConnectionType = match conn_type {
0 => ConnectionType::Client,
1 => ConnectionType::AuthenticatedServer,
2 => ConnectionType::UnauthenticatedServer,
_ => { return ::std::ptr::null_mut(); }
};
let key: Option<&[u8]> = match auth_key.is_null() {
false => unsafe { Some(std::slice::from_raw_parts(auth_key, 32)) },
true => None,
};
let conn = match OssuaryConnection::new(conn_type, key) {
Ok(c) => c,
Err(_e) => return ::std::ptr::null_mut(),
};
let mut conn = Box::new(conn);
let ptr: *mut _ = &mut *conn;
::std::mem::forget(conn);
ptr
}
#[no_mangle]
pub extern "C" fn ossuary_destroy_connection(conn: &mut *mut OssuaryConnection) {
if conn.is_null() {
return;
}
let obj: Box<OssuaryConnection> = unsafe { ::std::mem::transmute(*conn) };
::std::mem::drop(obj);
*conn = ::std::ptr::null_mut();
}
#[no_mangle]
pub extern "C" fn ossuary_add_authorized_key(conn: *mut OssuaryConnection,
key_buf: *const u8) -> i32 {
if conn.is_null() || key_buf.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let r_key_buf: &[u8] = unsafe {
std::slice::from_raw_parts(key_buf, KEY_LEN)
};
let res = match conn.add_authorized_key(r_key_buf) {
Ok(_) => 0i32,
Err(_) => -1i32,
};
::std::mem::forget(conn);
res
}
#[no_mangle]
pub extern "C" fn ossuary_add_authorized_keys(conn: *mut OssuaryConnection,
keys: *const *const u8,
key_count: u8) -> i32 {
if conn.is_null() || keys.is_null() {
return -1 as i32;
}
let conn = unsafe { &mut *conn };
let keys: &[*const u8] = unsafe { std::slice::from_raw_parts(keys, key_count as usize) };
let mut r_keys: Vec<&[u8]> = Vec::with_capacity(key_count as usize);
for key in keys {
if !key.is_null() {
let key: &[u8] = unsafe { std::slice::from_raw_parts(*key, 32) };
r_keys.push(key);
}
}
let written = match conn.add_authorized_keys(r_keys) {
Ok(c) => c as i32,
Err(_) => -1i32,
};
::std::mem::forget(conn);
written
}
#[no_mangle]
pub extern "C" fn ossuary_set_secret_key(conn: *mut OssuaryConnection,
key: *const u8) -> i32 {
if conn.is_null() || key.is_null() {
return -1 as i32;
}
let conn = unsafe { &mut *conn };
let key: &[u8] = unsafe { std::slice::from_raw_parts(key, 32) };
let success = match conn.set_secret_key(key) {
Ok(_) => 0i32,
Err(_) => -1i32,
};
::std::mem::forget(conn);
success
}
#[no_mangle]
pub extern "C" fn ossuary_recv_handshake(conn: *mut OssuaryConnection,
in_buf: *const u8, in_buf_len: *mut u16) -> i32 {
if conn.is_null() || in_buf.is_null() || in_buf_len.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let inlen = unsafe { *in_buf_len as usize };
let r_in_buf: &[u8] = unsafe { std::slice::from_raw_parts(in_buf, inlen) };
let mut slice = r_in_buf;
let read: i32 = match conn.recv_handshake(&mut slice) {
Ok(read) => {
unsafe { *in_buf_len = read as u16; }
read as i32
},
Err(OssuaryError::WouldBlock(b)) => {
unsafe { *in_buf_len = b as u16; }
OSSUARY_ERR_WOULD_BLOCK
},
_ => {
unsafe { *in_buf_len = 0u16; }
-1i32
},
};
::std::mem::forget(conn);
read as i32
}
#[no_mangle]
pub extern "C" fn ossuary_send_handshake(conn: *mut OssuaryConnection,
out_buf: *mut u8, out_buf_len: *mut u16) -> i32 {
if conn.is_null() || out_buf.is_null() || out_buf_len.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let outlen = unsafe { *out_buf_len as usize };
let r_out_buf: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(out_buf, outlen) };
let mut slice = r_out_buf;
let wrote: i32 = match conn.send_handshake(&mut slice) {
Ok(w) => {
unsafe { *out_buf_len = w as u16 };
w as i32
},
Err(OssuaryError::WouldBlock(w)) => {
unsafe { *out_buf_len = w as u16 };
OSSUARY_ERR_WOULD_BLOCK
},
Err(_) => {
unsafe { *out_buf_len = 0u16 };
-1
},
};
::std::mem::forget(conn);
wrote
}
#[no_mangle]
pub extern "C" fn ossuary_handshake_done(conn: *mut OssuaryConnection) -> i32 {
if conn.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let done = conn.handshake_done();
::std::mem::forget(conn);
match done {
Ok(done) => done as i32,
Err(OssuaryError::UntrustedServer(_)) => OSSUARY_ERR_UNTRUSTED_SERVER,
Err(_) => -1i32,
}
}
#[no_mangle]
pub extern "C" fn ossuary_send_data(conn: *mut OssuaryConnection,
in_buf: *mut u8, in_buf_len: u16,
out_buf: *mut u8, out_buf_len: *mut u16) -> i32 {
if conn.is_null() || in_buf.is_null() ||
out_buf.is_null() || out_buf_len.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let r_out_buf: &mut [u8] = unsafe {
std::slice::from_raw_parts_mut(out_buf, *out_buf_len as usize)
};
let r_in_buf: &[u8] = unsafe { std::slice::from_raw_parts(in_buf, in_buf_len as usize) };
let mut out_slice = r_out_buf;
let in_slice = r_in_buf;
let bytes_written = match conn.send_data(&in_slice, &mut out_slice) {
Ok(w) => {
unsafe { *out_buf_len = w as u16; }
w as i32
},
Err(OssuaryError::WouldBlock(w)) => {
unsafe { *out_buf_len = w as u16; }
OSSUARY_ERR_WOULD_BLOCK
},
Err(_) => {
unsafe { *out_buf_len = 0u16; }
-1i32
},
};
::std::mem::forget(conn);
bytes_written
}
#[no_mangle]
pub extern "C" fn ossuary_recv_data(conn: *mut OssuaryConnection,
in_buf: *mut u8, in_buf_len: *mut u16,
out_buf: *mut u8, out_buf_len: *mut u16) -> i32 {
if conn.is_null() || in_buf.is_null() || out_buf.is_null() ||
in_buf_len.is_null() || out_buf_len.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let r_out_buf: &mut [u8] = unsafe {
std::slice::from_raw_parts_mut(out_buf, *out_buf_len as usize)
};
let r_in_buf: &[u8] = unsafe { std::slice::from_raw_parts(in_buf, *in_buf_len as usize) };
let mut out_slice = r_out_buf;
let mut in_slice = r_in_buf;
let bytes_read = match conn.recv_data(&mut in_slice, &mut out_slice) {
Ok((read,written)) => {
unsafe {
*in_buf_len = read as u16;
*out_buf_len = written as u16;
};
read as i32
},
Err(OssuaryError::WouldBlock(r)) => {
unsafe {
*in_buf_len = r as u16;
*out_buf_len = 0u16;
};
OSSUARY_ERR_WOULD_BLOCK
},
Err(_) => {
unsafe {
*in_buf_len = 0u16;
*out_buf_len = 0u16;
}
-1i32
},
};
::std::mem::forget(conn);
bytes_read as i32
}
#[no_mangle]
pub extern "C" fn ossuary_flush(conn: *mut OssuaryConnection,
out_buf: *mut u8, out_buf_len: u16) -> i32 {
if conn.is_null() || out_buf.is_null() {
return -1i32;
}
let conn = unsafe { &mut *conn };
let r_out_buf: &mut [u8] = unsafe {
std::slice::from_raw_parts_mut(out_buf, out_buf_len as usize)
};
let mut out_slice = r_out_buf;
let bytes_written = match conn.flush(&mut out_slice) {
Ok(x) => x as i32,
Err(OssuaryError::WouldBlock(_)) => OSSUARY_ERR_WOULD_BLOCK,
Err(_) => -1i32,
};
::std::mem::forget(conn);
bytes_written
}
#[no_mangle]
pub extern "C" fn ossuary_remote_public_key(conn: *mut OssuaryConnection,
key_buf: *mut u8, key_buf_len: u16) -> i32 {
if conn.is_null() || key_buf.is_null() || key_buf_len < KEY_LEN as u16 {
return -1i32;
}
let conn = unsafe { &mut *conn };
let r_key_buf: &mut [u8] = unsafe {
std::slice::from_raw_parts_mut(key_buf, KEY_LEN)
};
let res = match conn.remote_public_key() {
Ok(key) => {
r_key_buf.copy_from_slice(key);
0i32
},
Err(_) => -1i32,
};
::std::mem::forget(conn);
res
}
#[no_mangle]
pub extern "C" fn ossuary_generate_auth_keypair(secret_buf: *mut u8, secret_buf_len: u16,
public_buf: *mut u8, public_buf_len: u16) -> i32 {
if secret_buf.is_null() || public_buf.is_null() {
return -1i32;
}
if secret_buf_len < KEY_LEN as u16 || public_buf_len < KEY_LEN as u16 {
return -1i32;
}
let r_secret: &mut [u8] = unsafe {
std::slice::from_raw_parts_mut(secret_buf, KEY_LEN)
};
let r_public: &mut [u8] = unsafe {
std::slice::from_raw_parts_mut(public_buf, KEY_LEN)
};
let res = match generate_auth_keypair() {
Ok((s,p)) => {
r_secret.copy_from_slice(&s);
r_public.copy_from_slice(&p);
0i32
}
_ => -1i32,
};
res
}