Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use crate::ctap2::commands::client_pin::PinUvAuthTokenPermission;
use crate::ctap2::commands::get_info::AuthenticatorInfo;
use crate::ctap2::commands::get_info::{AuthenticatorInfo, AuthenticatorVersion};
use crate::errors::AuthenticatorError;
use crate::{ctap2::commands::CommandError, transport::errors::HIDError};
use serde::{
Expand Down Expand Up @@ -40,9 +40,18 @@ pub use backend::ecdsa_p256_sha256_sign_raw;

pub struct PinUvAuthProtocol(Box<dyn PinProtocolImpl + Send + Sync>);
impl PinUvAuthProtocol {
pub fn from_id(id: u64) -> Option<Self> {
match id {
1 => Some(Self(Box::new(PinUvAuth1 {}))),
2 => Some(Self(Box::new(PinUvAuth2 {}))),
_ => None,
}
}

pub fn id(&self) -> u64 {
self.0.protocol_id()
}

pub fn encapsulate(&self, peer_cose_key: &COSEKey) -> Result<SharedSecret, CryptoError> {
self.0.encapsulate(peer_cose_key)
}
Expand Down Expand Up @@ -141,28 +150,22 @@ impl TryFrom<&AuthenticatorInfo> for PinUvAuthProtocol {
// has no preference, it SHOULD select the one listed first in
// pinUvAuthProtocols."
if let Some(pin_protocols) = &info.pin_protocols {
for proto_id in pin_protocols.iter() {
match proto_id {
1 => return Ok(PinUvAuthProtocol(Box::new(PinUvAuth1 {}))),
2 => return Ok(PinUvAuthProtocol(Box::new(PinUvAuth2 {}))),
_ => continue,
}
}
pin_protocols
.iter()
.copied()
.find_map(PinUvAuthProtocol::from_id)
.ok_or(CommandError::UnsupportedPinProtocol)
} else {
match info.max_supported_version() {
crate::ctap2::commands::get_info::AuthenticatorVersion::U2F_V2 => {
return Err(CommandError::UnsupportedPinProtocol)
}
crate::ctap2::commands::get_info::AuthenticatorVersion::FIDO_2_0 => {
return Ok(PinUvAuthProtocol(Box::new(PinUvAuth1 {})))
AuthenticatorVersion::U2F_V2 | AuthenticatorVersion::Unknown => {
Err(CommandError::UnsupportedPinProtocol)
}
crate::ctap2::commands::get_info::AuthenticatorVersion::FIDO_2_1_PRE
| crate::ctap2::commands::get_info::AuthenticatorVersion::FIDO_2_1 => {
return Ok(PinUvAuthProtocol(Box::new(PinUvAuth2 {})))
AuthenticatorVersion::FIDO_2_0 => Ok(PinUvAuthProtocol(Box::new(PinUvAuth1 {}))),
AuthenticatorVersion::FIDO_2_1_PRE | AuthenticatorVersion::FIDO_2_1 => {
Ok(PinUvAuthProtocol(Box::new(PinUvAuth2 {})))
}
}
}
Err(CommandError::UnsupportedPinProtocol)
}
}

Expand Down
69 changes: 69 additions & 0 deletions src/ctap2/commands/get_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ pub enum AuthenticatorVersion {
FIDO_2_0,
FIDO_2_1_PRE,
FIDO_2_1,
#[serde(other)]
Unknown,
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
Expand Down Expand Up @@ -742,6 +744,40 @@ pub mod tests {
0x18, 0x18, // unsigned(24)
];

pub const AUTHENTICATOR_INFO_FIDO_2_2: &[u8] = &[
0xa2, // map(2)
0x01, // unsigned(1)
0x83, // array(3)
0x66, // text(6)
0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, // "U2F_V2"
0x68, // text(8)
0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, // "FIDO_2_0"
0x68, // text(8)
0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x32, // "FIDO_2_2"
0x03, // unsigned(3)
0x50, // bytes(16)
0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d, // "\xF8\xA0\u0011\xF3\x8C\nM\u0015\x80\u0006\u0017\u0011\u001F\x9E\xDC}"
];

pub const AUTHENTICATOR_INFO_UNKNOWN_VERSIONS: &[u8] = &[
0xa2, // map(2)
0x01, // unsigned(1)
0x84, // array(4)
0x63, // text(3)
0x66, 0x6f, 0x6f, // "foo"
0x66, // text(6)
0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, // "U2F_V2"
0x68, // text(8)
0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, // "FIDO_2_0"
0x63, // text(3)
0x62, 0x61, 0x72, // "bar"
0x03, // unsigned(3)
0x50, // bytes(16)
0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d, // "\xF8\xA0\u0011\xF3\x8C\nM\u0015\x80\u0006\u0017\u0011\u001F\x9E\xDC}"
];

#[test]
fn parse_authenticator_info() {
let authenticator_info: AuthenticatorInfo =
Expand Down Expand Up @@ -1051,4 +1087,37 @@ pub mod tests {
let authenticator_info: AuthenticatorInfo = from_slice(&raw_list).unwrap();
assert_eq!(authenticator_info, expected);
}

#[test]
fn parse_authenticator_info_fido_2_2() {
assert_eq!(
from_slice::<AuthenticatorInfo>(&AUTHENTICATOR_INFO_FIDO_2_2).unwrap(),
AuthenticatorInfo {
versions: vec![
AuthenticatorVersion::U2F_V2,
AuthenticatorVersion::FIDO_2_0,
AuthenticatorVersion::Unknown,
],
aaguid: AAGuid(AAGUID_RAW),
..Default::default()
},
);
}

#[test]
fn parse_authenticator_info_unknown_versions() {
assert_eq!(
from_slice::<AuthenticatorInfo>(&AUTHENTICATOR_INFO_UNKNOWN_VERSIONS).unwrap(),
AuthenticatorInfo {
versions: vec![
AuthenticatorVersion::Unknown,
AuthenticatorVersion::U2F_V2,
AuthenticatorVersion::FIDO_2_0,
AuthenticatorVersion::Unknown,
],
aaguid: AAGuid(AAGUID_RAW),
..Default::default()
},
);
}
}