Merge branch 'develop' into doc
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -18,8 +18,8 @@ use super::data_formats::{
|
|||||||
extract_unsigned, ok_or_missing, ClientPinSubCommand, ConfigSubCommand, ConfigSubCommandParams,
|
extract_unsigned, ok_or_missing, ClientPinSubCommand, ConfigSubCommand, ConfigSubCommandParams,
|
||||||
CoseKey, CredentialManagementSubCommand, CredentialManagementSubCommandParameters,
|
CoseKey, CredentialManagementSubCommand, CredentialManagementSubCommandParameters,
|
||||||
GetAssertionExtensions, GetAssertionOptions, MakeCredentialExtensions, MakeCredentialOptions,
|
GetAssertionExtensions, GetAssertionOptions, MakeCredentialExtensions, MakeCredentialOptions,
|
||||||
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialRpEntity,
|
PinUvAuthProtocol, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
|
||||||
PublicKeyCredentialUserEntity, SetMinPinLengthParams,
|
PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, SetMinPinLengthParams,
|
||||||
};
|
};
|
||||||
use super::key_material;
|
use super::key_material;
|
||||||
use super::status_code::Ctap2StatusCode;
|
use super::status_code::Ctap2StatusCode;
|
||||||
@@ -302,12 +302,12 @@ impl TryFrom<cbor::Value> for AuthenticatorGetAssertionParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct AuthenticatorClientPinParameters {
|
pub struct AuthenticatorClientPinParameters {
|
||||||
pub pin_uv_auth_protocol: u64,
|
pub pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||||
pub sub_command: ClientPinSubCommand,
|
pub sub_command: ClientPinSubCommand,
|
||||||
pub key_agreement: Option<CoseKey>,
|
pub key_agreement: Option<CoseKey>,
|
||||||
pub pin_auth: Option<Vec<u8>>,
|
pub pin_uv_auth_param: Option<Vec<u8>>,
|
||||||
pub new_pin_enc: Option<Vec<u8>>,
|
pub new_pin_enc: Option<Vec<u8>>,
|
||||||
pub pin_hash_enc: Option<Vec<u8>>,
|
pub pin_hash_enc: Option<Vec<u8>>,
|
||||||
pub permissions: Option<u8>,
|
pub permissions: Option<u8>,
|
||||||
@@ -323,7 +323,7 @@ impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
|
|||||||
0x01 => pin_uv_auth_protocol,
|
0x01 => pin_uv_auth_protocol,
|
||||||
0x02 => sub_command,
|
0x02 => sub_command,
|
||||||
0x03 => key_agreement,
|
0x03 => key_agreement,
|
||||||
0x04 => pin_auth,
|
0x04 => pin_uv_auth_param,
|
||||||
0x05 => new_pin_enc,
|
0x05 => new_pin_enc,
|
||||||
0x06 => pin_hash_enc,
|
0x06 => pin_hash_enc,
|
||||||
0x09 => permissions,
|
0x09 => permissions,
|
||||||
@@ -331,10 +331,11 @@ impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
|
|||||||
} = extract_map(cbor_value)?;
|
} = extract_map(cbor_value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pin_uv_auth_protocol = extract_unsigned(ok_or_missing(pin_uv_auth_protocol)?)?;
|
let pin_uv_auth_protocol =
|
||||||
|
PinUvAuthProtocol::try_from(ok_or_missing(pin_uv_auth_protocol)?)?;
|
||||||
let sub_command = ClientPinSubCommand::try_from(ok_or_missing(sub_command)?)?;
|
let sub_command = ClientPinSubCommand::try_from(ok_or_missing(sub_command)?)?;
|
||||||
let key_agreement = key_agreement.map(CoseKey::try_from).transpose()?;
|
let key_agreement = key_agreement.map(CoseKey::try_from).transpose()?;
|
||||||
let pin_auth = pin_auth.map(extract_byte_string).transpose()?;
|
let pin_uv_auth_param = pin_uv_auth_param.map(extract_byte_string).transpose()?;
|
||||||
let new_pin_enc = new_pin_enc.map(extract_byte_string).transpose()?;
|
let new_pin_enc = new_pin_enc.map(extract_byte_string).transpose()?;
|
||||||
let pin_hash_enc = pin_hash_enc.map(extract_byte_string).transpose()?;
|
let pin_hash_enc = pin_hash_enc.map(extract_byte_string).transpose()?;
|
||||||
// We expect a bit field of 8 bits, and drop everything else.
|
// We expect a bit field of 8 bits, and drop everything else.
|
||||||
@@ -349,7 +350,7 @@ impl TryFrom<cbor::Value> for AuthenticatorClientPinParameters {
|
|||||||
pin_uv_auth_protocol,
|
pin_uv_auth_protocol,
|
||||||
sub_command,
|
sub_command,
|
||||||
key_agreement,
|
key_agreement,
|
||||||
pin_auth,
|
pin_uv_auth_param,
|
||||||
new_pin_enc,
|
new_pin_enc,
|
||||||
pin_hash_enc,
|
pin_hash_enc,
|
||||||
permissions,
|
permissions,
|
||||||
@@ -706,10 +707,10 @@ mod test {
|
|||||||
AuthenticatorClientPinParameters::try_from(cbor_value).unwrap();
|
AuthenticatorClientPinParameters::try_from(cbor_value).unwrap();
|
||||||
|
|
||||||
let expected_client_pin_parameters = AuthenticatorClientPinParameters {
|
let expected_client_pin_parameters = AuthenticatorClientPinParameters {
|
||||||
pin_uv_auth_protocol: 1,
|
pin_uv_auth_protocol: PinUvAuthProtocol::V1,
|
||||||
sub_command: ClientPinSubCommand::GetPinRetries,
|
sub_command: ClientPinSubCommand::GetPinRetries,
|
||||||
key_agreement: Some(cose_key),
|
key_agreement: Some(cose_key),
|
||||||
pin_auth: Some(vec![0xBB]),
|
pin_uv_auth_param: Some(vec![0xBB]),
|
||||||
new_pin_enc: Some(vec![0xCC]),
|
new_pin_enc: Some(vec![0xCC]),
|
||||||
pin_hash_enc: Some(vec![0xDD]),
|
pin_hash_enc: Some(vec![0xDD]),
|
||||||
permissions: Some(0x03),
|
permissions: Some(0x03),
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ pub fn process_config(
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ctap::customization::ENFORCE_ALWAYS_UV;
|
use crate::ctap::customization::ENFORCE_ALWAYS_UV;
|
||||||
|
use crate::ctap::data_formats::PinUvAuthProtocol;
|
||||||
use crypto::rng256::ThreadRng256;
|
use crypto::rng256::ThreadRng256;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -134,7 +135,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
let config_params = AuthenticatorConfigParameters {
|
let config_params = AuthenticatorConfigParameters {
|
||||||
sub_command: ConfigSubCommand::EnableEnterpriseAttestation,
|
sub_command: ConfigSubCommand::EnableEnterpriseAttestation,
|
||||||
@@ -161,7 +163,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
let config_params = AuthenticatorConfigParameters {
|
let config_params = AuthenticatorConfigParameters {
|
||||||
sub_command: ConfigSubCommand::ToggleAlwaysUv,
|
sub_command: ConfigSubCommand::ToggleAlwaysUv,
|
||||||
@@ -197,7 +200,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
||||||
|
|
||||||
let pin_uv_auth_param = Some(vec![
|
let pin_uv_auth_param = Some(vec![
|
||||||
@@ -257,7 +261,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
// First, increase minimum PIN length from 4 to 6 without PIN auth.
|
// First, increase minimum PIN length from 4 to 6 without PIN auth.
|
||||||
let min_pin_length = 6;
|
let min_pin_length = 6;
|
||||||
@@ -301,7 +306,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
// First, set RP IDs without PIN auth.
|
// First, set RP IDs without PIN auth.
|
||||||
let min_pin_length = 6;
|
let min_pin_length = 6;
|
||||||
@@ -377,7 +383,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
||||||
// Increase min PIN, force PIN change.
|
// Increase min PIN, force PIN change.
|
||||||
@@ -400,7 +407,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
persistent_store.set_pin(&[0x88; 16], 4).unwrap();
|
||||||
let pin_uv_auth_param = Some(vec![
|
let pin_uv_auth_param = Some(vec![
|
||||||
@@ -431,7 +439,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
let config_params = AuthenticatorConfigParameters {
|
let config_params = AuthenticatorConfigParameters {
|
||||||
sub_command: ConfigSubCommand::VendorPrototype,
|
sub_command: ConfigSubCommand::VendorPrototype,
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ pub fn process_credential_management(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::super::data_formats::PublicKeyCredentialType;
|
use super::super::data_formats::{PinUvAuthProtocol, PublicKeyCredentialType};
|
||||||
use super::super::CtapState;
|
use super::super::CtapState;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crypto::rng256::{Rng256, ThreadRng256};
|
use crypto::rng256::{Rng256, ThreadRng256};
|
||||||
@@ -382,7 +382,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
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(&mut rng);
|
||||||
|
|
||||||
let user_immediately_present = |_| Ok(());
|
let user_immediately_present = |_| Ok(());
|
||||||
@@ -453,7 +454,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let credential_source1 = create_credential_source(&mut rng);
|
let credential_source1 = create_credential_source(&mut rng);
|
||||||
let mut credential_source2 = create_credential_source(&mut rng);
|
let mut credential_source2 = create_credential_source(&mut rng);
|
||||||
credential_source2.rp_id = "another.example.com".to_string();
|
credential_source2.rp_id = "another.example.com".to_string();
|
||||||
@@ -550,7 +552,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
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(&mut rng);
|
||||||
|
|
||||||
let user_immediately_present = |_| Ok(());
|
let user_immediately_present = |_| Ok(());
|
||||||
@@ -632,7 +635,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let credential_source1 = create_credential_source(&mut rng);
|
let credential_source1 = create_credential_source(&mut rng);
|
||||||
let mut credential_source2 = create_credential_source(&mut rng);
|
let mut credential_source2 = create_credential_source(&mut rng);
|
||||||
credential_source2.user_handle = vec![0x02];
|
credential_source2.user_handle = vec![0x02];
|
||||||
@@ -737,7 +741,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
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(&mut rng);
|
||||||
credential_source.credential_id = vec![0x1D; 32];
|
credential_source.credential_id = vec![0x1D; 32];
|
||||||
|
|
||||||
@@ -808,7 +813,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
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(&mut rng);
|
||||||
credential_source.credential_id = vec![0x1D; 32];
|
credential_source.credential_id = vec![0x1D; 32];
|
||||||
|
|
||||||
@@ -880,7 +886,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
let user_immediately_present = |_| Ok(());
|
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 rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ pub struct GetAssertionHmacSecretInput {
|
|||||||
pub key_agreement: CoseKey,
|
pub key_agreement: CoseKey,
|
||||||
pub salt_enc: Vec<u8>,
|
pub salt_enc: Vec<u8>,
|
||||||
pub salt_auth: Vec<u8>,
|
pub salt_auth: Vec<u8>,
|
||||||
|
pub pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
|
impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
|
||||||
@@ -367,16 +368,20 @@ impl TryFrom<cbor::Value> for GetAssertionHmacSecretInput {
|
|||||||
1 => key_agreement,
|
1 => key_agreement,
|
||||||
2 => salt_enc,
|
2 => salt_enc,
|
||||||
3 => salt_auth,
|
3 => salt_auth,
|
||||||
|
4 => pin_uv_auth_protocol,
|
||||||
} = extract_map(cbor_value)?;
|
} = extract_map(cbor_value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let key_agreement = CoseKey::try_from(ok_or_missing(key_agreement)?)?;
|
let key_agreement = CoseKey::try_from(ok_or_missing(key_agreement)?)?;
|
||||||
let salt_enc = extract_byte_string(ok_or_missing(salt_enc)?)?;
|
let salt_enc = extract_byte_string(ok_or_missing(salt_enc)?)?;
|
||||||
let salt_auth = extract_byte_string(ok_or_missing(salt_auth)?)?;
|
let salt_auth = extract_byte_string(ok_or_missing(salt_auth)?)?;
|
||||||
|
let pin_uv_auth_protocol =
|
||||||
|
pin_uv_auth_protocol.map_or(Ok(PinUvAuthProtocol::V1), PinUvAuthProtocol::try_from)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
key_agreement,
|
key_agreement,
|
||||||
salt_enc,
|
salt_enc,
|
||||||
salt_auth,
|
salt_auth,
|
||||||
|
pin_uv_auth_protocol,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -638,7 +643,7 @@ impl TryFrom<cbor::Value> for PublicKeyCredentialSource {
|
|||||||
let cred_protect_policy = cred_protect_policy
|
let cred_protect_policy = cred_protect_policy
|
||||||
.map(CredentialProtectionPolicy::try_from)
|
.map(CredentialProtectionPolicy::try_from)
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
let creation_order = creation_order.map(extract_unsigned).unwrap_or(Ok(0))?;
|
let creation_order = creation_order.map_or(Ok(0), extract_unsigned)?;
|
||||||
let user_name = user_name.map(extract_text_string).transpose()?;
|
let user_name = user_name.map(extract_text_string).transpose()?;
|
||||||
let user_icon = user_icon.map(extract_text_string).transpose()?;
|
let user_icon = user_icon.map(extract_text_string).transpose()?;
|
||||||
let cred_blob = cred_blob.map(extract_byte_string).transpose()?;
|
let cred_blob = cred_blob.map(extract_byte_string).transpose()?;
|
||||||
@@ -809,6 +814,24 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum PinUvAuthProtocol {
|
||||||
|
V1,
|
||||||
|
V2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<cbor::Value> for PinUvAuthProtocol {
|
||||||
|
type Error = Ctap2StatusCode;
|
||||||
|
|
||||||
|
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
|
||||||
|
match extract_unsigned(cbor_value)? {
|
||||||
|
1 => Ok(PinUvAuthProtocol::V1),
|
||||||
|
2 => Ok(PinUvAuthProtocol::V2),
|
||||||
|
_ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(test, derive(IntoEnumIterator))]
|
#[cfg_attr(test, derive(IntoEnumIterator))]
|
||||||
pub enum ClientPinSubCommand {
|
pub enum ClientPinSubCommand {
|
||||||
@@ -1569,7 +1592,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_get_assertion_extensions() {
|
fn test_from_get_assertion_extensions_default_protocol() {
|
||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
|
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pk = sk.genpk();
|
let pk = sk.genpk();
|
||||||
@@ -1588,6 +1611,7 @@ mod test {
|
|||||||
key_agreement: cose_key,
|
key_agreement: cose_key,
|
||||||
salt_enc: vec![0x02; 32],
|
salt_enc: vec![0x02; 32],
|
||||||
salt_auth: vec![0x03; 16],
|
salt_auth: vec![0x03; 16],
|
||||||
|
pin_uv_auth_protocol: PinUvAuthProtocol::V1,
|
||||||
};
|
};
|
||||||
let expected_extensions = GetAssertionExtensions {
|
let expected_extensions = GetAssertionExtensions {
|
||||||
hmac_secret: Some(expected_input),
|
hmac_secret: Some(expected_input),
|
||||||
@@ -1597,6 +1621,38 @@ mod test {
|
|||||||
assert_eq!(extensions, Ok(expected_extensions));
|
assert_eq!(extensions, Ok(expected_extensions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_get_assertion_extensions_with_protocol() {
|
||||||
|
let mut rng = ThreadRng256 {};
|
||||||
|
let sk = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
|
let pk = sk.genpk();
|
||||||
|
let cose_key = CoseKey::from(pk);
|
||||||
|
let cbor_extensions = cbor_map! {
|
||||||
|
"hmac-secret" => cbor_map! {
|
||||||
|
1 => cbor::Value::from(cose_key.clone()),
|
||||||
|
2 => vec![0x02; 32],
|
||||||
|
3 => vec![0x03; 16],
|
||||||
|
4 => 2,
|
||||||
|
},
|
||||||
|
"credBlob" => true,
|
||||||
|
"largeBlobKey" => true,
|
||||||
|
};
|
||||||
|
let extensions = GetAssertionExtensions::try_from(cbor_extensions);
|
||||||
|
let expected_input = GetAssertionHmacSecretInput {
|
||||||
|
key_agreement: cose_key,
|
||||||
|
salt_enc: vec![0x02; 32],
|
||||||
|
salt_auth: vec![0x03; 16],
|
||||||
|
pin_uv_auth_protocol: PinUvAuthProtocol::V2,
|
||||||
|
};
|
||||||
|
let expected_extensions = GetAssertionExtensions {
|
||||||
|
hmac_secret: Some(expected_input),
|
||||||
|
cred_blob: true,
|
||||||
|
large_blob_key: Some(true),
|
||||||
|
};
|
||||||
|
assert_eq!(extensions, Ok(expected_extensions));
|
||||||
|
// TODO more tests, check default
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_make_credential_options() {
|
fn test_from_make_credential_options() {
|
||||||
let cbor_make_options = cbor_map! {
|
let cbor_make_options = cbor_map! {
|
||||||
@@ -1759,6 +1815,25 @@ mod test {
|
|||||||
assert_eq!(cose_key.algorithm, ES256_ALGORITHM);
|
assert_eq!(cose_key.algorithm, ES256_ALGORITHM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_pin_uv_auth_protocol() {
|
||||||
|
let cbor_protocol: cbor::Value = cbor_int!(0x01);
|
||||||
|
assert_eq!(
|
||||||
|
PinUvAuthProtocol::try_from(cbor_protocol),
|
||||||
|
Ok(PinUvAuthProtocol::V1)
|
||||||
|
);
|
||||||
|
let cbor_protocol: cbor::Value = cbor_int!(0x02);
|
||||||
|
assert_eq!(
|
||||||
|
PinUvAuthProtocol::try_from(cbor_protocol),
|
||||||
|
Ok(PinUvAuthProtocol::V2)
|
||||||
|
);
|
||||||
|
let cbor_protocol: cbor::Value = cbor_int!(0x03);
|
||||||
|
assert_eq!(
|
||||||
|
PinUvAuthProtocol::try_from(cbor_protocol),
|
||||||
|
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_into_client_pin_sub_command() {
|
fn test_from_into_client_pin_sub_command() {
|
||||||
let cbor_sub_command: cbor::Value = cbor_int!(0x01);
|
let cbor_sub_command: cbor::Value = cbor_int!(0x01);
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ impl LargeBlobs {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::super::data_formats::PinUvAuthProtocol;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crypto::rng256::ThreadRng256;
|
use crypto::rng256::ThreadRng256;
|
||||||
|
|
||||||
@@ -144,7 +145,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut large_blobs = LargeBlobs::new();
|
let mut large_blobs = LargeBlobs::new();
|
||||||
|
|
||||||
let large_blob = vec![
|
let large_blob = vec![
|
||||||
@@ -175,7 +177,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut large_blobs = LargeBlobs::new();
|
let mut large_blobs = LargeBlobs::new();
|
||||||
|
|
||||||
const BLOB_LEN: usize = 200;
|
const BLOB_LEN: usize = 200;
|
||||||
@@ -237,7 +240,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut large_blobs = LargeBlobs::new();
|
let mut large_blobs = LargeBlobs::new();
|
||||||
|
|
||||||
const BLOB_LEN: usize = 200;
|
const BLOB_LEN: usize = 200;
|
||||||
@@ -283,7 +287,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut large_blobs = LargeBlobs::new();
|
let mut large_blobs = LargeBlobs::new();
|
||||||
|
|
||||||
const BLOB_LEN: usize = 200;
|
const BLOB_LEN: usize = 200;
|
||||||
@@ -329,7 +334,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut large_blobs = LargeBlobs::new();
|
let mut large_blobs = LargeBlobs::new();
|
||||||
|
|
||||||
const BLOB_LEN: usize = 20;
|
const BLOB_LEN: usize = 20;
|
||||||
@@ -358,7 +364,8 @@ mod test {
|
|||||||
let mut persistent_store = PersistentStore::new(&mut rng);
|
let mut persistent_store = PersistentStore::new(&mut rng);
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x55; 32];
|
let pin_uv_auth_token = [0x55; 32];
|
||||||
let mut client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let mut client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
let mut large_blobs = LargeBlobs::new();
|
let mut large_blobs = LargeBlobs::new();
|
||||||
|
|
||||||
const BLOB_LEN: usize = 20;
|
const BLOB_LEN: usize = 20;
|
||||||
|
|||||||
@@ -1223,7 +1223,8 @@ mod test {
|
|||||||
use super::command::AuthenticatorAttestationMaterial;
|
use super::command::AuthenticatorAttestationMaterial;
|
||||||
use super::data_formats::{
|
use super::data_formats::{
|
||||||
CoseKey, GetAssertionHmacSecretInput, GetAssertionOptions, MakeCredentialExtensions,
|
CoseKey, GetAssertionHmacSecretInput, GetAssertionOptions, MakeCredentialExtensions,
|
||||||
MakeCredentialOptions, PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity,
|
MakeCredentialOptions, PinUvAuthProtocol, PublicKeyCredentialRpEntity,
|
||||||
|
PublicKeyCredentialUserEntity,
|
||||||
};
|
};
|
||||||
use super::*;
|
use super::*;
|
||||||
use cbor::{cbor_array, cbor_array_vec, cbor_map};
|
use cbor::{cbor_array, cbor_array_vec, cbor_map};
|
||||||
@@ -1983,6 +1984,7 @@ mod test {
|
|||||||
key_agreement: CoseKey::from(pk),
|
key_agreement: CoseKey::from(pk),
|
||||||
salt_enc: vec![0x02; 32],
|
salt_enc: vec![0x02; 32],
|
||||||
salt_auth: vec![0x03; 16],
|
salt_auth: vec![0x03; 16],
|
||||||
|
pin_uv_auth_protocol: PinUvAuthProtocol::V1,
|
||||||
};
|
};
|
||||||
let get_extensions = GetAssertionExtensions {
|
let get_extensions = GetAssertionExtensions {
|
||||||
hmac_secret: Some(hmac_secret_input),
|
hmac_secret: Some(hmac_secret_input),
|
||||||
@@ -2040,6 +2042,7 @@ mod test {
|
|||||||
key_agreement: CoseKey::from(pk),
|
key_agreement: CoseKey::from(pk),
|
||||||
salt_enc: vec![0x02; 32],
|
salt_enc: vec![0x02; 32],
|
||||||
salt_auth: vec![0x03; 16],
|
salt_auth: vec![0x03; 16],
|
||||||
|
pin_uv_auth_protocol: PinUvAuthProtocol::V1,
|
||||||
};
|
};
|
||||||
let get_extensions = GetAssertionExtensions {
|
let get_extensions = GetAssertionExtensions {
|
||||||
hmac_secret: Some(hmac_secret_input),
|
hmac_secret: Some(hmac_secret_input),
|
||||||
@@ -2317,7 +2320,8 @@ mod test {
|
|||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
let key_agreement_key = crypto::ecdh::SecKey::gensk(&mut rng);
|
||||||
let pin_uv_auth_token = [0x88; 32];
|
let pin_uv_auth_token = [0x88; 32];
|
||||||
let client_pin = ClientPin::new_test(key_agreement_key, pin_uv_auth_token);
|
let client_pin =
|
||||||
|
ClientPin::new_test(key_agreement_key, pin_uv_auth_token, PinUvAuthProtocol::V1);
|
||||||
|
|
||||||
let user_immediately_present = |_| Ok(());
|
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 rng, user_immediately_present, DUMMY_CLOCK_VALUE);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use crate::ctap::client_pin::PIN_TOKEN_LENGTH;
|
use crate::ctap::client_pin::PIN_TOKEN_LENGTH;
|
||||||
use crate::ctap::data_formats::CoseKey;
|
use crate::ctap::data_formats::{CoseKey, PinUvAuthProtocol};
|
||||||
use crate::ctap::status_code::Ctap2StatusCode;
|
use crate::ctap::status_code::Ctap2StatusCode;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
@@ -21,6 +21,8 @@ use alloc::vec::Vec;
|
|||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use crypto::cbc::{cbc_decrypt, cbc_encrypt};
|
use crypto::cbc::{cbc_decrypt, cbc_encrypt};
|
||||||
use crypto::hkdf::hkdf_empty_salt_256;
|
use crypto::hkdf::hkdf_empty_salt_256;
|
||||||
|
#[cfg(test)]
|
||||||
|
use crypto::hmac::hmac_256;
|
||||||
use crypto::hmac::{verify_hmac_256, verify_hmac_256_first_128bits};
|
use crypto::hmac::{verify_hmac_256, verify_hmac_256_first_128bits};
|
||||||
use crypto::rng256::Rng256;
|
use crypto::rng256::Rng256;
|
||||||
use crypto::sha256::Sha256;
|
use crypto::sha256::Sha256;
|
||||||
@@ -64,14 +66,13 @@ impl PinProtocol {
|
|||||||
pub fn decapsulate(
|
pub fn decapsulate(
|
||||||
&self,
|
&self,
|
||||||
peer_cose_key: CoseKey,
|
peer_cose_key: CoseKey,
|
||||||
pin_uv_auth_protocol: u64,
|
pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||||
) -> Result<Box<dyn SharedSecret>, Ctap2StatusCode> {
|
) -> Result<Box<dyn SharedSecret>, Ctap2StatusCode> {
|
||||||
let pk: crypto::ecdh::PubKey = CoseKey::try_into(peer_cose_key)?;
|
let pk: crypto::ecdh::PubKey = CoseKey::try_into(peer_cose_key)?;
|
||||||
let handshake = self.key_agreement_key.exchange_x(&pk);
|
let handshake = self.key_agreement_key.exchange_x(&pk);
|
||||||
match pin_uv_auth_protocol {
|
match pin_uv_auth_protocol {
|
||||||
1 => Ok(Box::new(SharedSecretV1::new(handshake))),
|
PinUvAuthProtocol::V1 => Ok(Box::new(SharedSecretV1::new(handshake))),
|
||||||
2 => Ok(Box::new(SharedSecretV2::new(handshake))),
|
PinUvAuthProtocol::V2 => Ok(Box::new(SharedSecretV2::new(handshake))),
|
||||||
_ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,12 +99,11 @@ pub fn verify_pin_uv_auth_token(
|
|||||||
token: &[u8; PIN_TOKEN_LENGTH],
|
token: &[u8; PIN_TOKEN_LENGTH],
|
||||||
message: &[u8],
|
message: &[u8],
|
||||||
signature: &[u8],
|
signature: &[u8],
|
||||||
pin_uv_auth_protocol: u64,
|
pin_uv_auth_protocol: PinUvAuthProtocol,
|
||||||
) -> Result<(), Ctap2StatusCode> {
|
) -> Result<(), Ctap2StatusCode> {
|
||||||
match pin_uv_auth_protocol {
|
match pin_uv_auth_protocol {
|
||||||
1 => verify_v1(token, message, signature),
|
PinUvAuthProtocol::V1 => verify_v1(token, message, signature),
|
||||||
2 => verify_v2(token, message, signature),
|
PinUvAuthProtocol::V2 => verify_v2(token, message, signature),
|
||||||
_ => Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +116,10 @@ pub trait SharedSecret {
|
|||||||
|
|
||||||
/// Verifies that the signature is a valid MAC for the given message.
|
/// Verifies that the signature is a valid MAC for the given message.
|
||||||
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode>;
|
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode>;
|
||||||
|
|
||||||
|
/// Creates a signature that matches verify.
|
||||||
|
#[cfg(test)]
|
||||||
|
fn authenticate(&self, message: &[u8]) -> Vec<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aes256_cbc_encrypt(
|
fn aes256_cbc_encrypt(
|
||||||
@@ -210,16 +214,6 @@ impl SharedSecretV1 {
|
|||||||
aes_enc_key,
|
aes_enc_key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new shared secret for testing.
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn new_test(hash: [u8; 32]) -> SharedSecretV1 {
|
|
||||||
let aes_enc_key = crypto::aes256::EncryptionKey::new(&hash);
|
|
||||||
SharedSecretV1 {
|
|
||||||
common_secret: hash,
|
|
||||||
aes_enc_key,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedSecret for SharedSecretV1 {
|
impl SharedSecret for SharedSecretV1 {
|
||||||
@@ -234,6 +228,11 @@ impl SharedSecret for SharedSecretV1 {
|
|||||||
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> {
|
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> {
|
||||||
verify_v1(&self.common_secret, message, signature)
|
verify_v1(&self.common_secret, message, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn authenticate(&self, message: &[u8]) -> Vec<u8> {
|
||||||
|
hmac_256::<Sha256>(&self.common_secret, message)[..16].to_vec()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SharedSecretV2 {
|
pub struct SharedSecretV2 {
|
||||||
@@ -264,6 +263,11 @@ impl SharedSecret for SharedSecretV2 {
|
|||||||
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> {
|
fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Ctap2StatusCode> {
|
||||||
verify_v2(&self.hmac_key, message, signature)
|
verify_v2(&self.hmac_key, message, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn authenticate(&self, message: &[u8]) -> Vec<u8> {
|
||||||
|
hmac_256::<Sha256>(&self.hmac_key, message).to_vec()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -300,6 +304,14 @@ mod test {
|
|||||||
assert_eq!(shared_secret.decrypt(&ciphertext), Ok(plaintext));
|
assert_eq!(shared_secret.decrypt(&ciphertext), Ok(plaintext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shared_secret_v1_authenticate_verify() {
|
||||||
|
let shared_secret = SharedSecretV1::new([0x55; 32]);
|
||||||
|
let message = [0xAA; 32];
|
||||||
|
let signature = shared_secret.authenticate(&message);
|
||||||
|
assert_eq!(shared_secret.verify(&message, &signature), Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shared_secret_v1_verify() {
|
fn test_shared_secret_v1_verify() {
|
||||||
let shared_secret = SharedSecretV1::new([0x55; 32]);
|
let shared_secret = SharedSecretV1::new([0x55; 32]);
|
||||||
@@ -328,6 +340,14 @@ mod test {
|
|||||||
assert_eq!(shared_secret.decrypt(&ciphertext), Ok(plaintext));
|
assert_eq!(shared_secret.decrypt(&ciphertext), Ok(plaintext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shared_secret_v2_authenticate_verify() {
|
||||||
|
let shared_secret = SharedSecretV2::new([0x55; 32]);
|
||||||
|
let message = [0xAA; 32];
|
||||||
|
let signature = shared_secret.authenticate(&message);
|
||||||
|
assert_eq!(shared_secret.verify(&message, &signature), Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shared_secret_v2_verify() {
|
fn test_shared_secret_v2_verify() {
|
||||||
let shared_secret = SharedSecretV2::new([0x55; 32]);
|
let shared_secret = SharedSecretV2::new([0x55; 32]);
|
||||||
@@ -348,23 +368,12 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_decapsulate_invalid() {
|
|
||||||
let mut rng = ThreadRng256 {};
|
|
||||||
let pin_protocol = PinProtocol::new(&mut rng);
|
|
||||||
let shared_secret = pin_protocol.decapsulate(pin_protocol.get_public_key(), 3);
|
|
||||||
assert_eq!(
|
|
||||||
shared_secret.err(),
|
|
||||||
Some(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_decapsulate_symmetric() {
|
fn test_decapsulate_symmetric() {
|
||||||
let mut rng = ThreadRng256 {};
|
let mut rng = ThreadRng256 {};
|
||||||
let pin_protocol1 = PinProtocol::new(&mut rng);
|
let pin_protocol1 = PinProtocol::new(&mut rng);
|
||||||
let pin_protocol2 = PinProtocol::new(&mut rng);
|
let pin_protocol2 = PinProtocol::new(&mut rng);
|
||||||
for protocol in 1..=2 {
|
for &protocol in &[PinUvAuthProtocol::V1, PinUvAuthProtocol::V2] {
|
||||||
let shared_secret1 = pin_protocol1
|
let shared_secret1 = pin_protocol1
|
||||||
.decapsulate(pin_protocol2.get_public_key(), protocol)
|
.decapsulate(pin_protocol2.get_public_key(), protocol)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -386,19 +395,24 @@ mod test {
|
|||||||
0x49, 0x68,
|
0x49, 0x68,
|
||||||
];
|
];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&token, &message, &signature, 1),
|
verify_pin_uv_auth_token(&token, &message, &signature, PinUvAuthProtocol::V1),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&[0x12; PIN_TOKEN_LENGTH], &message, &signature, 1),
|
verify_pin_uv_auth_token(
|
||||||
|
&[0x12; PIN_TOKEN_LENGTH],
|
||||||
|
&message,
|
||||||
|
&signature,
|
||||||
|
PinUvAuthProtocol::V1
|
||||||
|
),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&token, &[0xBB], &signature, 1),
|
verify_pin_uv_auth_token(&token, &[0xBB], &signature, PinUvAuthProtocol::V1),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&token, &message, &[0x12; 16], 1),
|
verify_pin_uv_auth_token(&token, &message, &[0x12; 16], PinUvAuthProtocol::V1),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -413,31 +427,25 @@ mod test {
|
|||||||
0x36, 0x93, 0xF7, 0x84,
|
0x36, 0x93, 0xF7, 0x84,
|
||||||
];
|
];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&token, &message, &signature, 2),
|
verify_pin_uv_auth_token(&token, &message, &signature, PinUvAuthProtocol::V2),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&[0x12; PIN_TOKEN_LENGTH], &message, &signature, 2),
|
verify_pin_uv_auth_token(
|
||||||
|
&[0x12; PIN_TOKEN_LENGTH],
|
||||||
|
&message,
|
||||||
|
&signature,
|
||||||
|
PinUvAuthProtocol::V2
|
||||||
|
),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&token, &[0xBB], &signature, 2),
|
verify_pin_uv_auth_token(&token, &[0xBB], &signature, PinUvAuthProtocol::V2),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_pin_uv_auth_token(&token, &message, &[0x12; 32], 2),
|
verify_pin_uv_auth_token(&token, &message, &[0x12; 32], PinUvAuthProtocol::V2),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
Err(Ctap2StatusCode::CTAP2_ERR_PIN_AUTH_INVALID)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_verify_pin_uv_auth_token_invalid_protocol() {
|
|
||||||
let token = [0x91; PIN_TOKEN_LENGTH];
|
|
||||||
let message = [0xAA];
|
|
||||||
let signature = [];
|
|
||||||
assert_eq!(
|
|
||||||
verify_pin_uv_auth_token(&token, &message, &signature, 3),
|
|
||||||
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user