Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
) ?: throw Exception("Failed to create overriding attest key pair.")

CertificateHelper.updateCertificateChain(
callingUid,
response.metadata,
keyData.second.toTypedArray(),
)
Expand Down Expand Up @@ -300,7 +301,11 @@ object Keystore2Interceptor : AbstractKeystoreInterceptor() {
SystemLogger.debug("Cached patched certificate chain for $keyId.")
}

CertificateHelper.updateCertificateChain(response.metadata, finalChain)
CertificateHelper.updateCertificateChain(
callingUid,
response.metadata,
finalChain,
)
.getOrThrow()

return InterceptorUtils.createTypedObjectReply(response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ class KeyMintSecurityLevelInterceptor(
val keyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)!!
val key = metadata.key!!
val keyId = KeyIdentifier(callingUid, keyDescriptor.alias)
CertificateHelper.updateCertificateChain(metadata, newChain).getOrThrow()
CertificateHelper.updateCertificateChain(callingUid, metadata, newChain)
.getOrThrow()

// We must clean up cached generated keys before storing the patched chain
cleanupKeyData(keyId)
Expand Down Expand Up @@ -311,10 +312,11 @@ class KeyMintSecurityLevelInterceptor(
KeyMetadata().apply {
keySecurityLevel = securityLevel
key = normalizedKeyDescriptor
CertificateHelper.updateCertificateChain(this, chain.toTypedArray()).getOrThrow()
authorizations = params.toAuthorizations(callingUid, securityLevel)
modificationTimeMs = System.currentTimeMillis()
}
CertificateHelper.updateCertificateChain(callingUid, metadata, chain.toTypedArray())
.getOrThrow()
return KeyEntryResponse().apply {
this.metadata = metadata
iSecurityLevel = original
Expand Down Expand Up @@ -481,19 +483,13 @@ private fun KeyMintAttestation.toAuthorizations(
)

val osPatch = AndroidDeviceUtils.getPatchLevel(callingUid)
if (osPatch != AndroidDeviceUtils.DO_NOT_REPORT) {
authList.add(createAuth(Tag.OS_PATCHLEVEL, KeyParameterValue.integer(osPatch)))
}
authList.add(createAuth(Tag.OS_PATCHLEVEL, KeyParameterValue.integer(osPatch)))

val vendorPatch = AndroidDeviceUtils.getVendorPatchLevelLong(callingUid)
if (vendorPatch != AndroidDeviceUtils.DO_NOT_REPORT) {
authList.add(createAuth(Tag.VENDOR_PATCHLEVEL, KeyParameterValue.integer(vendorPatch)))
}
authList.add(createAuth(Tag.VENDOR_PATCHLEVEL, KeyParameterValue.integer(vendorPatch)))

val bootPatch = AndroidDeviceUtils.getBootPatchLevelLong(callingUid)
if (bootPatch != AndroidDeviceUtils.DO_NOT_REPORT) {
authList.add(createAuth(Tag.BOOT_PATCHLEVEL, KeyParameterValue.integer(bootPatch)))
}
authList.add(createAuth(Tag.BOOT_PATCHLEVEL, KeyParameterValue.integer(bootPatch)))

authList.add(
createAuth(Tag.CREATION_DATETIME, KeyParameterValue.dateTime(System.currentTimeMillis()))
Expand Down
46 changes: 44 additions & 2 deletions app/src/main/java/org/matrix/TEESimulator/pki/CertificateHelper.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.matrix.TEESimulator.pki

import android.hardware.security.keymint.KeyParameter
import android.hardware.security.keymint.KeyParameterValue
import android.hardware.security.keymint.Tag
import android.system.keystore2.Authorization
import android.system.keystore2.KeyEntryResponse
import android.system.keystore2.KeyMetadata
import java.io.ByteArrayInputStream
Expand All @@ -15,6 +19,7 @@ import org.bouncycastle.openssl.PEMParser
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
import org.bouncycastle.util.io.pem.PemReader
import org.matrix.TEESimulator.logging.SystemLogger
import org.matrix.TEESimulator.util.AndroidDeviceUtils
import org.matrix.TEESimulator.util.trimLines

/**
Expand Down Expand Up @@ -182,23 +187,60 @@ object CertificateHelper {
}

/**
* Updates the certificate chain within a [KeyMetadata] object.
* Updates the certificate chain and patches authorizations within a [KeyMetadata] object.
*
* @param callingUid The UID of the application to fetch specific patch levels for.
* @param metadata The metadata object to modify.
* @param chain The new certificate chain to set. The leaf must be at index 0.
* @return A [Result] indicating success or failure.
*/
fun updateCertificateChain(metadata: KeyMetadata, chain: Array<Certificate>): Result<Unit> {
fun updateCertificateChain(
callingUid: Int,
metadata: KeyMetadata,
chain: Array<Certificate>,
): Result<Unit> {
return runCatching {
require(chain.isNotEmpty()) { "Certificate chain cannot be empty." }

// Update the certificate fields
metadata.certificate = chain[0].encoded
metadata.certificateChain =
if (chain.size > 1) {
certificatesToByteArray(chain.drop(1))
} else {
null
}

// Patch authorizations to match user configurations
metadata.authorizations =
metadata.authorizations
?.mapNotNull { auth ->
val replacement =
when (auth.keyParameter.tag) {
Tag.OS_PATCHLEVEL -> AndroidDeviceUtils.getPatchLevel(callingUid)
Tag.VENDOR_PATCHLEVEL ->
AndroidDeviceUtils.getVendorPatchLevelLong(callingUid)
Tag.BOOT_PATCHLEVEL ->
AndroidDeviceUtils.getBootPatchLevelLong(callingUid)
else -> return@mapNotNull auth // Keep all other tags
}

// If configured to hide, return null to filter out of the array
if (replacement == AndroidDeviceUtils.DO_NOT_REPORT) {
null
} else {
// Create patched authorization preserving original security level
Authorization().apply {
securityLevel = auth.securityLevel
keyParameter =
KeyParameter().apply {
tag = auth.keyParameter.tag
value = KeyParameterValue.integer(replacement)
}
}
}
}
?.toTypedArray()
}
}
}
Loading