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