dummy implementation for enterprise attestation

This commit is contained in:
Fabian Kaczmarczyck
2021-02-04 21:26:00 +01:00
parent b32d92d9e2
commit 44b7c3cdc1
7 changed files with 171 additions and 13 deletions

View File

@@ -36,10 +36,10 @@ use self::command::{
use self::config_command::process_config;
use self::credential_management::process_credential_management;
use self::data_formats::{
AuthenticatorTransport, CoseKey, CredentialProtectionPolicy, GetAssertionExtensions,
PackedAttestationStatement, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialSource, PublicKeyCredentialType, PublicKeyCredentialUserEntity,
SignatureAlgorithm,
AuthenticatorTransport, CoseKey, CredentialProtectionPolicy, EnterpriseAttestationMode,
GetAssertionExtensions, PackedAttestationStatement, PublicKeyCredentialDescriptor,
PublicKeyCredentialParameter, PublicKeyCredentialSource, PublicKeyCredentialType,
PublicKeyCredentialUserEntity, SignatureAlgorithm,
};
use self::hid::ChannelID;
use self::large_blobs::{LargeBlobs, MAX_MSG_SIZE};
@@ -61,6 +61,7 @@ use alloc::vec::Vec;
use arrayref::array_ref;
use byteorder::{BigEndian, ByteOrder};
use cbor::cbor_map_options;
use core::convert::TryFrom;
#[cfg(feature = "debug_ctap")]
use core::fmt::Write;
use crypto::cbc::{cbc_decrypt, cbc_encrypt};
@@ -86,6 +87,18 @@ const USE_BATCH_ATTESTATION: bool = false;
// solution is a compromise to be compatible with U2F and not wasting storage.
const USE_SIGNATURE_COUNTER: bool = true;
pub const INITIAL_SIGNATURE_COUNTER: u32 = 1;
// This flag allows usage of enterprise attestation. For privacy reasons, it is
// disabled by default. You can choose between
// - EnterpriseAttestationMode::VendorFacilitated,
// - EnterpriseAttestationMode::PlatformManaged.
// For VendorFacilitated, choose an appriopriate ENTERPRISE_RP_ID_LIST.
// To enable the feature, send the subcommand enableEnterpriseAttestation in
// AuthenticatorConfig. An enterprise might want to customize the type of
// attestation that is used. OpenSK defaults to batch attestation. Configuring
// individual certificates then makes authenticators identifiable. Do NOT set
// USE_BATCH_ATTESTATION to true at the same time in this case!
pub const ENTERPRISE_ATTESTATION_MODE: Option<EnterpriseAttestationMode> = None;
const ENTERPRISE_RP_ID_LIST: Vec<String> = Vec::new();
// Our credential ID consists of
// - 16 byte initialization vector for AES-256,
// - 32 byte ECDSA private key for the credential,
@@ -562,7 +575,7 @@ where
options,
pin_uv_auth_param,
pin_uv_auth_protocol,
enterprise_attestation: _,
enterprise_attestation,
} = make_credential_params;
self.pin_uv_auth_precheck(&pin_uv_auth_param, pin_uv_auth_protocol, cid)?;
@@ -572,6 +585,26 @@ where
}
let rp_id = rp.rp_id;
let ep_att = if let Some(enterprise_attestation) = enterprise_attestation {
let authenticator_mode =
ENTERPRISE_ATTESTATION_MODE.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
if !self.persistent_store.enterprise_attestation()? {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
match (
EnterpriseAttestationMode::try_from(enterprise_attestation)?,
authenticator_mode,
) {
(
EnterpriseAttestationMode::PlatformManaged,
EnterpriseAttestationMode::PlatformManaged,
) => ENTERPRISE_RP_ID_LIST.contains(&rp_id),
_ => true,
}
} else {
false
};
let mut cred_protect_policy = extensions.cred_protect;
if cred_protect_policy.unwrap_or(CredentialProtectionPolicy::UserVerificationOptional)
< DEFAULT_CRED_PROTECT.unwrap_or(CredentialProtectionPolicy::UserVerificationOptional)
@@ -723,7 +756,7 @@ where
let mut signature_data = auth_data.clone();
signature_data.extend(client_data_hash);
let (signature, x5c) = if USE_BATCH_ATTESTATION {
let (signature, x5c) = if USE_BATCH_ATTESTATION || ep_att {
let attestation_private_key = self
.persistent_store
.attestation_private_key()?
@@ -750,11 +783,13 @@ where
x5c,
ecdaa_key_id: None,
};
let ep_att = if ep_att { Some(true) } else { None };
Ok(ResponseData::AuthenticatorMakeCredential(
AuthenticatorMakeCredentialResponse {
fmt: String::from("packed"),
auth_data,
att_stmt: attestation_statement,
ep_att,
large_blob_key,
},
))
@@ -1026,6 +1061,12 @@ where
options_map.insert(String::from("up"), true);
options_map.insert(String::from("pinUvAuthToken"), true);
options_map.insert(String::from("largeBlobs"), true);
if ENTERPRISE_ATTESTATION_MODE.is_some() {
options_map.insert(
String::from("ep"),
self.persistent_store.enterprise_attestation()?,
);
}
options_map.insert(String::from("authnrCfg"), true);
options_map.insert(String::from("credMgmt"), true);
options_map.insert(String::from("setMinPINLength"), true);
@@ -1227,6 +1268,7 @@ mod test {
fmt,
auth_data,
att_stmt,
ep_att,
large_blob_key,
} = make_credential_response;
// The expected response is split to only assert the non-random parts.
@@ -1247,6 +1289,7 @@ mod test {
&auth_data[auth_data.len() - expected_extension_cbor.len()..auth_data.len()],
expected_extension_cbor
);
assert!(ep_att.is_none());
assert_eq!(att_stmt.alg, SignatureAlgorithm::ES256 as i64);
assert_eq!(large_blob_key, None);
}
@@ -1276,12 +1319,13 @@ mod test {
String::from("largeBlobKey"),
]],
0x03 => ctap_state.persistent_store.aaguid().unwrap(),
0x04 => cbor_map! {
0x04 => cbor_map_options! {
"rk" => true,
"clientPin" => false,
"up" => true,
"pinUvAuthToken" => true,
"largeBlobs" => true,
"ep" => ENTERPRISE_ATTESTATION_MODE.map(|_| false),
"authnrCfg" => true,
"credMgmt" => true,
"setMinPINLength" => true,