Skip to content

Commit

Permalink
Implement proper WorkQueue and callbacks, update C API
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Taubert committed Jul 7, 2017
1 parent 89aec0f commit eb312fa
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 148 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ env_logger = "0.4.1"
rust-crypto = "^0.2"
base64 = "^0.4"
libc = "^0.2"
boxfnonce = "0.0.3"

[replace]
"libudev-sys:0.1.3" = { git = "https://github.com/ttaubert/libudev-sys" }
22 changes: 13 additions & 9 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern crate u2fhid;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use std::io;
use std::sync::mpsc::channel;
use u2fhid::U2FManager;

#[macro_use] extern crate log;
Expand Down Expand Up @@ -37,21 +38,24 @@ fn main() {
let mut app_bytes: Vec<u8> = vec![0; application.output_bytes()];
application.result(&mut app_bytes);

let mut manager = U2FManager::new();
let manager = U2FManager::new().unwrap();

let register_data = manager.register(15, chall_bytes, app_bytes).unwrap();
println!("Register result: {}", base64::encode(&register_data));
let (tx, rx) = channel();
manager.register(15, chall_bytes.clone(), app_bytes.clone(), move |rv| {
tx.send(rv.unwrap()).unwrap();
}).unwrap();

let register_data = rx.recv().unwrap();
println!("Register result: {}", base64::encode(&register_data));
println!("Asking a security key to sign now, with the data from the register...");
let key_handle = u2f_get_key_handle_from_register_response(&register_data).unwrap();

let mut chall_bytes: Vec<u8> = vec![0; challenge.output_bytes()];
challenge.result(&mut chall_bytes);
let mut app_bytes: Vec<u8> = vec![0; application.output_bytes()];
application.result(&mut app_bytes);
let (tx, rx) = channel();
manager.sign(15, chall_bytes, app_bytes, key_handle, move |rv| {
tx.send(rv.unwrap()).unwrap();
}).unwrap();

let sign_data = manager.sign(15, chall_bytes, app_bytes, key_handle).unwrap();
let sign_data = rx.recv().unwrap();
println!("Sign result: {}", base64::encode(&sign_data));

println!("Done.");
}
150 changes: 150 additions & 0 deletions src/capi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use libc::size_t;
use std::collections::HashMap;
use std::{ptr, slice};

use ::U2FManager;

type U2FResult = HashMap<u8, Vec<u8>>;
type U2FCallback = extern "C" fn (u64, *mut U2FResult);

const RESBUF_ID_REGISTRATION : u8 = 0;
const RESBUF_ID_KEYHANDLE : u8 = 1;
const RESBUF_ID_SIGNATURE : u8 = 2;

unsafe fn from_raw(ptr: *const u8, len: usize) -> Vec<u8> {
slice::from_raw_parts(ptr, len).to_vec()
}

