Introduce a trait to abstract the CTAP environment
The end goal is to provide users with: - the Env trait that they should implement - the Ctap struct that they can use
This commit is contained in:
committed by
Julien Cretin
parent
8a2e99960f
commit
18faf9f38f
@@ -359,7 +359,9 @@ mod test {
|
||||
use super::super::pin_protocol::authenticate_pin_uv_auth_token;
|
||||
use super::super::CtapState;
|
||||
use super::*;
|
||||
use crypto::rng256::{Rng256, ThreadRng256};
|
||||
use crate::env::test::TestEnv;
|
||||
use crate::env::Env;
|
||||
use crypto::rng256::Rng256;
|
||||
|
||||
const CLOCK_FREQUENCY_HZ: usize = 32768;
|
||||
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
|
||||
@@ -383,15 +385,14 @@ mod test {
|
||||
}
|
||||
|
||||
fn test_helper_process_get_creds_metadata(pin_uv_auth_protocol: PinUvAuthProtocol) {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, pin_uv_auth_protocol);
|
||||
let credential_source = create_credential_source(&mut rng);
|
||||
let credential_source = create_credential_source(env.rng());
|
||||
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
ctap_state.client_pin = client_pin;
|
||||
|
||||
ctap_state.persistent_store.set_pin(&[0u8; 16], 4).unwrap();
|
||||
@@ -467,17 +468,16 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_enumerate_rps_with_uv() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
let credential_source1 = create_credential_source(&mut rng);
|
||||
let mut credential_source2 = create_credential_source(&mut rng);
|
||||
let credential_source1 = create_credential_source(env.rng());
|
||||
let mut credential_source2 = create_credential_source(env.rng());
|
||||
credential_source2.rp_id = "another.example.com".to_string();
|
||||
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
ctap_state.client_pin = client_pin;
|
||||
|
||||
ctap_state
|
||||
@@ -565,15 +565,14 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_enumerate_rps_completeness() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
let credential_source = create_credential_source(&mut rng);
|
||||
let credential_source = create_credential_source(env.rng());
|
||||
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
ctap_state.client_pin = client_pin;
|
||||
|
||||
const NUM_CREDENTIALS: usize = 20;
|
||||
@@ -648,20 +647,19 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_enumerate_credentials_with_uv() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
let credential_source1 = create_credential_source(&mut rng);
|
||||
let mut credential_source2 = create_credential_source(&mut rng);
|
||||
let credential_source1 = create_credential_source(env.rng());
|
||||
let mut credential_source2 = create_credential_source(env.rng());
|
||||
credential_source2.user_handle = vec![0x02];
|
||||
credential_source2.user_name = Some("user2".to_string());
|
||||
credential_source2.user_display_name = Some("User Two".to_string());
|
||||
credential_source2.user_icon = Some("icon2".to_string());
|
||||
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
ctap_state.client_pin = client_pin;
|
||||
|
||||
ctap_state
|
||||
@@ -754,16 +752,15 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_delete_credential() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
let mut credential_source = create_credential_source(&mut rng);
|
||||
let mut credential_source = create_credential_source(env.rng());
|
||||
credential_source.credential_id = vec![0x1D; 32];
|
||||
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
ctap_state.client_pin = client_pin;
|
||||
|
||||
ctap_state
|
||||
@@ -826,16 +823,15 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_update_user_information() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||
let mut env = TestEnv::new();
|
||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(env.rng());
|
||||
let pin_uv_auth_token = [0x55; 32];
|
||||
let client_pin =
|
||||
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||
let mut credential_source = create_credential_source(&mut rng);
|
||||
let mut credential_source = create_credential_source(env.rng());
|
||||
credential_source.credential_id = vec![0x1D; 32];
|
||||
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
ctap_state.client_pin = client_pin;
|
||||
|
||||
ctap_state
|
||||
@@ -899,9 +895,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_credential_management_invalid_pin_uv_auth_param() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
|
||||
ctap_state.persistent_store.set_pin(&[0u8; 16], 4).unwrap();
|
||||
|
||||
|
||||
@@ -13,14 +13,12 @@
|
||||
// limitations under the License.
|
||||
|
||||
use super::apdu::{Apdu, ApduStatusCode};
|
||||
use super::hid::ChannelID;
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::CtapState;
|
||||
use crate::env::Env;
|
||||
use alloc::vec::Vec;
|
||||
use arrayref::array_ref;
|
||||
use core::convert::Into;
|
||||
use core::convert::TryFrom;
|
||||
use crypto::rng256::Rng256;
|
||||
use libtock_drivers::timer::ClockValue;
|
||||
|
||||
// For now, they're the same thing with apdu.rs containing the authoritative definition
|
||||
@@ -180,15 +178,12 @@ impl Ctap1Command {
|
||||
const VENDOR_SPECIFIC_FIRST: u8 = 0x40;
|
||||
const VENDOR_SPECIFIC_LAST: u8 = 0xBF;
|
||||
|
||||
pub fn process_command<R, CheckUserPresence>(
|
||||
pub fn process_command(
|
||||
env: &mut impl Env,
|
||||
message: &[u8],
|
||||
ctap_state: &mut CtapState<R, CheckUserPresence>,
|
||||
ctap_state: &mut CtapState,
|
||||
clock_value: ClockValue,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode>
|
||||
where
|
||||
R: Rng256,
|
||||
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
|
||||
{
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||
if !ctap_state
|
||||
.allows_ctap1()
|
||||
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?
|
||||
@@ -204,7 +199,7 @@ impl Ctap1Command {
|
||||
if !ctap_state.u2f_up_state.consume_up(clock_value) {
|
||||
return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED);
|
||||
}
|
||||
Ctap1Command::process_register(challenge, application, ctap_state)
|
||||
Ctap1Command::process_register(env, challenge, application, ctap_state)
|
||||
}
|
||||
|
||||
U2fCommand::Authenticate {
|
||||
@@ -220,6 +215,7 @@ impl Ctap1Command {
|
||||
return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED);
|
||||
}
|
||||
Ctap1Command::process_authenticate(
|
||||
env,
|
||||
challenge,
|
||||
application,
|
||||
key_handle,
|
||||
@@ -247,19 +243,16 @@ impl Ctap1Command {
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
// + 0x00 | application (32B) | challenge (32B) | key handle | User pub key (65B) |
|
||||
// +------+-------------------+-----------------+------------+--------------------+
|
||||
fn process_register<R, CheckUserPresence>(
|
||||
fn process_register(
|
||||
env: &mut impl Env,
|
||||
challenge: [u8; 32],
|
||||
application: [u8; 32],
|
||||
ctap_state: &mut CtapState<R, CheckUserPresence>,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode>
|
||||
where
|
||||
R: Rng256,
|
||||
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
|
||||
{
|
||||
let sk = crypto::ecdsa::SecKey::gensk(ctap_state.rng);
|
||||
ctap_state: &mut CtapState,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let pk = sk.genpk();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(sk, &application)
|
||||
.encrypt_key_handle(env, sk, &application)
|
||||
.map_err(|_| Ctap1StatusCode::SW_INTERNAL_EXCEPTION)?;
|
||||
if key_handle.len() > 0xFF {
|
||||
// This is just being defensive with unreachable code.
|
||||
@@ -314,17 +307,14 @@ impl Ctap1Command {
|
||||
// +-------------------+---------+--------------+-----------------+
|
||||
// + application (32B) | UP (1B) | Counter (4B) | challenge (32B) |
|
||||
// +-------------------+---------+--------------+-----------------+
|
||||
fn process_authenticate<R, CheckUserPresence>(
|
||||
fn process_authenticate(
|
||||
env: &mut impl Env,
|
||||
challenge: [u8; 32],
|
||||
application: [u8; 32],
|
||||
key_handle: Vec<u8>,
|
||||
flags: Ctap1Flags,
|
||||
ctap_state: &mut CtapState<R, CheckUserPresence>,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode>
|
||||
where
|
||||
R: Rng256,
|
||||
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
|
||||
{
|
||||
ctap_state: &mut CtapState,
|
||||
) -> Result<Vec<u8>, Ctap1StatusCode> {
|
||||
let credential_source = ctap_state
|
||||
.decrypt_credential_source(key_handle, &application)
|
||||
.map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?;
|
||||
@@ -333,7 +323,7 @@ impl Ctap1Command {
|
||||
return Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED);
|
||||
}
|
||||
ctap_state
|
||||
.increment_global_signature_counter()
|
||||
.increment_global_signature_counter(env)
|
||||
.map_err(|_| Ctap1StatusCode::SW_WRONG_DATA)?;
|
||||
let mut signature_data = ctap_state
|
||||
.generate_auth_data(&application, Ctap1Command::USER_PRESENCE_INDICATOR_BYTE)
|
||||
@@ -356,7 +346,7 @@ impl Ctap1Command {
|
||||
mod test {
|
||||
use super::super::{key_material, CREDENTIAL_ID_SIZE, USE_SIGNATURE_COUNTER};
|
||||
use super::*;
|
||||
use crypto::rng256::ThreadRng256;
|
||||
use crate::env::test::TestEnv;
|
||||
use crypto::Hash256;
|
||||
|
||||
const CLOCK_FREQUENCY_HZ: usize = 32768;
|
||||
@@ -406,30 +396,34 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_allowed() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
ctap_state.persistent_store.toggle_always_uv().unwrap();
|
||||
|
||||
let application = [0x0A; 32];
|
||||
let message = create_register_message(&application);
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_COMMAND_NOT_ALLOWED));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_register() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let application = [0x0A; 32];
|
||||
let message = create_register_message(&application);
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
// Certificate and private key are missing
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION));
|
||||
|
||||
@@ -440,7 +434,8 @@ mod test {
|
||||
.is_ok());
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
// Certificate is still missing
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_INTERNAL_EXCEPTION));
|
||||
|
||||
@@ -452,7 +447,8 @@ mod test {
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE).unwrap();
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE)
|
||||
.unwrap();
|
||||
assert_eq!(response[0], Ctap1Command::LEGACY_BYTE);
|
||||
assert_eq!(response[66], CREDENTIAL_ID_SIZE as u8);
|
||||
assert!(ctap_state
|
||||
@@ -468,13 +464,15 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_register_bad_message() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let application = [0x0A; 32];
|
||||
let message = create_register_message(&application);
|
||||
let response = Ctap1Command::process_command(
|
||||
&mut env,
|
||||
&message[..message.len() - 1],
|
||||
&mut ctap_state,
|
||||
START_CLOCK_VALUE,
|
||||
@@ -488,60 +486,72 @@ mod test {
|
||||
let application = [0x0A; 32];
|
||||
let message = create_register_message(&application);
|
||||
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&message, &mut ctap_state, TIMEOUT_CLOCK_VALUE);
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_check_only() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let message = create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle);
|
||||
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_check_only_wrong_rp() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let application = [0x55; 32];
|
||||
let message = create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle);
|
||||
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_DATA));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_check_only_wrong_length() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let mut message = create_authenticate_message(
|
||||
&application,
|
||||
Ctap1Flags::DontEnforceUpAndSign,
|
||||
@@ -549,73 +559,89 @@ mod test {
|
||||
);
|
||||
|
||||
message.push(0x00);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert!(response.is_ok());
|
||||
|
||||
message.push(0x00);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert!(response.is_ok());
|
||||
|
||||
message.push(0x00);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert!(response.is_ok());
|
||||
|
||||
message.push(0x00);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_LENGTH));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_check_only_wrong_cla() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let mut message =
|
||||
create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle);
|
||||
message[0] = 0xEE;
|
||||
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_CLA_INVALID));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_check_only_wrong_ins() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let mut message =
|
||||
create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle);
|
||||
message[1] = 0xEE;
|
||||
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_INS_INVALID));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_check_only_wrong_flags() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let mut message =
|
||||
create_authenticate_message(&application, Ctap1Flags::CheckOnly, &key_handle);
|
||||
message[2] = 0xEE;
|
||||
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_DATA));
|
||||
}
|
||||
|
||||
@@ -629,21 +655,25 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_enforce() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let message =
|
||||
create_authenticate_message(&application, Ctap1Flags::EnforceUpAndSign, &key_handle);
|
||||
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE).unwrap();
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE)
|
||||
.unwrap();
|
||||
assert_eq!(response[0], 0x01);
|
||||
check_signature_counter(
|
||||
array_ref!(response, 1, 4),
|
||||
@@ -656,14 +686,17 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_process_authenticate_dont_enforce() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let sk = crypto::ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
let rp_id = "example.com";
|
||||
let application = crypto::sha256::Sha256::hash(rp_id.as_bytes());
|
||||
let key_handle = ctap_state.encrypt_key_handle(sk, &application).unwrap();
|
||||
let key_handle = ctap_state
|
||||
.encrypt_key_handle(&mut env, sk, &application)
|
||||
.unwrap();
|
||||
let message = create_authenticate_message(
|
||||
&application,
|
||||
Ctap1Flags::DontEnforceUpAndSign,
|
||||
@@ -671,7 +704,8 @@ mod test {
|
||||
);
|
||||
|
||||
let response =
|
||||
Ctap1Command::process_command(&message, &mut ctap_state, TIMEOUT_CLOCK_VALUE).unwrap();
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE)
|
||||
.unwrap();
|
||||
assert_eq!(response[0], 0x01);
|
||||
check_signature_counter(
|
||||
array_ref!(response, 1, 4),
|
||||
@@ -689,13 +723,15 @@ mod test {
|
||||
let message =
|
||||
create_authenticate_message(&application, Ctap1Flags::EnforceUpAndSign, &key_handle);
|
||||
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response = Ctap1Command::process_command(&message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, START_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_WRONG_DATA));
|
||||
}
|
||||
|
||||
@@ -706,14 +742,15 @@ mod test {
|
||||
let message =
|
||||
create_authenticate_message(&application, Ctap1Flags::EnforceUpAndSign, &key_handle);
|
||||
|
||||
let mut rng = ThreadRng256 {};
|
||||
let dummy_user_presence = |_| panic!("Unexpected user presence check in CTAP1");
|
||||
let mut ctap_state = CtapState::new(&mut rng, dummy_user_presence, START_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
env.user_presence()
|
||||
.set(|_| panic!("Unexpected user presence check in CTAP1"));
|
||||
let mut ctap_state = CtapState::new(&mut env, START_CLOCK_VALUE);
|
||||
|
||||
ctap_state.u2f_up_state.consume_up(START_CLOCK_VALUE);
|
||||
ctap_state.u2f_up_state.grant_up(START_CLOCK_VALUE);
|
||||
let response =
|
||||
Ctap1Command::process_command(&message, &mut ctap_state, TIMEOUT_CLOCK_VALUE);
|
||||
Ctap1Command::process_command(&mut env, &message, &mut ctap_state, TIMEOUT_CLOCK_VALUE);
|
||||
assert_eq!(response, Err(Ctap1StatusCode::SW_COND_USE_NOT_SATISFIED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ use super::ctap1;
|
||||
use super::status_code::Ctap2StatusCode;
|
||||
use super::timed_permission::TimedPermission;
|
||||
use super::CtapState;
|
||||
use crate::env::Env;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use arrayref::{array_ref, array_refs};
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use core::fmt::Write;
|
||||
use crypto::rng256::Rng256;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use libtock_drivers::console::Console;
|
||||
use libtock_drivers::timer::{ClockValue, Duration, Timestamp};
|
||||
@@ -146,16 +146,13 @@ impl CtapHid {
|
||||
|
||||
// Process an incoming USB HID packet, and optionally returns a list of outgoing packets to
|
||||
// send as a reply.
|
||||
pub fn process_hid_packet<R, CheckUserPresence>(
|
||||
pub fn process_hid_packet(
|
||||
&mut self,
|
||||
env: &mut impl Env,
|
||||
packet: &HidPacket,
|
||||
clock_value: ClockValue,
|
||||
ctap_state: &mut CtapState<R, CheckUserPresence>,
|
||||
) -> HidPacketIterator
|
||||
where
|
||||
R: Rng256,
|
||||
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
|
||||
{
|
||||
ctap_state: &mut CtapState,
|
||||
) -> HidPacketIterator {
|
||||
// TODO: Send COMMAND_KEEPALIVE every 100ms?
|
||||
match self
|
||||
.assembler
|
||||
@@ -183,6 +180,7 @@ impl CtapHid {
|
||||
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
match ctap1::Ctap1Command::process_command(
|
||||
env,
|
||||
&message.payload,
|
||||
ctap_state,
|
||||
clock_value,
|
||||
@@ -200,7 +198,7 @@ impl CtapHid {
|
||||
// don't handle any other packet in the meantime.
|
||||
// TODO: Send keep-alive packets in the meantime.
|
||||
let response =
|
||||
ctap_state.process_command(&message.payload, cid, clock_value);
|
||||
ctap_state.process_command(env, &message.payload, cid, clock_value);
|
||||
if let Some(iterator) = CtapHid::split_message(Message {
|
||||
cid,
|
||||
cmd: CtapHid::COMMAND_CBOR,
|
||||
@@ -433,27 +431,25 @@ impl CtapHid {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crypto::rng256::ThreadRng256;
|
||||
use crate::env::test::TestEnv;
|
||||
|
||||
const CLOCK_FREQUENCY_HZ: usize = 32768;
|
||||
// Except for tests for timeouts (done in ctap1.rs), transactions are time independant.
|
||||
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
|
||||
const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
|
||||
|
||||
fn process_messages<CheckUserPresence>(
|
||||
fn process_messages(
|
||||
env: &mut impl Env,
|
||||
ctap_hid: &mut CtapHid,
|
||||
ctap_state: &mut CtapState<ThreadRng256, CheckUserPresence>,
|
||||
ctap_state: &mut CtapState,
|
||||
request: Vec<Message>,
|
||||
) -> Option<Vec<Message>>
|
||||
where
|
||||
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
|
||||
{
|
||||
) -> Option<Vec<Message>> {
|
||||
let mut result = Vec::new();
|
||||
let mut assembler_reply = MessageAssembler::new();
|
||||
for msg_request in request {
|
||||
for pkt_request in HidPacketIterator::new(msg_request).unwrap() {
|
||||
for pkt_reply in
|
||||
ctap_hid.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE, ctap_state)
|
||||
ctap_hid.process_hid_packet(env, &pkt_request, DUMMY_CLOCK_VALUE, ctap_state)
|
||||
{
|
||||
match assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP) {
|
||||
Ok(Some(message)) => result.push(message),
|
||||
@@ -466,15 +462,14 @@ mod test {
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn cid_from_init<CheckUserPresence>(
|
||||
fn cid_from_init(
|
||||
env: &mut impl Env,
|
||||
ctap_hid: &mut CtapHid,
|
||||
ctap_state: &mut CtapState<ThreadRng256, CheckUserPresence>,
|
||||
) -> ChannelID
|
||||
where
|
||||
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
|
||||
{
|
||||
ctap_state: &mut CtapState,
|
||||
) -> ChannelID {
|
||||
let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
|
||||
let reply = process_messages(
|
||||
env,
|
||||
ctap_hid,
|
||||
ctap_state,
|
||||
vec![Message {
|
||||
@@ -521,15 +516,16 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_spurious_continuation_packet() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
|
||||
let mut packet = [0x00; 64];
|
||||
packet[0..7].copy_from_slice(&[0xC1, 0xC1, 0xC1, 0xC1, 0x00, 0x51, 0x51]);
|
||||
let mut assembler_reply = MessageAssembler::new();
|
||||
for pkt_reply in ctap_hid.process_hid_packet(&packet, DUMMY_CLOCK_VALUE, &mut ctap_state) {
|
||||
for pkt_reply in
|
||||
ctap_hid.process_hid_packet(&mut env, &packet, DUMMY_CLOCK_VALUE, &mut ctap_state)
|
||||
{
|
||||
// Continuation packets are silently ignored.
|
||||
assert_eq!(
|
||||
assembler_reply
|
||||
@@ -542,12 +538,12 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_command_init() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
|
||||
let reply = process_messages(
|
||||
&mut env,
|
||||
&mut ctap_hid,
|
||||
&mut ctap_state,
|
||||
vec![Message {
|
||||
@@ -587,11 +583,10 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_command_init_for_sync() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
let cid = cid_from_init(&mut ctap_hid, &mut ctap_state);
|
||||
let cid = cid_from_init(&mut env, &mut ctap_hid, &mut ctap_state);
|
||||
|
||||
// Ping packet with a length longer than one packet.
|
||||
let mut packet1 = [0x51; 64];
|
||||
@@ -606,9 +601,12 @@ mod test {
|
||||
let mut result = Vec::new();
|
||||
let mut assembler_reply = MessageAssembler::new();
|
||||
for pkt_request in &[packet1, packet2] {
|
||||
for pkt_reply in
|
||||
ctap_hid.process_hid_packet(pkt_request, DUMMY_CLOCK_VALUE, &mut ctap_state)
|
||||
{
|
||||
for pkt_reply in ctap_hid.process_hid_packet(
|
||||
&mut env,
|
||||
pkt_request,
|
||||
DUMMY_CLOCK_VALUE,
|
||||
&mut ctap_state,
|
||||
) {
|
||||
if let Some(message) = assembler_reply
|
||||
.parse_packet(&pkt_reply, DUMMY_TIMESTAMP)
|
||||
.unwrap()
|
||||
@@ -647,13 +645,13 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_command_ping() {
|
||||
let mut rng = ThreadRng256 {};
|
||||
let user_immediately_present = |_| Ok(());
|
||||
let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||
let mut env = TestEnv::new();
|
||||
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
let cid = cid_from_init(&mut ctap_hid, &mut ctap_state);
|
||||
let cid = cid_from_init(&mut env, &mut ctap_hid, &mut ctap_state);
|
||||
|
||||
let reply = process_messages(
|
||||
&mut env,
|
||||
&mut ctap_hid,
|
||||
&mut ctap_state,
|
||||
vec![Message {
|
||||
|
||||
479
src/ctap/mod.rs
479
src/ctap/mod.rs
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
// For now, only the CTAP2 codes are here, the CTAP1 are not included.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Ctap2StatusCode {
|
||||
CTAP2_OK = 0x00,
|
||||
CTAP1_ERR_INVALID_COMMAND = 0x01,
|
||||
|
||||
Reference in New Issue
Block a user