How to tell if keys are hardware backed?

房东的猫 提交于 2019-12-11 17:34:28

问题


I need to tell if my keys created are in the hardware backed AndroidKeyStore(TEE or SE) or the software backed implementation.

I understand that for api < 23 I should be using KeyChain.isBoundKeyAlgorithm(algorithm) and for api >= 23 I should use keyInfo.isInsideSecureHardware.

However, I have a Nexus 6, Android 7.1.1 api level 25. I created a keypair in AndroidKeyStore and when I call keyInfo.isInsideSecureHardware, it returns false but when i try calling KeyChain.isBoundKeyAlgorithm(algorithm), it returns true.

So my question is, is the keypair inside the hardware backed keystore(TEE/SE) or not?

Here is my function to check if the key is inside hardware back keystore or not

fun checkKeyInHardware(): Boolean {

            val key = androidKeyStore.getKey(AUTH_ALIAS, null) as PrivateKey
            val algorithm = key.algorithm

            Log.d("checkKeyInHardware", "Key algo = $algorithm")
            Log.d("checkKeyInHardware", "KeyChain.isBoundKeyAlgorithm(algorithm) = ${KeyChain.isBoundKeyAlgorithm(algorithm)}")

            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val factory = KeyFactory.getInstance(algorithm, androidKeyStoreProvider)
                val keyInfo =
                        try {
                            factory.getKeySpec(key, KeyInfo::class.java)
                        } catch (e: InvalidKeySpecException) {
                            Log.d("checkKeyInHardware", "not in AndroidKeyStore")
                            null
                        }

                return if(keyInfo == null) {
                    Log.d("checkKeyInHardware", "keyinfo is null")
                    false
                }
                else {
                    Log.d("checkKeyInHardware", "keyInfo.isInsideSecureHardware = ${keyInfo.isInsideSecureHardware}")
                    keyInfo.isInsideSecureHardware || KeyChain.isBoundKeyAlgorithm(algorithm)
                }

            } else {
                KeyChain.isBoundKeyAlgorithm(algorithm)
            }

        }

and here is how i generate my key pairs

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                val originationEnd = Date(start.time + ORIGINATION_TIME_OFFSET)
                val consumptionEnd = Date(end.time + CONSUMPTION_TIME_OFFSET)

                val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, androidKeyStoreProvider)

                val paramSpecBuilder: KeyGenParameterSpec.Builder = KeyGenParameterSpec
                        .Builder(AUTH_ALIAS, KeyProperties.PURPOSE_SIGN)

                paramSpecBuilder.apply {
                    setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512)
                    setAlgorithmParameterSpec(ecGenParameterSpec)
                    setCertificateNotBefore(start)
                    setCertificateNotAfter(end)
                    setKeyValidityStart(start)
                    setKeyValidityEnd(end)
                    setKeyValidityForOriginationEnd(originationEnd)
                    setKeyValidityForConsumptionEnd(consumptionEnd)
                    setCertificateSubject(subjectPrincipal)
                    setUserAuthenticationRequired(false)
                    setCertificateSerialNumber(serialNumber)

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        setAttestationChallenge(challenge)
                }

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    val paramSpec = paramSpecBuilder.setIsStrongBoxBacked(true).build()
                    kpg.initialize(paramSpec)

                    try {
                        generateKeyCatcher { kpg.generateKeyPair() }
                    } catch (e: StrongBoxUnavailableException) {
                        val weakBoxParamSpec = paramSpecBuilder.setIsStrongBoxBacked(false).build()
                        kpg.initialize(weakBoxParamSpec)
                        generateKeyCatcher { kpg.generateKeyPair() }
                    }
                } else {
                    val paramSpec = paramSpecBuilder.build()
                    Log.d("GenerateKey", "PROVIDER = ${kpg.provider.name}")
                    kpg.initialize(paramSpec)
                    generateKeyCatcher { kpg.generateKeyPair() }
                }

            }
            else {

                rearrangeSecurityProviders()

                val kpg = KeyPairGenerator.getInstance("RSA", androidKeyStoreProvider)

                val spec = KeyPairGeneratorSpec.Builder(context).run {
                    setAlias(AUTH_ALIAS)
                    setSubject(subjectPrincipal)
                    setSerialNumber(BigInteger.ONE)
                    setKeyType("EC")
                    setKeySize(256)
                    setAlgorithmParameterSpec(ecGenParameterSpec)
                    setStartDate(start)
                    setEndDate(end)
                    build()
                }

                Log.d("GenerateKey", "PROVIDER = ${kpg.provider.name}")
                Log.d("GenerateKey", "PROVIDER = ${kpg.provider}")
                kpg.initialize(spec)
                generateKeyCatcher { kpg.generateKeyPair() }

            }

回答1:


Your key is not hardware backed.

KeyInfo.isInsideSecureHardware() provides reliable information about the key in question, whereas KeyChain.isBoundKeyAlgorithm() will tell if the back-end, i.e., Keymaster the TEE or SE trusted app, supports the given algorithm.

There can be a few reasons why you see this discrepancy. Keymaster versions < 1.0 implemented some parameter combinations but not others. There were also buggy KM 1.0 implementations that occasionally failed to generate EC keys. In both cases a software fallback would take over and generate the key in software.

KeyChain.isBoundKeyAlgorithm() is too coarse a check to tell if every combination is supported, and it won't tell if the back-end is buggy. So despite it returning true, your key ends up being software backed.

Starting with KM2.0 this fallback as been deactivated. So devices with KM2.0 or newer will generate the key in hardware (TEE/SE) or not at all.

For reliable information about asymmetric keys and conveying this information to a remote relying party, consider using Keystore Key Attestation. However, this feature is hardware enforced only since KM2.0 and newer.



来源:https://stackoverflow.com/questions/57554971/how-to-tell-if-keys-are-hardware-backed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!