From e19d1450e2fb0ecc51b8f11fece879516178a629 Mon Sep 17 00:00:00 2001
From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com>
Date: Mon, 30 Sep 2024 07:58:57 +0000
Subject: [PATCH] Support deserializing and displaying downstream security
state
---
.../auditor/AttestationProtocol.java | 84 ++++++++++++++++++-
app/src/main/res/values/strings.xml | 18 ++++
2 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/app/attestation/auditor/AttestationProtocol.java b/app/src/main/java/app/attestation/auditor/AttestationProtocol.java
index 40e18267..fded3bc8 100644
--- a/app/src/main/java/app/attestation/auditor/AttestationProtocol.java
+++ b/app/src/main/java/app/attestation/auditor/AttestationProtocol.java
@@ -958,7 +958,8 @@ private static VerificationResult verify(final Context context, final byte[] fin
final boolean accessibility, final boolean deviceAdmin,
final boolean deviceAdminNonSystem, final boolean adbEnabled,
final boolean addUsersWhenLocked, final boolean enrolledBiometrics,
- final boolean oemUnlockAllowed, final boolean systemUser)
+ final boolean oemUnlockAllowed, final boolean systemUser,
+ SecurityStateExt securityStateExt)
throws GeneralSecurityException {
final String fingerprintHex = BaseEncoding.base16().encode(fingerprint);
final byte[] currentFingerprint = getFingerprint(attestationCertificates[0]);
@@ -1134,6 +1135,80 @@ private static VerificationResult verify(final Context context, final byte[] fin
osEnforced.append(context.getString(R.string.system_user,
toYesNoString(context, systemUser)));
+ final boolean appliesToPogoPins = verified.device() == R.string.device_pixel_tablet;
+ final int usbcPortSecurityModePrefix;
+ if (appliesToPogoPins) {
+ usbcPortSecurityModePrefix = R.string.usbc_port_and_pogo_pins;
+ } else {
+ usbcPortSecurityModePrefix = R.string.usbc_port_security_mode;
+ }
+
+ final int usbcPortSecurityModeOffRes;
+ if (appliesToPogoPins) {
+ usbcPortSecurityModeOffRes = R.string.usbc_port_and_pogo_pins_off_title;
+ } else {
+ usbcPortSecurityModeOffRes = R.string.usbc_port_security_mode_off;
+ }
+
+ final byte usbcPortSecurityMode = securityStateExt.portSecurityMode();
+ final int usbcPortSecurityModeValueRes;
+ if (usbcPortSecurityMode == SecurityStateExt.UNKNOWN_VALUE) {
+ usbcPortSecurityModeValueRes = R.string.unknown_value;
+ } else if (usbcPortSecurityMode == SecurityStateExt.INVALID_VALUE) {
+ usbcPortSecurityModeValueRes = R.string.invalid_value;
+ } else {
+ usbcPortSecurityModeValueRes = switch (usbcPortSecurityMode) {
+ case 0 -> usbcPortSecurityModeOffRes;
+ case 1 -> R.string.usbc_port_security_mode_charging_only;
+ case 2 -> R.string.usbc_port_security_mode_charging_only_when_locked;
+ case 3 -> R.string.usbc_port_security_mode_charging_only_when_locked_afu;
+ case 4 -> R.string.usbc_port_security_mode_on;
+ default -> throw new IllegalArgumentException();
+ };
+ }
+ osEnforced.append(context.getString(usbcPortSecurityModePrefix,
+ context.getString(usbcPortSecurityModeValueRes)));
+
+ final short autoRebootMinutes = securityStateExt.autoRebootMinutes();
+ final String autoRebootValueString;
+ if (autoRebootMinutes == SecurityStateExt.UNKNOWN_VALUE) {
+ autoRebootValueString = context.getString(R.string.unknown_value);
+ } else if (autoRebootMinutes == SecurityStateExt.INVALID_VALUE) {
+ autoRebootValueString = context.getString(R.string.invalid_value);
+ } else {
+ final StringBuilder autoRebootValueStrBuilder = new StringBuilder();
+ long autoRebootTimeoutMinutes = TimeUnit.MINUTES.toMinutes(autoRebootMinutes);
+ if (autoRebootMinutes > TimeUnit.HOURS.toMinutes(1)) {
+ final long hours = TimeUnit.MINUTES.toHours(autoRebootTimeoutMinutes);
+ autoRebootValueStrBuilder.append(
+ context.getString(R.string.auto_reboot_hours_value, hours));
+ autoRebootTimeoutMinutes -= TimeUnit.HOURS.toMinutes(hours);
+ }
+
+ if (autoRebootTimeoutMinutes > TimeUnit.MINUTES.toMinutes(1)) {
+ final long minutes = TimeUnit.MINUTES.toMinutes(autoRebootTimeoutMinutes);
+ if (autoRebootValueStrBuilder.length() > 0) {
+ autoRebootValueStrBuilder.append(" ");
+ }
+ autoRebootValueStrBuilder.append(
+ context.getString(R.string.auto_reboot_minutes_value, minutes));
+ }
+
+ autoRebootValueString = autoRebootValueStrBuilder.toString();
+ }
+ osEnforced.append(context.getString(R.string.auto_reboot_timeout, autoRebootValueString));
+
+ final byte userCount = securityStateExt.userCount();
+ final String userCountValueString;
+ if (userCount == SecurityStateExt.UNKNOWN_VALUE) {
+ userCountValueString = context.getString(R.string.unknown_value);
+ } else if (userCount == SecurityStateExt.INVALID_VALUE) {
+ userCountValueString = context.getString(R.string.invalid_value);
+ } else {
+ userCountValueString = String.valueOf(securityStateExt.userCount());
+ }
+ osEnforced.append(context.getString(R.string.user_count, userCountValueString));
+
return new VerificationResult(hasPersistentKey, teeEnforced.toString(), osEnforced.toString(), history.toString());
}
@@ -1231,10 +1306,14 @@ static VerificationResult verifySerialized(final Context context, final byte[] a
throw new GeneralSecurityException("invalid device administrator state");
}
+ final SecurityStateExt securityStateExt;
if (version >= 6) {
final short autoRebootMinutes = deserializer.getShort();
final byte portSecurityMode = deserializer.get();
final byte userCount = deserializer.get();
+ securityStateExt = new SecurityStateExt(autoRebootMinutes, portSecurityMode, userCount);
+ } else {
+ securityStateExt = SecurityStateExt.UNKNOWN;
}
final int signatureLength = deserializer.remaining();
@@ -1247,7 +1326,8 @@ static VerificationResult verifySerialized(final Context context, final byte[] a
final byte[] challenge = Arrays.copyOfRange(challengeMessage, 1 + RANDOM_TOKEN_LENGTH, 1 + RANDOM_TOKEN_LENGTH * 2);
return verify(context, fingerprint, challenge, deserializer.asReadOnlyBuffer(), signature,
certificates, userProfileSecure, accessibility, deviceAdmin, deviceAdminNonSystem,
- adbEnabled, addUsersWhenLocked, enrolledBiometrics, oemUnlockAllowed, systemUser);
+ adbEnabled, addUsersWhenLocked, enrolledBiometrics, oemUnlockAllowed, systemUser,
+ securityStateExt);
}
record AttestationResult(boolean pairing, byte[] serialized) {}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c29d7031..29a62976 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -86,6 +86,24 @@
Add users from lock screen: %s\n
OEM unlocking allowed: %s\n
Main user account: %s\n
+ Auto reboot timeout: %s\n
+ %d minutes
+ %d hours
+
+ USB-C port: %s\n
+ USB-C port and pogo pins: %s\n
+
+ Off
+ USB-C port off, pogo pins used only for charging
+ Charging-only
+ Charging-only when locked
+ Charging-only when locked, except before first unlock
+ On
+
+ User count: %s\n
+
+ Unknown
+ Invalid
\nAttestation history:\n\n
First verified: %s\n