WearAuthn implements a comprehensive security model designed to protect user credentials and maintain the integrity of the FIDO2/WebAuthn authentication process. This document outlines the security architecture, threat model, and security controls implemented in the system.
-
Private Cryptographic Keys
- EC P-256 private keys for WebAuthn credentials
- HMAC secret keys for extensions
- Master signing keys for credential integrity
-
User Credentials and Metadata
- User identifiers and display names
- Relying Party information
- Credential creation timestamps
-
Authentication Decisions
- User presence verification
- User verification status
- Authentication assertions
-
User Privacy Information
- Credential usage patterns
- Relying Party associations
- Biometric templates (handled by system)
-
Malicious Applications
- Other apps on the same device
- Privilege escalation attempts
- Data extraction via shared storage
-
Network Attackers
- Man-in-the-middle attacks
- Replay attacks
- Protocol downgrade attempts
-
Physical Device Access
- Unauthorized device access
- Hardware tampering
- Side-channel attacks
-
Compromised Transport Channels
- Bluetooth interception
- NFC eavesdropping
- Protocol manipulation
-
Key Extraction
- Memory dumps
- Debug interfaces
- Hardware attacks
-
Credential Enumeration
- Storage analysis
- Timing attacks
- Metadata leakage
-
Authentication Bypass
- Biometric spoofing
- PIN/password attacks
- Social engineering
-
Protocol Attacks
- Replay attacks
- Downgrade attacks
- Extension manipulation
// Secure key generation with hardware backing
val keyGenParameterSpec = KeyGenParameterSpec.Builder(
keyAlias,
KeyProperties.PURPOSE_SIGN
)
.setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
.setDigests(KeyProperties.DIGEST_SHA256)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(validityDuration)
.setAttestationChallenge(attestationChallenge)
.build()Security Properties:
- Hardware-backed key storage (when available)
- Keys never leave secure hardware
- User authentication enforcement
- Hardware attestation support
TrustZone Integration:
- Secure key operations in TEE
- Isolated execution environment
- Hardware-enforced security boundaries
- Secure boot verification
Secure Element (SE) Support:
- NFC-based secure element access
- Hardware security module integration
- Tamper-resistant key storage
- Certified security evaluation
// User verification implementation
suspend fun verifyUser(): Boolean {
return when {
biometricManager.canAuthenticate(BIOMETRIC_WEAK) == BIOMETRIC_SUCCESS -> {
performBiometricAuthentication()
}
keyguardManager.isDeviceSecure -> {
performDeviceCredentialAuthentication()
}
else -> false
}
}Authentication Methods:
-
Biometric Authentication
- Fingerprint recognition
- Face recognition
- Voice recognition (where supported)
-
Device Credentials
- PIN verification
- Password authentication
- Pattern unlock
-
Hardware Tokens
- Secure element authentication
- Hardware security keys
- Smart card integration
Implementation:
- Physical user interaction required
- Timeout-based presence checking
- Anti-automation measures
- Gesture-based confirmation
Key Generation:
fun generateWebAuthnCredential(
createResidentKey: Boolean,
createHmacSecret: Boolean,
attestationChallenge: ByteArray?
): String? {
val keyAlias = SecureRandom.getInstanceStrong().nextBytes(32).base64()
// Generate EC P-256 key pair
val keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC,
"AndroidKeyStore"
)
keyPairGenerator.initialize(keyGenParameterSpec)
val keyPair = keyPairGenerator.generateKeyPair()
return keyAlias
}Key Properties:
- Algorithm: ECDSA with P-256 curve
- Key Size: 256 bits
- Storage: Android Keystore (hardware-backed)
- Usage: Digital signatures only
- Lifecycle: Tied to user authentication
WebAuthn Assertion:
suspend fun assertWebAuthn(
clientDataHash: ByteArray,
userVerified: Boolean
): ByteArray {
val authenticatorData = buildAuthenticatorData(userVerified)
val signatureData = authenticatorData + clientDataHash
val signature = signWithKey(keyAlias, signatureData)
return buildAssertionResponse(authenticatorData, signature)
}Security Properties:
- Non-repudiation through digital signatures
- Integrity protection of authentication data
- Replay protection via challenge-response
- Cryptographic binding to relying party
Credential Serialization:
fun serialize(userVerified: Boolean): String {
val userMap = if (userVerified) {
encryptUserInfo(userDisplayName, userName, userIcon)
} else {
null
}
val credentialData = CborMap(mapOf(
"keyAlias" to CborTextString(keyAlias),
"userId" to CborByteString(userId),
"userMap" to userMap
))
return credentialData.toCbor().base64()
}Encryption Details:
- Algorithm: AES-256-GCM
- Key Derivation: PBKDF2 with hardware-backed key
- Authentication: AEAD for integrity protection
- IV Generation: Cryptographically secure random
CTAP 2.1 Implementation:
- Full protocol compliance
- Extension support validation
- Error handling standardization
- Backward compatibility
Security Features:
- Challenge-response authentication
- Origin validation
- Credential isolation per RP
- User verification enforcement
Bluetooth HID Security:
class SecureHidTransport : HidDeviceApp() {
override fun sendData(data: ByteArray) {
// Validate data integrity
require(data.size <= MAX_HID_PACKET_SIZE)
// Send via encrypted Bluetooth channel
bluetoothDevice.sendEncryptedData(data)
}
}NFC Security:
- ISO 14443-4 secure communication
- Secure channel establishment
- Anti-collision protocols
- Proximity verification
Credential Storage:
private fun storeCredential(credential: WebAuthnCredential) {
val encryptedData = encryptWithUserInfoKey(credential.serialize(true))
val rpIdHash = credential.rpIdHash.base64()
val userId = credential.userId.base64()
getSecurePreferences(rpIdHash).edit {
putString("cred_$userId", encryptedData)
}
}Storage Properties:
- Encrypted SharedPreferences
- Per-RP isolation
- User-specific encryption keys
- Secure key derivation
Data Minimization:
- Only necessary data stored
- Automatic data expiration
- User-controlled data deletion
- Minimal metadata collection
Anonymization:
- RP ID hashing for storage keys
- User ID encryption
- No cross-RP correlation
- Privacy-preserving design
Code Protection:
// Obfuscation and anti-tampering
@Keep
class SecurityManager {
@JvmStatic
external fun validateIntegrity(): Boolean
companion object {
init {
System.loadLibrary("security")
}
}
}Runtime Checks:
- Application signature verification
- Debug detection
- Root detection
- Emulator detection
Secure Memory Handling:
class SecureByteArray(size: Int) : AutoCloseable {
private val data = ByteArray(size)
fun get(): ByteArray = data.clone()
override fun close() {
data.fill(0) // Clear sensitive data
}
}Memory Security:
- Sensitive data clearing
- Stack protection
- Heap randomization
- Memory encryption (where available)
<!-- Minimal permissions required -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" /><!-- Exported components with proper protection -->
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:permission="android.permission.BIND_DEVICE_ADMIN" />fun validateCtapRequest(request: ByteArray): Boolean {
// Size validation
if (request.size > MAX_CTAP_REQUEST_SIZE) return false
// Format validation
if (!isValidCborFormat(request)) return false
// Command validation
val command = request.firstOrNull()
if (!VALID_COMMANDS.contains(command)) return false
return true
}fun sanitizeRpId(rpId: String): String {
require(rpId.isNotBlank()) { "RP ID cannot be blank" }
require(rpId.length <= MAX_RP_ID_LENGTH) { "RP ID too long" }
require(rpId.matches(RP_ID_REGEX)) { "Invalid RP ID format" }
return rpId.lowercase().trim()
}fun handleError(error: Exception): ByteArray {
val ctapError = when (error) {
is SecurityException -> CtapError.OperationDenied
is IllegalArgumentException -> CtapError.InvalidParameter
is TimeoutException -> CtapError.UserActionTimeout
else -> CtapError.Other
}
// Log error without sensitive information
Timber.w("CTAP error: ${ctapError.name}")
return ctapError.toResponse()
}- Generic error messages
- No stack traces in production
- Minimal error information
- Consistent error timing
object SecurityAudit {
fun logAuthenticationAttempt(rpId: String, success: Boolean) {
val event = SecurityEvent(
type = "authentication",
rpId = rpId.sha256().take(8), // Anonymized
success = success,
timestamp = System.currentTimeMillis()
)
secureLog(event)
}
}- Unusual authentication patterns
- Rapid credential creation
- Suspicious transport usage
- Error rate monitoring
- Key extraction attempts
- Protocol manipulation
- Transport interception
- Authentication bypass
- Static code analysis
- Dynamic analysis
- Fuzzing testing
- Side-channel analysis
- FIDO2 conformance tests
- Security evaluation criteria
- Interoperability testing
- Vulnerability assessment
- Common Criteria evaluation
- FIPS 140-2 validation
- WebAuthn specification compliance
- CTAP 2.1 certification
# Security checks in CI/CD
security_scan:
- static_analysis
- dependency_check
- secret_detection
- vulnerability_scan- Quarterly security reviews
- Annual penetration testing
- Continuous monitoring
- Incident response procedures
- Input validation everywhere
- Fail-secure defaults
- Principle of least privilege
- Defense in depth
- Security-focused reviews
- Cryptographic implementation review
- Protocol compliance verification
- Threat model validation
- Code signing verification
- Integrity checking
- Secure distribution
- Update mechanisms
- Application hardening
- Anti-tampering measures
- Runtime application self-protection
- Secure configuration
- Detection: Automated monitoring and alerting
- Analysis: Threat assessment and impact evaluation
- Containment: Immediate threat mitigation
- Recovery: System restoration and validation
- Lessons Learned: Process improvement and prevention
- User notification procedures
- Vendor coordination
- Regulatory reporting
- Public disclosure guidelines
This security documentation provides a comprehensive overview of the security measures implemented in WearAuthn. Regular updates and reviews ensure that the security posture remains strong against evolving threats.