feat: CTAP/FIDO cert
This commit is contained in:
23
src/fido.rs
23
src/fido.rs
@@ -59,4 +59,27 @@ pub fn start_status_updater() -> Sender<StatusUpdate> {
|
||||
}
|
||||
});
|
||||
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
|
||||
}
|
||||
@@ -4,7 +4,6 @@ use authenticator::authenticatorservice::AuthenticatorService;
|
||||
use authenticator::statecallback::StateCallback;
|
||||
use authenticator::RegisterFlags;
|
||||
use std::sync::mpsc::channel;
|
||||
use rust_util::XResult;
|
||||
use crate::fido;
|
||||
use crate::digest;
|
||||
use crate::fido::U2fV2Challenge;
|
||||
@@ -28,7 +27,8 @@ impl Command for CommandImpl {
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@@ -61,47 +61,45 @@ impl Command for CommandImpl {
|
||||
|
||||
success!("Device info: {}", &device_info);
|
||||
success!("Register result: {}", base64::encode(®ister_data));
|
||||
let credential = u2f_get_key_handle_from_register_response(®ister_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(())
|
||||
}
|
||||
}
|
||||
|
||||
// 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:
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
// + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
// see https://github.com/google/OpenSK/blob/stable/src/ctap/ctap1.rs
|
||||
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");
|
||||
}
|
||||
|
||||
let key_handle_len = register_response[66] as usize;
|
||||
let mut public_key = register_response.to_owned();
|
||||
let mut key_handle = public_key.split_off(67);
|
||||
let _attestation = key_handle.split_off(key_handle_len);
|
||||
|
||||
Ok(key_handle)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let app_id = "https://webencrypt.org";
|
||||
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();
|
||||
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));
|
||||
}
|
||||
// // 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:
|
||||
// // +------+-------------------+-----------------+------------+--------------------+
|
||||
// // + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
|
||||
// // +------+-------------------+-----------------+------------+--------------------+
|
||||
// // see https://github.com/google/OpenSK/blob/stable/src/ctap/ctap1.rs
|
||||
// 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");
|
||||
// }
|
||||
//
|
||||
// let key_handle_len = register_response[66] as usize;
|
||||
// let mut public_key = register_response.to_owned();
|
||||
// let mut key_handle = public_key.split_off(67);
|
||||
// let _attestation = key_handle.split_off(key_handle_len);
|
||||
//
|
||||
// Ok(key_handle)
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user