#[no_mangle]
pub extern "C" fn rust_u2f_mgr_new() -> *mut U2FManager
{
if let Ok(mgr) = U2FManager::new() {
Box::into_raw(Box::new(mgr))
} else {
ptr::null_mut()
}
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_free(mgr: *mut U2FManager)
{
if !mgr.is_null() {
Box::from_raw(mgr);
}
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_resbuf_length(res: *const U2FResult,
bid: u8,
len: *mut size_t) -> bool
{
if res.is_null() {
return false;
}

if let Some(buf) = (*res).get(&bid) {
*len = buf.len();
return true;
}

false
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_resbuf_copy(res: *const U2FResult,
bid: u8,
dst: *mut u8) -> bool
{
if res.is_null() {
return false;
}

if let Some(buf) = (*res).get(&bid) {
ptr::copy_nonoverlapping(buf.as_ptr(), dst, buf.len());
return true;
}

false
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_res_free(res: *mut U2FResult)
{
if !res.is_null() {
Box::from_raw(res);
}
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_register(mgr: *mut U2FManager,
tid: u64,
timeout: u64,
callback: U2FCallback,
challenge_ptr: *const u8,
challenge_len: usize,
application_ptr: *const u8,
application_len: usize) -> bool
{
if mgr.is_null() {
return false;
}

let challenge = from_raw(challenge_ptr, challenge_len);
let application = from_raw(application_ptr, application_len);

let res = (*mgr).register(timeout, challenge, application, move |rv| {
if let Ok(registration) = rv {
let mut result = U2FResult::new();
result.insert(RESBUF_ID_REGISTRATION, registration);
callback(tid, Box::into_raw(Box::new(result)));
} else {
callback(tid, ptr::null_mut());
};
});

res.is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_sign(mgr: *mut U2FManager,
tid: u64,
timeout: u64,
callback: U2FCallback,
challenge_ptr: *const u8,
challenge_len: usize,
application_ptr: *const u8,
application_len: usize,
key_handle_ptr: *const u8,
key_handle_len: usize) -> bool
{
if mgr.is_null() {
return false;
}

let challenge = from_raw(challenge_ptr, challenge_len);
let application = from_raw(application_ptr, application_len);
let key_handle = from_raw(key_handle_ptr, key_handle_len);

// TODO no need to clone as soon as sign() returns the chosen key handle
let res = (*mgr).sign(timeout, challenge, application, key_handle.clone(), move |rv| {
if let Ok(signature) = rv {
let mut result = U2FResult::new();
result.insert(RESBUF_ID_KEYHANDLE, key_handle);
result.insert(RESBUF_ID_SIGNATURE, signature);
callback(tid, Box::into_raw(Box::new(result)));
} else {
callback(tid, ptr::null_mut());
};
});

res.is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_cancel(mgr: *mut U2FManager)
{
if !mgr.is_null() {
// Ignore return value.
let _ = (*mgr).cancel();
}
}
113 changes: 33 additions & 80 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,97 +19,50 @@ pub mod platform;
#[macro_use] extern crate log;
extern crate rand;
extern crate libc;
extern crate boxfnonce;

mod consts;
mod manager;
mod runloop;
pub mod u2fprotocol;
// TODO
use std::io;
use boxfnonce::SendBoxFnOnce;
use std::sync::{Arc,Mutex};

use std::ptr;

pub use u2fprotocol::*;
pub use manager::U2FManager as U2FManager;
type Callback = SendBoxFnOnce<(io::Result<Vec<u8>>,)>;

#[no_mangle]
pub extern "C" fn rust_u2f_mgr_new() -> *mut U2FManager {
let manager = U2FManager::new();
Box::into_raw(Box::new(manager))
// TODO move this somewhere else?
pub struct OnceCallback {
callback: Arc<Mutex<Option<Callback>>>
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_free(ptr: *mut U2FManager) {
if !ptr.is_null() {
Box::from_raw(ptr);
impl OnceCallback {
fn new<F>(cb: F) -> Self
where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
{
let cb = Some(SendBoxFnOnce::from(cb));
Self { callback: Arc::new(Mutex::new(cb)) }
}
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_register(ptr: *mut U2FManager,
timeout: u64,
challenge_ptr: *const u8,
challenge_len: usize,
application_ptr: *const u8,
application_len: usize,
registration_ptr: *mut u8,
registration_len: *mut usize,
max_registration_len: usize) {
if ptr.is_null() {
return; // TODO error
}

let mut mgr = Box::from_raw(ptr);
let challenge = std::slice::from_raw_parts(challenge_ptr, challenge_len);
let application = std::slice::from_raw_parts(application_ptr, application_len);

let res = mgr.register(timeout, challenge.to_vec(), application.to_vec());
let _ = Box::into_raw(mgr);

let res = match res {
Ok(rv) => rv,
_ => return // TODO error
};

if res.len() > max_registration_len {
return; // TODO error
fn call(&self, rv: io::Result<Vec<u8>>) {
if let Ok(mut cb) = self.callback.lock() {
if let Some(cb) = cb.take() {
cb.call(rv);
}
}
}

*registration_len = res.len();
ptr::copy_nonoverlapping(res.as_ptr(), registration_ptr, res.len());
}

#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_sign(ptr: *mut U2FManager,
timeout: u64,
challenge_ptr: *const u8,
challenge_len: usize,
application_ptr: *const u8,
application_len: usize,
key_handle_ptr: *const u8,
key_handle_len: usize,
signature_ptr: *mut u8,
signature_len: *mut usize,
max_signature_len: usize) {
if ptr.is_null() {
return; // TODO error
impl Clone for OnceCallback {
fn clone(&self) -> Self {
Self { callback: self.callback.clone() }
}
}

let mut mgr = Box::from_raw(ptr);
let challenge = std::slice::from_raw_parts(challenge_ptr, challenge_len);
let application = std::slice::from_raw_parts(application_ptr, application_len);
let key_handle = std::slice::from_raw_parts(key_handle_ptr, key_handle_len);

let sig = mgr.sign(timeout, challenge.to_vec(), application.to_vec(), key_handle.to_vec());
let _ = Box::into_raw(mgr);

let sig = match sig {
Ok(rv) => rv,
_ => return // TODO error
};
mod consts;
mod manager;
mod runloop;
pub mod u2fprotocol;

if sig.len() > max_signature_len {
return; // TODO error
}
pub use u2fprotocol::*;
pub use manager::U2FManager as U2FManager;

*signature_len = sig.len();
ptr::copy_nonoverlapping(sig.as_ptr(), signature_ptr, sig.len());
}
mod capi;
pub use capi::*;
Loading

0 comments on commit eb312fa

Please sign in to comment.