feat: v1.1.14
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -384,7 +384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "card-cli"
|
||||
version = "1.1.13"
|
||||
version = "1.1.14"
|
||||
dependencies = [
|
||||
"authenticator",
|
||||
"base64 0.13.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "card-cli"
|
||||
version = "1.1.13"
|
||||
version = "1.1.14"
|
||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::sync::mpsc::channel;
|
||||
use authenticator::authenticatorservice::AuthenticatorService;
|
||||
use authenticator::RegisterFlags;
|
||||
use authenticator::statecallback::StateCallback;
|
||||
use base64::URL_SAFE_NO_PAD;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkey::PKey;
|
||||
@@ -40,14 +39,7 @@ impl Command for CommandImpl {
|
||||
Err(e) => return simple_error!("Timeout should be a number: {}", e),
|
||||
};
|
||||
|
||||
let u2fv2_challenge = match sub_arg_matches.value_of("challenge") {
|
||||
None => U2fV2Challenge::new_random(app_id),
|
||||
Some(challenge_hex) => {
|
||||
let challenge_bytes = opt_result!(hex::decode(challenge_hex), "Decode challenge hex failed: {}");
|
||||
let challenge = base64::encode_config(&challenge_bytes, URL_SAFE_NO_PAD);
|
||||
U2fV2Challenge::new(challenge, app_id)
|
||||
}
|
||||
};
|
||||
let u2fv2_challenge = U2fV2Challenge::new_challenge(sub_arg_matches.value_of("challenge"), app_id)?;
|
||||
|
||||
let u2fv2_challenge_str = u2fv2_challenge.to_json();
|
||||
let chall_bytes = digest::sha256(&u2fv2_challenge_str);
|
||||
@@ -87,12 +79,12 @@ impl Command for CommandImpl {
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
// + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
let mut to_be_signed = Vec::with_capacity(200);
|
||||
to_be_signed.push(0x00);
|
||||
to_be_signed.extend_from_slice(&app_bytes);
|
||||
to_be_signed.extend_from_slice(&chall_bytes);
|
||||
to_be_signed.extend_from_slice(&u2f_registration_data.key_handle);
|
||||
to_be_signed.extend_from_slice(&u2f_registration_data.pub_key);
|
||||
let mut signed_message = Vec::with_capacity(200);
|
||||
signed_message.push(0x00);
|
||||
signed_message.extend_from_slice(&app_bytes);
|
||||
signed_message.extend_from_slice(&chall_bytes);
|
||||
signed_message.extend_from_slice(&u2f_registration_data.key_handle);
|
||||
signed_message.extend_from_slice(&u2f_registration_data.pub_key);
|
||||
// +------+--------------------+---------------------+------------+------------+------+
|
||||
// + 0x05 | User pub key (65B) | key handle len (1B) | key handle | X.509 Cert | Sign |
|
||||
// +------+--------------------+---------------------+------------+------------+------+
|
||||
@@ -114,7 +106,7 @@ impl Command for CommandImpl {
|
||||
json.insert("pub_key", hex::encode(&u2f_registration_data.pub_key));
|
||||
json.insert("key_handle", hex::encode(&u2f_registration_data.key_handle));
|
||||
json.insert("signature", hex::encode(sign));
|
||||
json.insert("to_be_signed", hex::encode(&to_be_signed));
|
||||
json.insert("signed_message", hex::encode(&signed_message));
|
||||
json.insert("registration_data", hex::encode(®ister_result.0));
|
||||
json.insert("app_id", app_id.to_string());
|
||||
json.insert("app_id_hash", hex::encode(&app_bytes));
|
||||
@@ -133,7 +125,7 @@ impl Command for CommandImpl {
|
||||
success!("Public key: {}", hex::encode(&u2f_registration_data.pub_key));
|
||||
success!("Key handle: {}", hex::encode(&u2f_registration_data.key_handle));
|
||||
debugging!("Registration data: {}", hex::encode(®ister_result.0));
|
||||
information!("To be signed: {}", hex::encode(&to_be_signed));
|
||||
information!("Signed message: {}", hex::encode(&signed_message));
|
||||
information!("Signature: {}", hex::encode(sign));
|
||||
|
||||
if let Some(attestation_cert) = &u2f_registration_data.attestation_cert {
|
||||
@@ -141,7 +133,7 @@ impl Command for CommandImpl {
|
||||
debugging!("Attestation public key: {:?}", cert.1.public_key().subject_public_key);
|
||||
let pkey = opt_result!(PKey::public_key_from_der(cert.1.public_key().raw), "Parse public key failed: {}");
|
||||
let mut verifier = opt_result!(Verifier::new(MessageDigest::sha256(), &pkey), "Verifier new failed: {}");
|
||||
verifier.update(&to_be_signed)?;
|
||||
verifier.update(&signed_message)?;
|
||||
let verify_result = opt_result!(verifier.verify(sign), "Verifier verify failed: {}");
|
||||
if verify_result {
|
||||
success!("Verify success");
|
||||
|
||||
@@ -4,7 +4,13 @@ use authenticator::{AuthenticatorTransports, KeyHandle, SignFlags};
|
||||
use authenticator::authenticatorservice::AuthenticatorService;
|
||||
use authenticator::statecallback::StateCallback;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use openssl::bn::BigNumContext;
|
||||
use openssl::ec::{EcGroup, EcKey, EcPoint};
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::nid::Nid;
|
||||
use openssl::pkey::PKey;
|
||||
use openssl::sha::sha256;
|
||||
use openssl::sign::Verifier;
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
|
||||
use crate::digest;
|
||||
@@ -20,6 +26,7 @@ impl Command for CommandImpl {
|
||||
.arg(Arg::with_name("app-id").short("a").long("app-id").default_value("https://example.com").help("App id"))
|
||||
.arg(Arg::with_name("timeout").short("t").long("timeout").default_value("30").help("Timeout in seconds"))
|
||||
.arg(Arg::with_name("public-key-hex").long("public-key-hex").takes_value(true).help("Public key hex"))
|
||||
.arg(Arg::with_name("challenge").long("challenge").takes_value(true).help("Challenge HEX"))
|
||||
.arg(Arg::with_name("key-handle").short("k").long("key-handle").takes_value(true).multiple(true).help("Key handle"))
|
||||
}
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
@@ -51,7 +58,9 @@ impl Command for CommandImpl {
|
||||
sign_tx.send(rv).unwrap();
|
||||
}));
|
||||
|
||||
let u2fv2_challenge = U2fV2Challenge::new_random(app_id);
|
||||
|
||||
let u2fv2_challenge = U2fV2Challenge::new_challenge(sub_arg_matches.value_of("challenge"), app_id)?;
|
||||
|
||||
let u2fv2_challenge_str = u2fv2_challenge.to_json();
|
||||
let chall_bytes = digest::sha256(&u2fv2_challenge_str);
|
||||
|
||||
@@ -88,7 +97,7 @@ impl Command for CommandImpl {
|
||||
information!("Sign result : {}", base64::encode(&sign_data));
|
||||
information!("- presence : {}", user_presence_flag);
|
||||
information!("- counter : {}", u32::from_be_bytes([counter[0], counter[1], counter[2], counter[3]]));
|
||||
information!("- signature: {}", base64::encode(&signature));
|
||||
information!("- signature: {}", hex::encode(&signature));
|
||||
// success!("Key handle used: {}", base64::encode(&handle_used));
|
||||
information!("Key handle: {}", hex::encode(&handle_used));
|
||||
|
||||
@@ -98,23 +107,37 @@ impl Command for CommandImpl {
|
||||
let client_data = u2fv2_challenge_str.as_bytes().to_vec();
|
||||
let app_id_hash = sha256(app_id.as_bytes());
|
||||
let client_data_hash = sha256(&client_data[..]);
|
||||
let mut msg = Vec::with_capacity(128);
|
||||
msg.extend_from_slice(&app_id_hash);
|
||||
msg.push(*user_presence_flag);
|
||||
msg.extend_from_slice(counter);
|
||||
msg.extend_from_slice(&client_data_hash);
|
||||
let mut signed_message = Vec::with_capacity(128);
|
||||
signed_message.extend_from_slice(&app_id_hash);
|
||||
signed_message.push(*user_presence_flag);
|
||||
signed_message.extend_from_slice(counter);
|
||||
signed_message.extend_from_slice(&client_data_hash);
|
||||
|
||||
information!("Public key: {}", base64::encode(&public_key));
|
||||
information!("Signed message: {}", base64::encode(&msg));
|
||||
information!("Public key: {}", hex::encode(&public_key));
|
||||
information!("Signed message: {}", hex::encode(&signed_message));
|
||||
|
||||
let authorization_result = u2f::authorization::parse_sign_response(
|
||||
app_id.to_string(),
|
||||
client_data,
|
||||
public_key,
|
||||
sign_data,
|
||||
public_key.clone(),
|
||||
sign_data.clone(),
|
||||
);
|
||||
let authorization = opt_result!(authorization_result, "Parse authorization failed: {}");
|
||||
success!("Parse authorization success, counter: {}", authorization.counter);
|
||||
|
||||
// PKey::public_key_from_der()
|
||||
let ec_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
|
||||
let ec_point = EcPoint::from_bytes(&ec_group, &public_key, &mut BigNumContext::new().unwrap()).unwrap();
|
||||
let ec_key = EcKey::from_public_key(&ec_group, &ec_point).unwrap();
|
||||
let ec_pkey = PKey::from_ec_key(ec_key).unwrap();
|
||||
let mut verifier = opt_result!(Verifier::new(MessageDigest::sha256(), &ec_pkey), "Verifier new failed: {}");
|
||||
verifier.update(&signed_message)?;
|
||||
let verify_result = opt_result!(verifier.verify(signature), "Verifier verify failed: {}");
|
||||
if verify_result {
|
||||
success!("Verify success");
|
||||
} else {
|
||||
failure!("Verify failed");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
|
||||
12
src/fido.rs
12
src/fido.rs
@@ -7,6 +7,7 @@ use base64::URL_SAFE_NO_PAD;
|
||||
use rand::Rng;
|
||||
use rust_util::XResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::pkiutil::bytes_to_pem;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
@@ -94,6 +95,17 @@ pub struct U2fV2Challenge {
|
||||
}
|
||||
|
||||
impl U2fV2Challenge {
|
||||
pub fn new_challenge(challenge_hex: Option<&str>, app_id: &str) -> XResult<U2fV2Challenge> {
|
||||
Ok(match challenge_hex {
|
||||
None => U2fV2Challenge::new_random(app_id),
|
||||
Some(challenge_hex) => {
|
||||
let challenge_bytes = opt_result!(hex::decode(challenge_hex), "Decode challenge hex failed: {}");
|
||||
let challenge = base64::encode_config(&challenge_bytes, base64::URL_SAFE_NO_PAD);
|
||||
U2fV2Challenge::new(challenge, app_id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_random<S>(app_id: S) -> Self where S: Into<String> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rand_bytes = [0_u8; 32];
|
||||
|
||||
Reference in New Issue
Block a user