introduces a default level for credProtect

This commit is contained in:
Fabian Kaczmarczyck
2020-05-13 18:49:35 +02:00
parent 43d77fd106
commit 8d737b3c80
4 changed files with 37 additions and 13 deletions

View File

@@ -99,6 +99,9 @@ a few things you can personalize:
4. Depending on your available flash storage, choose an appropriate maximum 4. Depending on your available flash storage, choose an appropriate maximum
number of supported residential keys and number of pages in number of supported residential keys and number of pages in
`ctap/storage.rs`. `ctap/storage.rs`.
5. Change the default level for the credProtect extension. Resident credentials
become undiscoverable without user verification. This helps privacy, but
can make usage less comfortable for less important credentials.
### 3D printed enclosure ### 3D printed enclosure

View File

@@ -440,7 +440,7 @@ impl TryFrom<&cbor::Value> for SignatureAlgorithm {
} }
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq, PartialOrd)]
#[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug))] #[cfg_attr(any(test, feature = "debug_ctap"), derive(Debug))]
pub enum CredentialProtectionPolicy { pub enum CredentialProtectionPolicy {
UserVerificationOptional = 0x01, UserVerificationOptional = 0x01,

View File

@@ -32,9 +32,10 @@ use self::command::{
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
use self::data_formats::AuthenticatorTransport; use self::data_formats::AuthenticatorTransport;
use self::data_formats::{ use self::data_formats::{
ClientPinSubCommand, CoseKey, GetAssertionHmacSecretInput, PackedAttestationStatement, ClientPinSubCommand, CoseKey, CredentialProtectionPolicy, GetAssertionHmacSecretInput,
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialSource, PackedAttestationStatement, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialType, PublicKeyCredentialUserEntity, SignatureAlgorithm, PublicKeyCredentialSource, PublicKeyCredentialType, PublicKeyCredentialUserEntity,
SignatureAlgorithm,
}; };
use self::hid::ChannelID; use self::hid::ChannelID;
use self::key_material::{AAGUID, ATTESTATION_CERTIFICATE, ATTESTATION_PRIVATE_KEY}; use self::key_material::{AAGUID, ATTESTATION_CERTIFICATE, ATTESTATION_PRIVATE_KEY};
@@ -109,6 +110,10 @@ pub const ES256_CRED_PARAM: PublicKeyCredentialParameter = PublicKeyCredentialPa
cred_type: PublicKeyCredentialType::PublicKey, cred_type: PublicKeyCredentialType::PublicKey,
alg: SignatureAlgorithm::ES256, alg: SignatureAlgorithm::ES256,
}; };
// You can change this value to one of the following for more privacy.
// - Some(CredentialProtectionPolicy::UserVerificationOptionalWithCredentialIdList)
// - Some(CredentialProtectionPolicy::UserVerificationRequired)
const DEFAULT_CRED_PROTECT: Option<CredentialProtectionPolicy> = None;
fn check_pin_auth(hmac_key: &[u8], hmac_contents: &[u8], pin_auth: &[u8]) -> bool { fn check_pin_auth(hmac_key: &[u8], hmac_contents: &[u8], pin_auth: &[u8]) -> bool {
if pin_auth.len() != PIN_AUTH_LENGTH { if pin_auth.len() != PIN_AUTH_LENGTH {
@@ -430,12 +435,19 @@ where
} }
let (use_hmac_extension, cred_protect_policy) = if let Some(extensions) = extensions { let (use_hmac_extension, cred_protect_policy) = if let Some(extensions) = extensions {
( let mut cred_protect = extensions
extensions.has_make_credential_hmac_secret()?,
extensions
.make_credential_cred_protect_policy() .make_credential_cred_protect_policy()
.transpose()?, .transpose()?;
) if cred_protect
.as_ref()
.unwrap_or(&CredentialProtectionPolicy::UserVerificationOptional)
> DEFAULT_CRED_PROTECT
.as_ref()
.unwrap_or(&CredentialProtectionPolicy::UserVerificationOptional)
{
cred_protect = DEFAULT_CRED_PROTECT;
}
(extensions.has_make_credential_hmac_secret()?, cred_protect)
} else { } else {
(false, None) (false, None)
}; };
@@ -812,6 +824,7 @@ where
transports: Some(vec![AuthenticatorTransport::Usb]), transports: Some(vec![AuthenticatorTransport::Usb]),
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
algorithms: Some(vec![ES256_CRED_PARAM]), algorithms: Some(vec![ES256_CRED_PARAM]),
default_cred_protect: DEFAULT_CRED_PROTECT,
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
firmware_version: None, firmware_version: None,
}, },
@@ -1116,8 +1129,8 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::data_formats::{ use super::data_formats::{
CredentialProtectionPolicy, Extensions, GetAssertionOptions, MakeCredentialOptions, Extensions, GetAssertionOptions, MakeCredentialOptions, PublicKeyCredentialRpEntity,
PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, PublicKeyCredentialUserEntity,
}; };
use super::*; use super::*;
use crypto::rng256::ThreadRng256; use crypto::rng256::ThreadRng256;

View File

@@ -15,7 +15,7 @@
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
use super::data_formats::{AuthenticatorTransport, PublicKeyCredentialParameter}; use super::data_formats::{AuthenticatorTransport, PublicKeyCredentialParameter};
use super::data_formats::{ use super::data_formats::{
CoseKey, PackedAttestationStatement, PublicKeyCredentialDescriptor, CoseKey, CredentialProtectionPolicy, PackedAttestationStatement, PublicKeyCredentialDescriptor,
PublicKeyCredentialUserEntity, PublicKeyCredentialUserEntity,
}; };
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
@@ -119,6 +119,7 @@ pub struct AuthenticatorGetInfoResponse {
pub transports: Option<Vec<AuthenticatorTransport>>, pub transports: Option<Vec<AuthenticatorTransport>>,
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
pub algorithms: Option<Vec<PublicKeyCredentialParameter>>, pub algorithms: Option<Vec<PublicKeyCredentialParameter>>,
pub default_cred_protect: Option<CredentialProtectionPolicy>,
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
pub firmware_version: Option<u64>, pub firmware_version: Option<u64>,
} }
@@ -137,6 +138,7 @@ impl From<AuthenticatorGetInfoResponse> for cbor::Value {
max_credential_id_length, max_credential_id_length,
transports, transports,
algorithms, algorithms,
default_cred_protect,
firmware_version, firmware_version,
} = get_info_response; } = get_info_response;
@@ -159,6 +161,7 @@ impl From<AuthenticatorGetInfoResponse> for cbor::Value {
0x08 => max_credential_id_length, 0x08 => max_credential_id_length,
0x09 => transports.map(|vec| cbor_array_vec!(vec)), 0x09 => transports.map(|vec| cbor_array_vec!(vec)),
0x0A => algorithms.map(|vec| cbor_array_vec!(vec)), 0x0A => algorithms.map(|vec| cbor_array_vec!(vec)),
0x0C => default_cred_protect.map(|p| p as u64),
0x0E => firmware_version, 0x0E => firmware_version,
} }
} }
@@ -172,6 +175,7 @@ impl From<AuthenticatorGetInfoResponse> for cbor::Value {
options, options,
max_msg_size, max_msg_size,
pin_protocols, pin_protocols,
default_cred_protect,
} = get_info_response; } = get_info_response;
let options_cbor: Option<cbor::Value> = options.map(|options| { let options_cbor: Option<cbor::Value> = options.map(|options| {
@@ -189,6 +193,7 @@ impl From<AuthenticatorGetInfoResponse> for cbor::Value {
0x04 => options_cbor, 0x04 => options_cbor,
0x05 => max_msg_size, 0x05 => max_msg_size,
0x06 => pin_protocols.map(|vec| cbor_array_vec!(vec)), 0x06 => pin_protocols.map(|vec| cbor_array_vec!(vec)),
0x0C => default_cred_protect.map(|p| p as u64),
} }
} }
} }
@@ -290,6 +295,7 @@ mod test {
transports: None, transports: None,
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
algorithms: None, algorithms: None,
default_cred_protect: None,
#[cfg(feature = "with_ctap2_1")] #[cfg(feature = "with_ctap2_1")]
firmware_version: None, firmware_version: None,
}; };
@@ -318,6 +324,7 @@ mod test {
max_credential_id_length: Some(256), max_credential_id_length: Some(256),
transports: Some(vec![AuthenticatorTransport::Usb]), transports: Some(vec![AuthenticatorTransport::Usb]),
algorithms: Some(vec![ES256_CRED_PARAM]), algorithms: Some(vec![ES256_CRED_PARAM]),
default_cred_protect: Some(CredentialProtectionPolicy::UserVerificationRequired),
firmware_version: Some(0), firmware_version: Some(0),
}; };
let response_cbor: Option<cbor::Value> = let response_cbor: Option<cbor::Value> =
@@ -333,6 +340,7 @@ mod test {
0x08 => 256, 0x08 => 256,
0x09 => cbor_array_vec![vec!["usb"]], 0x09 => cbor_array_vec![vec!["usb"]],
0x0A => cbor_array_vec![vec![ES256_CRED_PARAM]], 0x0A => cbor_array_vec![vec![ES256_CRED_PARAM]],
0x0C => CredentialProtectionPolicy::UserVerificationRequired as u64,
0x0E => 0, 0x0E => 0,
}; };
assert_eq!(response_cbor, Some(expected_cbor)); assert_eq!(response_cbor, Some(expected_cbor));