From 20754c119e788a54d242062e25e35edebfc41397 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Tue, 12 Apr 2022 22:45:28 +0800 Subject: [PATCH] feat: v1.1.16 --- Cargo.lock | 59 ++++++++++++++++++++++++------------------ Cargo.toml | 2 +- src/cmd_u2fregister.rs | 5 +++- src/cmd_u2fsign.rs | 15 +++++++---- src/fido.rs | 14 +++++++--- 5 files changed, 60 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95f66e5..2678c14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,7 +97,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", "synstructure", ] @@ -109,7 +109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -166,7 +166,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "libc", - "miniz_oxide", + "miniz_oxide 0.4.4", "object", "rustc-demangle", ] @@ -202,7 +202,7 @@ dependencies = [ "lazycell", "peeking_take_while", "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "regex", "rustc-hash", "shlex", @@ -248,7 +248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b04ce3d2372d05d1ef4ea3fdf427da6ae3c17ca06d688a107b5344836276bc3" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -384,7 +384,7 @@ dependencies = [ [[package]] name = "card-cli" -version = "1.1.15" +version = "1.1.16" dependencies = [ "authenticator", "base64 0.13.0", @@ -580,7 +580,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -734,7 +734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -827,14 +827,14 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" [[package]] name = "flate2" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" dependencies = [ "cfg-if 1.0.0", "crc32fast", "libc", - "miniz_oxide", + "miniz_oxide 0.5.1", ] [[package]] @@ -923,7 +923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -1316,6 +1316,15 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "miniz_oxide" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.2" @@ -1844,9 +1853,9 @@ checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -2160,7 +2169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -2394,7 +2403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "unicode-xid", ] @@ -2405,7 +2414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", "unicode-xid", ] @@ -2485,7 +2494,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -2568,7 +2577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", ] @@ -2714,7 +2723,7 @@ dependencies = [ "lazy_static", "log", "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", "wasm-bindgen-shared", ] @@ -2725,7 +2734,7 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ - "quote 1.0.17", + "quote 1.0.18", "wasm-bindgen-macro-support", ] @@ -2736,7 +2745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -2885,9 +2894,9 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a16b7b403377d61184bb601d8349a4ff2c4cec08a305d004f710b7eaafef24" +checksum = "074914ea4eec286eb8d1fd745768504f420a1f7b7919185682a4a267bed7d2e7" [[package]] name = "yubico_manager" @@ -2955,7 +2964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", - "quote 1.0.17", + "quote 1.0.18", "syn", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index 92c7536..24b77f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "card-cli" -version = "1.1.15" +version = "1.1.16" authors = ["Hatter Jiang "] edition = "2018" diff --git a/src/cmd_u2fregister.rs b/src/cmd_u2fregister.rs index 9e706b6..b9fc7ea 100644 --- a/src/cmd_u2fregister.rs +++ b/src/cmd_u2fregister.rs @@ -26,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("challenge").long("challenge").takes_value(true).help("Challenge HEX")) + .arg(Arg::with_name("challenge-with-timestamp-prefix").long("challenge-with-timestamp-prefix").help("Challenge with timestamp prefix")) .arg(Arg::with_name("json").long("json").help("JSON output")) } @@ -39,7 +40,9 @@ impl Command for CommandImpl { Err(e) => return simple_error!("Timeout should be a number: {}", e), }; - let u2fv2_challenge = U2fV2Challenge::new_challenge(sub_arg_matches.value_of("challenge"), app_id)?; + let challenge_hex = sub_arg_matches.value_of("challenge"); + let challenge_with_timestamp_prefix = sub_arg_matches.is_present("challenge-with-timestamp-prefix"); + let u2fv2_challenge = U2fV2Challenge::new_challenge(challenge_hex, app_id, challenge_with_timestamp_prefix)?; let u2fv2_challenge_str = u2fv2_challenge.to_json(); let chall_bytes = digest::sha256(&u2fv2_challenge_str); diff --git a/src/cmd_u2fsign.rs b/src/cmd_u2fsign.rs index 8243dfa..aa757be 100644 --- a/src/cmd_u2fsign.rs +++ b/src/cmd_u2fsign.rs @@ -28,6 +28,7 @@ impl Command for CommandImpl { .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("challenge-with-timestamp-prefix").long("challenge-with-timestamp-prefix").help("Challenge with timestamp prefix")) .arg(Arg::with_name("key-handle").short("k").long("key-handle").takes_value(true).multiple(true).help("Key handle")) .arg(Arg::with_name("json").long("json").help("JSON output")) } @@ -63,8 +64,9 @@ impl Command for CommandImpl { sign_tx.send(rv).unwrap(); })); - - let u2fv2_challenge = U2fV2Challenge::new_challenge(sub_arg_matches.value_of("challenge"), app_id)?; + let challenge_hex = sub_arg_matches.value_of("challenge"); + let challenge_with_timestamp_prefix = sub_arg_matches.is_present("challenge-with-timestamp-prefix"); + let u2fv2_challenge = U2fV2Challenge::new_challenge(challenge_hex, app_id, challenge_with_timestamp_prefix)?; let u2fv2_challenge_str = u2fv2_challenge.to_json(); let chall_bytes = digest::sha256(&u2fv2_challenge_str); @@ -99,6 +101,8 @@ 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 counter_u32 = u32::from_be_bytes([counter[0], counter[1], counter[2], counter[3]]); + // application (32B) + user presence (1B) + counter (4B) + client data hash (32B) let mut signed_message = Vec::with_capacity(128); signed_message.extend_from_slice(&app_id_hash); signed_message.push(*user_presence_flag); @@ -117,15 +121,18 @@ impl Command for CommandImpl { json.insert("signed_message", hex::encode(&signed_message)); json.insert("key_handle", hex::encode(&handle_used)); json.insert("sign_data", hex::encode(&sign_data)); + json.insert("user_presence_flag", format!("{}", *user_presence_flag)); + json.insert("counter", format!("{}", counter_u32)); } else { information!("Sign challenge: {}", u2fv2_challenge_str); information!("Sign challenge base64: {}", base64::encode(&u2fv2_challenge_str)); 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!("- counter : {}", counter_u32); information!("- signature: {}", hex::encode(&signature)); // success!("Key handle used: {}", base64::encode(&handle_used)); information!("Key handle: {}", hex::encode(&handle_used)); + information!("Signed message: {}", hex::encode(&signed_message)); } if let Some(public_key_hex) = sub_arg_matches.value_of("public-key-hex") { @@ -134,8 +141,6 @@ impl Command for CommandImpl { json.insert("pub_key", hex::encode(&public_key)); } else { 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, diff --git a/src/fido.rs b/src/fido.rs index 3a0fd49..5a74448 100644 --- a/src/fido.rs +++ b/src/fido.rs @@ -1,6 +1,7 @@ use std::fmt; use std::sync::mpsc::{channel, Sender}; use std::thread; +use std::time::SystemTime; use authenticator::{RegisterResult, StatusUpdate}; use base64::URL_SAFE_NO_PAD; @@ -95,9 +96,9 @@ pub struct U2fV2Challenge { } impl U2fV2Challenge { - pub fn new_challenge(challenge_hex: Option<&str>, app_id: &str) -> XResult { + pub fn new_challenge(challenge_hex: Option<&str>, app_id: &str, with_time_stamp_prefix: bool) -> XResult { Ok(match challenge_hex { - None => U2fV2Challenge::new_random(app_id), + None => U2fV2Challenge::new_random(app_id, with_time_stamp_prefix), 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); @@ -106,13 +107,20 @@ impl U2fV2Challenge { }) } - pub fn new_random(app_id: S) -> Self where S: Into { + pub fn new_random(app_id: S, with_time_stamp_prefix: bool) -> Self where S: Into { let mut rng = rand::thread_rng(); let mut rand_bytes = [0_u8; 32]; for c in &mut rand_bytes { let b: u8 = rng.gen(); *c = b; } + if with_time_stamp_prefix { + let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis() as u64; + let timestamp_be_bytes = timestamp.to_be_bytes(); + for i in 0..8 { + rand_bytes[i] = timestamp_be_bytes[i]; + } + } let challenge = base64::encode_config(&rand_bytes, URL_SAFE_NO_PAD); Self::new(challenge, app_id)