diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/AuthorizeCreate.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/AuthorizeCreate.kt index 99ae55a..ec3ad29 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/AuthorizeCreate.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/AuthorizeCreate.kt @@ -1,8 +1,10 @@ package org.matrix.TEESimulator.interception.keystore.shim import android.hardware.security.keymint.Algorithm +import android.hardware.security.keymint.BlockMode import android.hardware.security.keymint.KeyParameter import android.hardware.security.keymint.KeyPurpose +import android.hardware.security.keymint.PaddingMode import android.hardware.security.keymint.Tag import org.matrix.TEESimulator.attestation.KeyMintAttestation @@ -18,6 +20,7 @@ object AuthorizeCreate { // Algorithm-level rejection runs before purpose-list check (AOSP HAL behavior) return checkAlgorithmPurpose(keyParams, purpose) ?: checkPurpose(keyParams, purpose) + ?: checkOperationAuthorizations(keyParams, opParams) ?: checkTemporalValidity(keyParams, purpose) ?: checkCallerNonce(keyParams, purpose, rawOpParams) } @@ -41,6 +44,46 @@ object AuthorizeCreate { return null } + private fun checkOperationAuthorizations( + keyParams: KeyMintAttestation, + opParams: KeyMintAttestation, + ): Int? { + if (opParams.blockMode.any { it !in keyParams.blockMode }) { + return KeystoreErrorCodes.incompatibleBlockMode + } + if (opParams.padding.any { it !in keyParams.padding }) { + return KeystoreErrorCodes.incompatiblePaddingMode + } + if (opParams.digest.any { it !in keyParams.digest }) { + return KeystoreErrorCodes.incompatibleDigest + } + if (opParams.rsaOaepMgfDigest.any { it !in keyParams.rsaOaepMgfDigest }) { + return KeystoreErrorCodes.incompatibleDigest + } + + if (keyParams.algorithm == Algorithm.AES && opParams.blockMode.contains(BlockMode.GCM)) { + val requestedMacLength = opParams.minMacLength + val keyMinMacLength = keyParams.minMacLength + if ( + requestedMacLength != null && + keyMinMacLength != null && + requestedMacLength < keyMinMacLength + ) { + return KeystoreErrorCodes.invalidMacLength + } + } + + if ( + keyParams.algorithm == Algorithm.RSA && + opParams.padding.contains(PaddingMode.RSA_OAEP) && + opParams.digest.isEmpty() + ) { + return KeystoreErrorCodes.incompatibleDigest + } + + return null + } + private fun checkTemporalValidity(keyParams: KeyMintAttestation, purpose: Int): Int? { val now = System.currentTimeMillis() diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt index bf8551c..fe7ec12 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt @@ -501,6 +501,22 @@ internal object KeystoreErrorCodes { resolveField("android.hardware.security.keymint.ErrorCode", "UNKNOWN_ERROR", -1000) } + val incompatibleBlockMode: Int by lazy { + resolveField("android.hardware.security.keymint.ErrorCode", "INCOMPATIBLE_BLOCK_MODE", -8) + } + + val incompatiblePaddingMode: Int by lazy { + resolveField("android.hardware.security.keymint.ErrorCode", "INCOMPATIBLE_PADDING_MODE", -11) + } + + val incompatibleDigest: Int by lazy { + resolveField("android.hardware.security.keymint.ErrorCode", "INCOMPATIBLE_DIGEST", -13) + } + + val invalidMacLength: Int by lazy { + resolveField("android.hardware.security.keymint.ErrorCode", "INVALID_MAC_LENGTH", -57) + } + fun resolveField(className: String, fieldName: String, fallback: Int): Int = runCatching { Class.forName(className).getField(fieldName).getInt(null) } .getOrElse {