fix(keymint): enforce operation authorizations
Add checkOperationAuthorizations to the AuthorizeCreate chain so the interceptor rejects operations whose parameters are incompatible with the key, matching real KeyMint HAL behavior: - block mode, padding, digest, and RSA-OAEP MGF digest must each be a subset of the key's authorized set; - AES-GCM rejects a requested MAC length below the key minimum; - RSA-OAEP requires a digest. Add the four backing KeyMint error codes (INCOMPATIBLE_BLOCK_MODE, INCOMPATIBLE_PADDING_MODE, INCOMPATIBLE_DIGEST, INVALID_MAC_LENGTH) to KeystoreErrorCodes, resolved at runtime with AOSP-correct fallbacks. The check reads the raw request params (AuthorizeCreate.check is called with parsedParams), so no op-param construction change is needed, and execution is unaffected: our SoftwareOperation already runs GCM (128-bit tag) and OAEP.
This commit is contained in:
+43
@@ -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()
|
||||
|
||||
|
||||
+16
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user