From a0ee77202c35dc784442f68eb14bf20b8144a872 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Tue, 10 Mar 2026 14:23:33 +0100 Subject: [PATCH] fix(attestation): correct leaf CN casing and enforce keystore2 parameter policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leaf cert Subject CN used "KeyStore" (capital S) but AOSP KeyGenParameterSpec uses "Keystore" (lowercase s). Fixed in both the Rust native certgen and BouncyCastle paths. Replicate keystore2's security_level.rs parameter validation for software-generated keys: reject CREATION_DATETIME (output-only tag, ResponseCode 20) and device ID attestation tags (CANNOT_ATTEST_IDS -66) that real keystore2 blocks before they reach the HAL. Also fix createErrorReply parcel write order — AIDL protocol expects exception_code, message, error_code but we had message and error_code swapped, causing malformed replies for positive error codes. --- .../interception/keystore/InterceptorUtils.kt | 2 +- .../shim/KeyMintSecurityLevelInterceptor.kt | 14 ++++++++++++++ .../TEESimulator/pki/CertificateGenerator.kt | 2 +- native-certgen/src/certbuilder.rs | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/InterceptorUtils.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/InterceptorUtils.kt index d187f1e..bbfaeb4 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/InterceptorUtils.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/InterceptorUtils.kt @@ -17,8 +17,8 @@ object InterceptorUtils { fun createErrorReply(errorCode: Int): BinderInterceptor.TransactionResult.OverrideReply { val parcel = Parcel.obtain().apply { writeInt(EX_SERVICE_SPECIFIC) - writeInt(errorCode) writeString(null) + writeInt(errorCode) } return BinderInterceptor.TransactionResult.OverrideReply(parcel) } diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt index 30fe8e6..aadcad8 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt @@ -254,6 +254,18 @@ class KeyMintSecurityLevelInterceptor( return InterceptorUtils.createErrorReply(KEYMINT_INVALID_INPUT_LENGTH) } + if (params.any { it.tag == Tag.CREATION_DATETIME }) { + SystemLogger.warning("[TX_ID: $txId] Rejecting CREATION_DATETIME in generateKey params") + return InterceptorUtils.createErrorReply(RESPONSE_INVALID_ARGUMENT) + } + + if (parsedParams.serial != null || parsedParams.imei != null || + parsedParams.meid != null || parsedParams.secondImei != null || + params.any { it.tag == Tag.DEVICE_UNIQUE_ATTESTATION }) { + SystemLogger.warning("[TX_ID: $txId] Rejecting device ID attestation for uid=$callingUid") + return InterceptorUtils.createErrorReply(KEYMINT_CANNOT_ATTEST_IDS) + } + val keyId = KeyIdentifier(callingUid, keyDescriptor.alias) val isAttestKeyRequest = parsedParams.isAttestKey() @@ -515,6 +527,8 @@ class KeyMintSecurityLevelInterceptor( // Binder buffer is ~1MB; 256KB provides 4x safety margin for transaction overhead private const val MAX_ALIAS_LENGTH = 256 * 1024 private const val KEYMINT_INVALID_INPUT_LENGTH = -21 + private const val RESPONSE_INVALID_ARGUMENT = 20 + private const val KEYMINT_CANNOT_ATTEST_IDS = -66 private const val MAX_CONCURRENT_HW_KEYGEN_PER_UID = 2 // Sliding window: max hardware keygen permits per UID within the burst window private const val MAX_HW_KEYGEN_PER_WINDOW = 2 diff --git a/app/src/main/java/org/matrix/TEESimulator/pki/CertificateGenerator.kt b/app/src/main/java/org/matrix/TEESimulator/pki/CertificateGenerator.kt index a5b3517..63c4c70 100644 --- a/app/src/main/java/org/matrix/TEESimulator/pki/CertificateGenerator.kt +++ b/app/src/main/java/org/matrix/TEESimulator/pki/CertificateGenerator.kt @@ -213,7 +213,7 @@ object CertificateGenerator { uid: Int, securityLevel: Int, ): Certificate { - val subject = params.certificateSubject ?: X500Name("CN=Android KeyStore Key") + val subject = params.certificateSubject ?: X500Name("CN=Android Keystore Key") val leafNotAfter = (signingKeyPair.public as? X509Certificate)?.notAfter ?: Date(System.currentTimeMillis() + 31536000000L) diff --git a/native-certgen/src/certbuilder.rs b/native-certgen/src/certbuilder.rs index 77d87a8..d87b7a2 100644 --- a/native-certgen/src/certbuilder.rs +++ b/native-certgen/src/certbuilder.rs @@ -51,7 +51,7 @@ fn build_leaf_cert( let subject_dn_der = if let Some(ref subject) = params.cert_subject { subject.clone() } else { - encode_simple_cn_dn("Android KeyStore Key") + encode_simple_cn_dn("Android Keystore Key") }; // Validity