Skip to content

Commit 23ddd4c

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

1 file changed

Lines changed: 61 additions & 10 deletions

File tree

src/main/kotlin/Verifier.kt

Lines changed: 61 additions & 10 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()) {
@@ -176,6 +197,7 @@ open class Verifier(
176197
val certPath = KeyAttestationCertPath(chain)
177198
runBlocking { internalVerify(certPath, challengeChecker, requestLog) }
178199
} catch (e: CertificateException) {
200+
logger.atWarning().withCause(e).log("Failed to parse certificate chain.")
179201
requestLog?.logInputChain(chain.map { it.getEncoded().toByteString() })
180202
VerificationResult.ChainParsingFailure(e)
181203
}
@@ -209,6 +231,7 @@ open class Verifier(
209231
val certPath = KeyAttestationCertPath(immutableChain)
210232
internalVerify(certPath, challengeChecker, requestLog)
211233
} catch (e: CertificateException) {
234+
logger.atWarning().withCause(e).log("Failed to parse certificate chain.")
212235
requestLog?.logInputChain(immutableChain.map { it.getEncoded().toByteString() })
213236
VerificationResult.ChainParsingFailure(e)
214237
}
@@ -242,6 +265,7 @@ open class Verifier(
242265
try {
243266
certPath.attestationCert().provisioningInfo()
244267
} catch (e: Exception) {
268+
logger.atWarning().withCause(e).log("Failed to parse provisioning info map.")
245269
log?.logInfoMessage("Failed to parse provisioning info map: ${e.message}")
246270
null
247271
}
@@ -257,13 +281,20 @@ open class Verifier(
257281
e.message == "No matching trust anchor found" &&
258282
certPath.certificatesWithAnchor.last().isSoftwareRoot()
259283
) {
284+
logger
285+
.atWarning()
286+
.withCause(e)
287+
.log(
288+
"Chain terminates in a software root and no matching trust anchor was found, so the chain was not validated."
289+
)
260290
return VerificationResult.PathValidationFailure(
261291
CertPathValidatorException(
262292
"Chain terminates in a software root and no matching trust anchor was found, so the chain was not validated.",
263293
e,
264294
)
265295
)
266296
}
297+
logger.atWarning().withCause(e).log("Certificate path validation failed.")
267298
return VerificationResult.PathValidationFailure(e)
268299
}
269300

@@ -276,8 +307,10 @@ open class Verifier(
276307
"Key attestation extension not found"
277308
}
278309
} catch (e: ExtensionParsingException) {
310+
logger.atWarning().withCause(e).log("Failed to parse key description extension.")
279311
return VerificationResult.ExtensionParsingFailure(e)
280312
} catch (e: Exception) {
313+
logger.atWarning().withCause(e).log("Failed to parse key description extension.")
281314
// TODO(google-internal bug): When experimental contracts aren't experimental,
282315
// update the IllegalArgumentException and IllegalStateException cases to return
283316
// ExtensionParsingException.
@@ -287,6 +320,7 @@ open class Verifier(
287320
if (challengeChecker != null) {
288321
val checkResult = challengeChecker.checkChallenge(keyDescription.attestationChallenge).await()
289322
if (!checkResult) {
323+
logger.atWarning().log("Attestation challenge mismatch.")
290324
return VerificationResult.ChallengeMismatch
291325
}
292326
}
@@ -295,6 +329,12 @@ open class Verifier(
295329
keyDescription.hardwareEnforced.origin == null ||
296330
keyDescription.hardwareEnforced.origin != Origin.GENERATED
297331
) {
332+
logger
333+
.atWarning()
334+
.log(
335+
"Constraint violation: origin != GENERATED: %s",
336+
keyDescription.hardwareEnforced.origin,
337+
)
298338
return VerificationResult.ExtensionConstraintViolation(
299339
"origin != GENERATED: ${keyDescription.hardwareEnforced.origin}",
300340
KeyAttestationReason.KEY_ORIGIN_NOT_GENERATED,
@@ -305,17 +345,28 @@ open class Verifier(
305345
if (keyDescription.attestationSecurityLevel == keyDescription.keyMintSecurityLevel) {
306346
keyDescription.attestationSecurityLevel
307347
} else {
348+
logger
349+
.atWarning()
350+
.log(
351+
"Constraint violation: attestationSecurityLevel != keyMintSecurityLevel: %s != %s",
352+
keyDescription.attestationSecurityLevel,
353+
keyDescription.keyMintSecurityLevel,
354+
)
308355
return VerificationResult.ExtensionConstraintViolation(
309356
"attestationSecurityLevel != keyMintSecurityLevel: ${keyDescription.attestationSecurityLevel} != ${keyDescription.keyMintSecurityLevel}",
310357
KeyAttestationReason.MISMATCHED_SECURITY_LEVELS,
311358
)
312359
}
313360
val rootOfTrust =
314361
keyDescription.hardwareEnforced.rootOfTrust
315-
?: return VerificationResult.ExtensionConstraintViolation(
316-
"hardwareEnforced.rootOfTrust is null",
317-
KeyAttestationReason.ROOT_OF_TRUST_MISSING,
318-
)
362+
?: run {
363+
logger.atWarning().log("Constraint violation: hardwareEnforced.rootOfTrust is null")
364+
return VerificationResult.ExtensionConstraintViolation(
365+
"hardwareEnforced.rootOfTrust is null",
366+
KeyAttestationReason.ROOT_OF_TRUST_MISSING,
367+
)
368+
}
369+
logger.atInfo().log("Attestation verification succeeded.")
319370
return VerificationResult.Success(
320371
pathValidationResult.publicKey,
321372
keyDescription.attestationChallenge,

0 commit comments

Comments
 (0)