From 18abe6c426a34d7f07517405d0f714dbd4e8b7b3 Mon Sep 17 00:00:00 2001 From: Carmen Hanish Date: Mon, 13 Jul 2026 05:08:41 -0700 Subject: [PATCH] Log the signing algorithms of the certificate chain. This change also gives the LogHook methods. Supporting what can be logged should not be a requirement. PiperOrigin-RevId: 946969655 --- src/main/kotlin/Verifier.kt | 24 ++++++++++++----- .../kotlin/provider/KeyAttestationCertPath.kt | 26 +++++++++++++++++++ src/main/kotlin/testing/FakeLogHook.kt | 5 ++++ .../provider/KeyAttestationCertPathTest.kt | 10 +++++++ 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/Verifier.kt b/src/main/kotlin/Verifier.kt index ed38e6d..f3ae21e 100644 --- a/src/main/kotlin/Verifier.kt +++ b/src/main/kotlin/Verifier.kt @@ -83,14 +83,14 @@ interface VerifyRequestLog { * * @param inputChain The certificate chain which is being verified. */ - fun logInputChain(inputChain: List) + fun logInputChain(inputChain: List) {} /** * Logs the result of the verification. Called for each call to [verify]. * * @param result The result of the verification. */ - fun logResult(result: VerificationResult) + fun logResult(result: VerificationResult) {} /** * Logs the key description of the leaf certificate. Called if [verify] reaches the point where @@ -98,7 +98,7 @@ interface VerifyRequestLog { * * @param keyDescription The key description of the leaf certificate. */ - fun logKeyDescription(keyDescription: KeyDescription) + fun logKeyDescription(keyDescription: KeyDescription) {} /** * Logs the provisioning info map extension of the attestation certificate. Called if [verify] @@ -107,7 +107,7 @@ interface VerifyRequestLog { * * @param provisioningInfoMap The provisioning info map extension of the leaf certificate. */ - fun logProvisioningInfoMap(provisioningInfoMap: ProvisioningInfoMap) + fun logProvisioningInfoMap(provisioningInfoMap: ProvisioningInfoMap) {} /** * Logs the serial numbers of the intermediate certificates in the certificate chain. Called if @@ -116,17 +116,25 @@ interface VerifyRequestLog { * @param certSerialNumbers The serial numbers of the intermediate certificates in the certificate * chain. */ - fun logCertSerialNumbers(certSerialNumbers: List) + fun logCertSerialNumbers(certSerialNumbers: List) {} + + /** + * Logs the certificate signing algorithms of the intermediate certificates in the certificate + * chain. Called if [verify] reaches the point where the certificate chain is validated. + * + * @param certSigningAlgorithms The certificate signing algorithms in the chain. + */ + fun logCertSigningAlgorithms(certSigningAlgorithms: Set) {} /** * Logs an info level message. May be called throughout the verification process. * * @param infoMessage The info level message to log. */ - fun logInfoMessage(infoMessage: String) + fun logInfoMessage(infoMessage: String) {} /* Flushes any buffered logs. Called just before [verify] returns. */ - fun flush() + fun flush() {} } /** @@ -267,6 +275,8 @@ constructor( return VerificationResult.PathValidationFailure(e) } + log?.logCertSigningAlgorithms(certPath.signingAlgorithms()) + val keyDescription = try { checkNotNull( diff --git a/src/main/kotlin/provider/KeyAttestationCertPath.kt b/src/main/kotlin/provider/KeyAttestationCertPath.kt index 8ce5fc6..cb18a30 100644 --- a/src/main/kotlin/provider/KeyAttestationCertPath.kt +++ b/src/main/kotlin/provider/KeyAttestationCertPath.kt @@ -19,9 +19,14 @@ package com.android.keyattestation.verifier.provider import com.android.keyattestation.verifier.SecurityLevel import com.android.keyattestation.verifier.asX509Certificate import com.google.protobuf.ByteString +import java.security.PublicKey import java.security.cert.CertPath import java.security.cert.CertificateException import java.security.cert.X509Certificate +import java.security.interfaces.DSAPublicKey +import java.security.interfaces.ECPublicKey +import java.security.interfaces.RSAPublicKey +import javax.crypto.interfaces.DHPublicKey import javax.security.auth.x500.X500Principal /** @@ -72,6 +77,18 @@ class KeyAttestationCertPath(certs: List) : CertPath("X.509") { */ fun serialNumbers() = certificatesWithAnchor.map { it.serialNumber.toString(16) } + /** + * Returns the signing algorithms of the certificates in the certificate chain. + * + * The format is "algNameKeySizeN". + * + * @return the signing algorithms of the certificates in the certificate chain. + */ + fun signingAlgorithms() = + certificatesWithAnchor + .zipWithNext { cert, issuer -> "${cert.sigAlgName}KeySize${issuer.publicKey.keySize()}" } + .toSet() + fun provisioningMethod() = when { isFactoryProvisioned() -> ProvisioningMethod.FACTORY_PROVISIONED @@ -152,6 +169,15 @@ private fun parseDN(dn: String): Map { return attributes } +private fun PublicKey.keySize() = + when (this) { + is RSAPublicKey -> this.modulus.bitLength().toString() + is ECPublicKey -> this.params.curve.field.fieldSize.toString() + is DSAPublicKey -> this.y.bitLength().toString() + is DHPublicKey -> this.y.bitLength().toString() + else -> "unknown" + } + private fun String?.toSecurityLevel() = when (this) { "TEE" -> SecurityLevel.TRUSTED_ENVIRONMENT diff --git a/src/main/kotlin/testing/FakeLogHook.kt b/src/main/kotlin/testing/FakeLogHook.kt index 5a969bb..e4ac99b 100644 --- a/src/main/kotlin/testing/FakeLogHook.kt +++ b/src/main/kotlin/testing/FakeLogHook.kt @@ -51,6 +51,7 @@ class FakeVerifyRequestLog : VerifyRequestLog { var provisioningInfoMap: ProvisioningInfoMap? = null var certSerialNumbers = mutableListOf() var infoMessages = mutableListOf() + var certSigningAlgorithms = mutableSetOf() override fun logInputChain(inputChain: List) { this.inputChain.addAll(inputChain) @@ -72,6 +73,10 @@ class FakeVerifyRequestLog : VerifyRequestLog { this.certSerialNumbers.addAll(certSerialNumbers) } + override fun logCertSigningAlgorithms(certSigningAlgorithms: Set) { + this.certSigningAlgorithms.addAll(certSigningAlgorithms) + } + override fun logInfoMessage(infoMessage: String) { this.infoMessages.add(infoMessage) } diff --git a/src/test/kotlin/provider/KeyAttestationCertPathTest.kt b/src/test/kotlin/provider/KeyAttestationCertPathTest.kt index cf73b69..bfc99fc 100644 --- a/src/test/kotlin/provider/KeyAttestationCertPathTest.kt +++ b/src/test/kotlin/provider/KeyAttestationCertPathTest.kt @@ -101,6 +101,16 @@ class KeyAttestationCertPathTest { .inOrder() } + @Test + fun signingAlgorithms_returnsExpectedSigningAlgorithms() { + assertThat(readCertPath("blueline/sdk28/TEE_EC_NONE.pem").signingAlgorithms()) + .containsExactly( + "SHA256withECDSAKeySize256", + "SHA256withECDSAKeySize384", + "SHA256withRSAKeySize4096", + ) + } + @Test fun provisioningMethod_returnsExpectedType(@TestParameter testCase: ProvisioningMethodTestCase) { val certPath = readCertPath("${testCase.path}.pem")