Skip to content

Commit 29b8243

Browse files
agxpcopybara-github
authored andcommitted
Add Flogger logging and ThreadSafe annotations to Verifier.
PiperOrigin-RevId: 850090876
1 parent 851433e commit 29b8243

1 file changed

Lines changed: 84 additions & 18 deletions

File tree

src/main/kotlin/Verifier.kt

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.android.keyattestation.verifier.provider.KeyAttestationProvider
2222
import com.android.keyattestation.verifier.provider.ProvisioningMethod
2323
import com.android.keyattestation.verifier.provider.RevocationChecker
2424
import com.google.common.collect.ImmutableList
25+
import com.google.common.flogger.GoogleLogger
2526
import com.google.common.util.concurrent.ListenableFuture
2627
import com.google.errorprone.annotations.ThreadSafe
2728
import com.google.protobuf.ByteString
@@ -42,28 +43,44 @@ import kotlinx.coroutines.guava.future
4243
import kotlinx.coroutines.runBlocking
4344

4445
/** The result of verifying an Android Key Attestation certificate chain. */
46+
@ThreadSafe
4547
sealed interface VerificationResult {
48+
@ThreadSafe
4649
data class Success(
47-
val publicKey: PublicKey,
50+
@field:ThreadSafe.Suppress(reason = "PublicKey is immutable") val publicKey: PublicKey,
4851
val challenge: ByteString,
4952
val securityLevel: SecurityLevel,
5053
val verifiedBootState: VerifiedBootState,
5154
val deviceInformation: ProvisioningInfoMap?,
55+
@field:ThreadSafe.Suppress(reason = "DeviceIdentity is deeply immutable")
5256
val attestedDeviceIds: DeviceIdentity,
5357
) : VerificationResult
5458

55-
data object ChallengeMismatch : VerificationResult
59+
@ThreadSafe data object ChallengeMismatch : VerificationResult
5660

57-
data class PathValidationFailure(val cause: CertPathValidatorException) : VerificationResult
61+
@ThreadSafe
62+
data class PathValidationFailure(
63+
@field:ThreadSafe.Suppress(reason = "Exceptions are generally immutable after creation")
64+
val cause: CertPathValidatorException
65+
) : VerificationResult
5866

59-
data class ChainParsingFailure(val cause: Exception) : VerificationResult
67+
@ThreadSafe
68+
data class ChainParsingFailure(
69+
@field:ThreadSafe.Suppress(reason = "Exceptions are generally immutable after creation")
70+
val cause: Exception
71+
) : VerificationResult
6072

61-
data class ExtensionParsingFailure(val cause: ExtensionParsingException) : VerificationResult
73+
@ThreadSafe
74+
data class ExtensionParsingFailure(
75+
@field:ThreadSafe.Suppress(reason = "Exceptions are generally immutable after creation")
76+
val cause: ExtensionParsingException
77+
) : VerificationResult
6278

79+
@ThreadSafe
6380
data class ExtensionConstraintViolation(val cause: String, val reason: KeyAttestationReason) :
6481
VerificationResult
6582

66-
data object SoftwareAttestationUnsupported : VerificationResult
83+
@ThreadSafe data object SoftwareAttestationUnsupported : VerificationResult
6784
}
6885

