feat: CTAP/FIDO cert

This commit is contained in:
2021-07-03 06:28:38 +08:00
parent 1e3fa35bdf
commit 9c2cc1d3f3
2 changed files with 62 additions and 41 deletions

View File

@@ -59,4 +59,27 @@ pub fn start_status_updater() -> Sender<StatusUpdate> {
} }
}); });
status_tx status_tx
}
pub fn to_pem(bs: &[u8], sub: &str, w: usize) -> String {
let mut s = String::with_capacity(bs.len() * 2);
s.push_str(&format!("-----BEGIN {}-----", sub));
let b64 = base64::encode(bs).chars().collect::<Vec<char>>();
let mut b64 = b64.as_slice();
while b64.len() > 0 {
s.push('\n');
if b64.len() >= w {
for i in 0..w {
s.push(b64[i]);
}
b64 = &b64[w..];
} else {
for c in b64 {
s.push(*c);
}
b64 = &[];
}
}
s.push_str(&format!("\n-----END {}-----", sub));
s
} }

View File

@@ -4,7 +4,6 @@ use authenticator::authenticatorservice::AuthenticatorService;
use authenticator::statecallback::StateCallback; use authenticator::statecallback::StateCallback;
use authenticator::RegisterFlags; use authenticator::RegisterFlags;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use rust_util::XResult;
use crate::fido; use crate::fido;
use crate::digest; use crate::digest;
use crate::fido::U2fV2Challenge; use crate::fido::U2fV2Challenge;
@@ -28,7 +27,8 @@ impl Command for CommandImpl {
}; };
let u2fv2_challenge = U2fV2Challenge::new_random(app_id); let u2fv2_challenge = U2fV2Challenge::new_random(app_id);
let chall_bytes = digest::sha256(&u2fv2_challenge.to_json()); let u2fv2_challenge_str = u2fv2_challenge.to_json();
let chall_bytes = digest::sha256(&u2fv2_challenge_str);
let app_bytes = digest::sha256(app_id); let app_bytes = digest::sha256(app_id);
@@ -61,47 +61,45 @@ impl Command for CommandImpl {
success!("Device info: {}", &device_info); success!("Device info: {}", &device_info);
success!("Register result: {}", base64::encode(&register_data)); success!("Register result: {}", base64::encode(&register_data));
let credential = u2f_get_key_handle_from_register_response(&register_data).unwrap();
success!("Key handle: {}", base64::encode(&credential));
success!("Key handle: {}", hex::encode(&credential));
let client_data = &u2fv2_challenge_str;
let rr = match u2f::register::parse_registration(app_id.to_string(), client_data.as_bytes().to_vec(), register_data) {
Ok(rr) => rr,
Err(e) => return simple_error!("Parse registration data failed: {}", e),
};
if let Some(cert) = rr.attestation_cert {
success!("Certificate: {}", fido::to_pem(&cert, "CERTIFICATE", 64));
}
if let Some(device_name) = rr.device_name {
success!("Device name: {}", device_name);
}
success!("Public key: {}", hex::encode(rr.pub_key));
success!("Key handle: {}", hex::encode(rr.key_handle));
Ok(()) Ok(())
} }
} }
// U2F raw message format specification (version 20170411) section 4.3
// In case of success we need to send back the following reply
// (excluding ISO7816 success code)
// +------+--------------------+---------------------+------------+------------+------+
// + 0x05 | User pub key (65B) | key handle len (1B) | key handle | X.509 Cert | Sign |
// +------+--------------------+---------------------+------------+------------+------+
// //
// Where Sign is an ECDSA signature over the following structure: // // U2F raw message format specification (version 20170411) section 4.3
// +------+-------------------+-----------------+------------+--------------------+ // // In case of success we need to send back the following reply
// + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) | // // (excluding ISO7816 success code)
// +------+-------------------+-----------------+------------+--------------------+ // // +------+--------------------+---------------------+------------+------------+------+
// see https://github.com/google/OpenSK/blob/stable/src/ctap/ctap1.rs // // + 0x05 | User pub key (65B) | key handle len (1B) | key handle | X.509 Cert | Sign |
fn u2f_get_key_handle_from_register_response(register_response: &[u8]) -> XResult<Vec<u8>> { // // +------+--------------------+---------------------+------------+------------+------+
if register_response[0] != 0x05 { // //
return simple_error!("Reserved byte not set correctly"); // // Where Sign is an ECDSA signature over the following structure:
} // // +------+-------------------+-----------------+------------+--------------------+
// // + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
let key_handle_len = register_response[66] as usize; // // +------+-------------------+-----------------+------------+--------------------+
let mut public_key = register_response.to_owned(); // // see https://github.com/google/OpenSK/blob/stable/src/ctap/ctap1.rs
let mut key_handle = public_key.split_off(67); // fn u2f_get_key_handle_from_register_response(register_response: &[u8]) -> XResult<Vec<u8>> {
let _attestation = key_handle.split_off(key_handle_len); // if register_response[0] != 0x05 {
// return simple_error!("Reserved byte not set correctly");
Ok(key_handle) // }
} //
// let key_handle_len = register_response[66] as usize;
#[test] // let mut public_key = register_response.to_owned();
fn test() { // let mut key_handle = public_key.split_off(67);
let app_id = "https://webencrypt.org"; // let _attestation = key_handle.split_off(key_handle_len);
let client_data = base64::decode("eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCIsImNoYWxsZW5nZSI6ImFHVnNiRzlmZDI5eWJHUSIsIm9yaWdpbiI6Imh0dHBzOi8vd2ViZW5jcnlwdC5vcmciLCJjcm9zc09yaWdpbiI6ZmFsc2V9").unwrap(); //
let register_data = base64::decode("BQSpAR+aliPCpz2u8c84Mv13bAYUcJnT9OgiXkCX9CTR/xhWqbJwoL9l6WRqvqwtG77NMvkDexcTKf9Mtf5+V1NCQKYfXWCP+IL2Lfbyng7mX0GV/etsHqlIiiaoEQo5g0Zetn+JimnLx5f259OZlEsvzB7Qs6swN5WRy57FRqREOPcwggE0MIHboAMCAQICCiBzHdQQUIQZ+ZgwCgYIKoZIzj0EAwIwFTETMBEGA1UEAxMKVTJGIElzc3VlcjAaFwswMDAxMDEwMDAwWhcLMDAwMTAxMDAwMFowFTETMBEGA1UEAxMKVTJGIERldmljZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCvum43LiwAMJacjIFh7SCIrl1e1ltYXeK50v2HWDRZ9pw38HSPmx2SjT+2hTY1YMVagbgXimYrb8+WWlZ6j9bqjFzAVMBMGCysGAQQBguUcAgEBBAQDAgUgMAoGCCqGSM49BAMCA0gAMEUCIQDBo6aOLxanIUYnBX9iu3KMngPnobpi0EZSTkVtLC8/cwIgC1945RGqGBKfbyNtkhMifZK05n7fU+gW37Bdnci5D94wRQIhAJHR1EsN/+Fb+74FyxSjBMaoD6p2edlqGPYEb4SiXwccAiAM48XFf/sWsgzS2YU4EeObztVLErUb1JaA2qHJtTUoig==").unwrap(); // Ok(key_handle)
let r = u2f::register::parse_registration(app_id.to_string(), client_data, register_data); // }
let rr = r.unwrap();
println!("{}", hex::encode(rr.pub_key));
println!("{}", hex::encode(rr.attestation_cert.unwrap()));
println!("{}", hex::encode(rr.key_handle));
}