authenticator_ctap2_2021/
capi.rs1use crate::authenticatorservice::{
6 AuthenticatorService, CtapVersion, RegisterArgsCtap1, SignArgsCtap1,
7};
8use crate::errors;
9use crate::statecallback::StateCallback;
10use crate::{RegisterResult, SignResult};
11use libc::size_t;
12use rand::{thread_rng, Rng};
13use std::collections::HashMap;
14use std::sync::mpsc::channel;
15use std::thread;
16use std::{ptr, slice};
17
18type U2FAppIds = Vec<crate::AppId>;
19type U2FKeyHandles = Vec<crate::KeyHandle>;
20type U2FCallback = extern "C" fn(u64, *mut U2FResult);
21
22pub enum U2FResult {
23 Success(HashMap<u8, Vec<u8>>),
24 Error(errors::AuthenticatorError),
25}
26
27const RESBUF_ID_REGISTRATION: u8 = 0;
28const RESBUF_ID_KEYHANDLE: u8 = 1;
29const RESBUF_ID_SIGNATURE: u8 = 2;
30const RESBUF_ID_APPID: u8 = 3;
31const RESBUF_ID_VENDOR_NAME: u8 = 4;
32const RESBUF_ID_DEVICE_NAME: u8 = 5;
33const RESBUF_ID_FIRMWARE_MAJOR: u8 = 6;
34const RESBUF_ID_FIRMWARE_MINOR: u8 = 7;
35const RESBUF_ID_FIRMWARE_BUILD: u8 = 8;
36
37fn new_tid() -> u64 {
39 thread_rng().gen::<u64>()
40}
41
42unsafe fn from_raw(ptr: *const u8, len: usize) -> Vec<u8> {
43 slice::from_raw_parts(ptr, len).to_vec()
44}
45
46#[no_mangle]
50pub extern "C" fn rust_u2f_mgr_new() -> *mut AuthenticatorService {
51 if let Ok(mut mgr) = AuthenticatorService::new(CtapVersion::CTAP1) {
52 mgr.add_detected_transports();
53 Box::into_raw(Box::new(mgr))
54 } else {
55 ptr::null_mut()
56 }
57}
58
59#[no_mangle]
64pub unsafe extern "C" fn rust_u2f_mgr_free(mgr: *mut AuthenticatorService) {
65 if !mgr.is_null() {
66 Box::from_raw(mgr);
67 }
68}
69
70#[no_mangle]
74pub unsafe extern "C" fn rust_u2f_app_ids_new() -> *mut U2FAppIds {
75 Box::into_raw(Box::new(vec![]))
76}
77
78#[no_mangle]
82pub unsafe extern "C" fn rust_u2f_app_ids_add(
83 ids: *mut U2FAppIds,
84 id_ptr: *const u8,
85 id_len: usize,
86) {
87 (*ids).push(from_raw(id_ptr, id_len));
88}
89
90#[no_mangle]
95pub unsafe extern "C" fn rust_u2f_app_ids_free(ids: *mut U2FAppIds) {
96 if !ids.is_null() {
97 Box::from_raw(ids);
98 }
99}
100
101#[no_mangle]
105pub unsafe extern "C" fn rust_u2f_khs_new() -> *mut U2FKeyHandles {
106 Box::into_raw(Box::new(vec![]))
107}
108
109#[no_mangle]
113pub unsafe extern "C" fn rust_u2f_khs_add(
114 khs: *mut U2FKeyHandles,
115 key_handle_ptr: *const u8,
116 key_handle_len: usize,
117 transports: u8,
118) {
119 (*khs).push(crate::KeyHandle {
120 credential: from_raw(key_handle_ptr, key_handle_len),
121 transports: crate::AuthenticatorTransports::from_bits_truncate(transports),
122 });
123}
124
125#[no_mangle]
130pub unsafe extern "C" fn rust_u2f_khs_free(khs: *mut U2FKeyHandles) {
131 if !khs.is_null() {
132 Box::from_raw(khs);
133 }
134}
135
136#[no_mangle]
140pub unsafe extern "C" fn rust_u2f_result_error(res: *const U2FResult) -> u8 {
141 if res.is_null() {
142 return errors::U2FTokenError::Unknown as u8;
143 }
144
145 if let U2FResult::Error(ref err) = *res {
146 return err.as_u2f_errorcode();
147 }
148
149 0 }
151
152#[no_mangle]
156pub unsafe extern "C" fn rust_u2f_resbuf_contains(res: *const U2FResult, bid: u8) -> bool {
157 if res.is_null() {
158 return false;
159 }
160
161 if let U2FResult::Success(ref bufs) = *res {
162 return bufs.contains_key(&bid);
163 }
164
165 false
166}
167
168#[no_mangle]
172pub unsafe extern "C" fn rust_u2f_resbuf_length(
173 res: *const U2FResult,
174 bid: u8,
175 len: *mut size_t,
176) -> bool {
177 if res.is_null() {
178 return false;
179 }
180
181 if let U2FResult::Success(ref bufs) = *res {
182 if let Some(buf) = bufs.get(&bid) {
183 *len = buf.len();
184 return true;
185 }
186 }
187
188 false
189}
190
191#[no_mangle]
196pub unsafe extern "C" fn rust_u2f_resbuf_copy(
197 res: *const U2FResult,
198 bid: u8,
199 dst: *mut u8,
200) -> bool {
201 if res.is_null() {
202 return false;
203 }
204
205 if let U2FResult::Success(ref bufs) = *res {
206 if let Some(buf) = bufs.get(&bid) {
207 ptr::copy_nonoverlapping(buf.as_ptr(), dst, buf.len());
208 return true;
209 }
210 }
211
212 false
213}
214
215#[no_mangle]
220pub unsafe extern "C" fn rust_u2f_res_free(res: *mut U2FResult) {
221 if !res.is_null() {
222 Box::from_raw(res);
223 }
224}
225
226#[no_mangle]
231pub unsafe extern "C" fn rust_u2f_mgr_register(
232 mgr: *mut AuthenticatorService,
233 flags: u64,
234 timeout: u64,
235 callback: U2FCallback,
236 challenge_ptr: *const u8,
237 challenge_len: usize,
238 application_ptr: *const u8,
239 application_len: usize,
240 khs: *const U2FKeyHandles,
241) -> u64 {
242 if mgr.is_null() {
243 return 0;
244 }
245
246 if challenge_ptr.is_null() || application_ptr.is_null() {
248 return 0;
249 }
250
251 let flags = crate::RegisterFlags::from_bits_truncate(flags);
252 let challenge = from_raw(challenge_ptr, challenge_len);
253 let application = from_raw(application_ptr, application_len);
254 let key_handles = (*khs).clone();
255
256 let (status_tx, status_rx) = channel::<crate::StatusUpdate>();
257 thread::spawn(move || loop {
258 match status_rx.recv() {
261 Ok(_) => {}
262 Err(_recv_error) => return,
263 }
264 });
265
266 let tid = new_tid();
267
268 let state_callback = StateCallback::<crate::Result<RegisterResult>>::new(Box::new(move |rv| {
269 let result = match rv {
270 Ok(RegisterResult::CTAP1(registration, dev_info)) => {
271 let mut bufs = HashMap::new();
272 bufs.insert(RESBUF_ID_REGISTRATION, registration);
273 bufs.insert(RESBUF_ID_VENDOR_NAME, dev_info.vendor_name);
274 bufs.insert(RESBUF_ID_DEVICE_NAME, dev_info.device_name);
275 bufs.insert(RESBUF_ID_FIRMWARE_MAJOR, vec![dev_info.version_major]);
276 bufs.insert(RESBUF_ID_FIRMWARE_MINOR, vec![dev_info.version_minor]);
277 bufs.insert(RESBUF_ID_FIRMWARE_BUILD, vec![dev_info.version_build]);
278 U2FResult::Success(bufs)
279 }
280 Ok(RegisterResult::CTAP2(..)) => U2FResult::Error(
281 errors::AuthenticatorError::VersionMismatch("rust_u2f_mgr_register", 1),
282 ),
283 Err(e) => U2FResult::Error(e),
284 };
285
286 callback(tid, Box::into_raw(Box::new(result)));
287 }));
288 let ctap_args = RegisterArgsCtap1 {
289 flags,
290 challenge,
291 application,
292 key_handles,
293 };
294
295 let res = (*mgr).register(timeout, ctap_args.into(), status_tx, state_callback);
296
297 if res.is_ok() {
298 tid
299 } else {
300 0
301 }
302}
303
304#[no_mangle]
309pub unsafe extern "C" fn rust_u2f_mgr_sign(
310 mgr: *mut AuthenticatorService,
311 flags: u64,
312 timeout: u64,
313 callback: U2FCallback,
314 challenge_ptr: *const u8,
315 challenge_len: usize,
316 app_ids: *const U2FAppIds,
317 khs: *const U2FKeyHandles,
318) -> u64 {
319 if mgr.is_null() || khs.is_null() {
320 return 0;
321 }
322
323 if challenge_ptr.is_null() {
325 return 0;
326 }
327
328 if (*app_ids).is_empty() {
330 return 0;
331 }
332
333 let flags = crate::SignFlags::from_bits_truncate(flags);
334 let challenge = from_raw(challenge_ptr, challenge_len);
335 let app_ids = (*app_ids).clone();
336 let key_handles = (*khs).clone();
337
338 let (status_tx, status_rx) = channel::<crate::StatusUpdate>();
339 thread::spawn(move || loop {
340 match status_rx.recv() {
343 Ok(_) => {}
344 Err(_recv_error) => return,
345 }
346 });
347
348 let tid = new_tid();
349 let state_callback = StateCallback::<crate::Result<SignResult>>::new(Box::new(move |rv| {
350 let result = match rv {
351 Ok(SignResult::CTAP1(app_id, key_handle, signature, dev_info)) => {
352 let mut bufs = HashMap::new();
353 bufs.insert(RESBUF_ID_KEYHANDLE, key_handle);
354 bufs.insert(RESBUF_ID_SIGNATURE, signature);
355 bufs.insert(RESBUF_ID_APPID, app_id);
356 bufs.insert(RESBUF_ID_VENDOR_NAME, dev_info.vendor_name);
357 bufs.insert(RESBUF_ID_DEVICE_NAME, dev_info.device_name);
358 bufs.insert(RESBUF_ID_FIRMWARE_MAJOR, vec![dev_info.version_major]);
359 bufs.insert(RESBUF_ID_FIRMWARE_MINOR, vec![dev_info.version_minor]);
360 bufs.insert(RESBUF_ID_FIRMWARE_BUILD, vec![dev_info.version_build]);
361 U2FResult::Success(bufs)
362 }
363 Ok(SignResult::CTAP2(..)) => U2FResult::Error(
364 errors::AuthenticatorError::VersionMismatch("rust_u2f_mgr_sign", 1),
365 ),
366 Err(e) => U2FResult::Error(e),
367 };
368
369 callback(tid, Box::into_raw(Box::new(result)));
370 }));
371
372 let res = (*mgr).sign(
373 timeout,
374 SignArgsCtap1 {
375 flags,
376 challenge,
377 app_ids,
378 key_handles,
379 }
380 .into(),
381 status_tx,
382 state_callback,
383 );
384
385 if res.is_ok() {
386 tid
387 } else {
388 0
389 }
390}
391
392#[no_mangle]
397pub unsafe extern "C" fn rust_u2f_mgr_cancel(mgr: *mut AuthenticatorService) {
398 if !mgr.is_null() {
399 let _ = (*mgr).cancel();
401 }
402}