6986
/**
@@ -141,6 +158,10 @@ open class Verifier(
141158
private val revokedSerialsSource: () -> Set<String>,
142159
private val instantSource: InstantSource,
143160
) {
161+
companion object {
162+
private val logger = GoogleLogger.forEnclosingClass()
163+
}
164+
144165
init {
145166
Security.addProvider(KeyAttestationProvider())
146167
for (anchor in trustAnchorsSource()) {
@@ -170,17 +191,17 @@ open class Verifier(
170191
challengeChecker: ChallengeChecker? = null,
171192
log: LogHook? = null,
172193
): VerificationResult {
173-
val requestLog = log?.createRequestLog()
194+
val requestLog = (log ?: GoogleLoggerLogHook(logger)).createRequestLog()
174195
val result =
175196
try {
176197
val certPath = KeyAttestationCertPath(chain)
177198
runBlocking { internalVerify(certPath, challengeChecker, requestLog) }
178199
} catch (e: CertificateException) {
179-
requestLog?.logInputChain(chain.map { it.getEncoded().toByteString() })
200+
requestLog.logInputChain(chain.map { it.getEncoded().toByteString() })
180201
VerificationResult.ChainParsingFailure(e)
181202
}
182-
requestLog?.logResult(result)
183-
requestLog?.flush()
203+
requestLog.logResult(result)
204+
requestLog.flush()
184205
return result
185206
}
186207

@@ -203,17 +224,17 @@ open class Verifier(
203224
): ListenableFuture<VerificationResult> {
204225
val immutableChain = ImmutableList.copyOf(chain)
205226
return coroutineScope.future {
206-
val requestLog = log?.createRequestLog()
227+
val requestLog = (log ?: GoogleLoggerLogHook(logger)).createRequestLog()
207228
val result =
208229
try {
209230
val certPath = KeyAttestationCertPath(immutableChain)
210231
internalVerify(certPath, challengeChecker, requestLog)
211232
} catch (e: CertificateException) {
212-
requestLog?.logInputChain(immutableChain.map { it.getEncoded().toByteString() })
233+
requestLog.logInputChain(immutableChain.map { it.getEncoded().toByteString() })
213234
VerificationResult.ChainParsingFailure(e)
214235
}
215-
requestLog?.logResult(result)
216-
requestLog?.flush()
236+
requestLog.logResult(result)
237+
requestLog.flush()
217238
result
218239
}
219240
}
@@ -242,6 +263,7 @@ open class Verifier(
242263
try {
243264
certPath.attestationCert().provisioningInfo()
244265
} catch (e: Exception) {
266+
logger.atWarning().withCause(e).log("Failed to parse provisioning info map.")
245267
log?.logInfoMessage("Failed to parse provisioning info map: ${e.message}")
246268
null
247269
}
@@ -312,10 +334,12 @@ open class Verifier(
312334
}
313335
val rootOfTrust =
314336
keyDescription.hardwareEnforced.rootOfTrust
315-
?: return VerificationResult.ExtensionConstraintViolation(
316-
"hardwareEnforced.rootOfTrust is null",
317-
KeyAttestationReason.ROOT_OF_TRUST_MISSING,
318-
)
337+
?: run {
338+
return VerificationResult.ExtensionConstraintViolation(
339+
"hardwareEnforced.rootOfTrust is null",
340+
KeyAttestationReason.ROOT_OF_TRUST_MISSING,
341+
)
342+
}
319343
return VerificationResult.Success(
320344
pathValidationResult.publicKey,
321345
keyDescription.attestationChallenge,
@@ -325,4 +349,46 @@ open class Verifier(
325349
DeviceIdentity.parseFrom(keyDescription),
326350
)
327351
}
352+
353+
@ThreadSafe
354+
private class GoogleLoggerLogHook(private val logger: GoogleLogger) : LogHook {
355+
override fun createRequestLog(): VerifyRequestLog {
356+
return GoogleLoggerRequestLog(logger)
357+
}
358+
}
359+
360+
@ThreadSafe
361+
private class GoogleLoggerRequestLog(private val logger: GoogleLogger) : VerifyRequestLog {
362+
override fun logInputChain(inputChain: List<ByteString>) {}
363+
364+
override fun logResult(result: VerificationResult) {
365+
when (result) {
366+
is VerificationResult.Success -> logger.atInfo().log("Attestation verification succeeded.")
367+
is VerificationResult.ChallengeMismatch ->
368+
logger.atWarning().log("Attestation challenge mismatch.")
369+
is VerificationResult.PathValidationFailure ->
370+
logger.atWarning().withCause(result.cause).log("Certificate path validation failed.")
371+
is VerificationResult.ChainParsingFailure ->
372+
logger.atWarning().withCause(result.cause).log("Failed to parse certificate chain.")
373+
is VerificationResult.ExtensionParsingFailure ->
374+
logger
375+
.atWarning()
376+
.withCause(result.cause)
377+
.log("Failed to parse key description extension.")
378+
is VerificationResult.ExtensionConstraintViolation ->
379+
logger.atWarning().log("Constraint violation: %s", result.cause)
380+
is VerificationResult.SoftwareAttestationUnsupported -> {}
381+
}
382+
}
383+
384+
override fun logKeyDescription(keyDescription: KeyDescription) {}
385+
386+
override fun logProvisioningInfoMap(provisioningInfoMap: ProvisioningInfoMap) {}
387+
388+
override fun logCertSerialNumbers(certSerialNumbers: List<String>) {}
389+
390+
override fun logInfoMessage(infoMessage: String) {}
391+
392+
override fun flush() {}
393+
}
328394
}

0 commit comments

Comments
 (0)