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
number of supported residential keys and number of pages in
`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

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))]
pub enum CredentialProtectionPolicy {
UserVerificationOptional = 0x01,

View File

@@ -32,9 +32,10 @@ use self::command::{
#[cfg(feature = "with_ctap2_1")]
use self::data_formats::AuthenticatorTransport;
use self::data_formats::{
ClientPinSubCommand, CoseKey, GetAssertionHmacSecretInput, PackedAttestationStatement,
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialSource,
PublicKeyCredentialType, PublicKeyCredentialUserEntity, SignatureAlgorithm,
ClientPinSubCommand, CoseKey, CredentialProtectionPolicy, GetAssertionHmacSecretInput,
PackedAttestationStatement, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialSource, PublicKeyCredentialType, PublicKeyCredentialUserEntity,
SignatureAlgorithm,
};
use self::hid::ChannelID;
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,
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 {
if pin_auth.len() != PIN_AUTH_LENGTH {
@@ -430,12 +435,19 @@ where
}
let (use_hmac_extension, cred_protect_policy) = if let Some(extensions) = extensions {
(
extensions.has_make_credential_hmac_secret()?,
extensions
.make_credential_cred_protect_policy()
.transpose()?,
)
let mut cred_protect = extensions
.make_credential_cred_protect_policy()
.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 {
(false, None)
};
@@ -812,6 +824,7 @@ where
transports: Some(vec![AuthenticatorTransport::Usb]),
#[cfg(feature = "with_ctap2_1")]
algorithms: Some(vec![ES256_CRED_PARAM]),
default_cred_protect: DEFAULT_CRED_PROTECT,
#[cfg(feature = "with_ctap2_1")]
firmware_version: None,
},
@@ -1116,8 +1129,8 @@ where
#[cfg(test)]
mod test {
use super::data_formats::{
CredentialProtectionPolicy, Extensions, GetAssertionOptions, MakeCredentialOptions,
PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity,
Extensions, GetAssertionOptions, MakeCredentialOptions, PublicKeyCredentialRpEntity,
PublicKeyCredentialUserEntity,
};
use super::*;
use crypto::rng256::ThreadRng256;

View File

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