Skip to content

Commit

Permalink
Support deserializing and displaying downstream security state
Browse files Browse the repository at this point in the history
  • Loading branch information
quh4gko8 committed Oct 1, 2024
1 parent aae0da6 commit e19d145
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
84 changes: 82 additions & 2 deletions app/src/main/java/app/attestation/auditor/AttestationProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down Expand Up @@ -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());
}

Expand Down Expand Up @@ -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();
Expand All @@ -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) {}
Expand Down
18 changes: 18 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,24 @@
<string name="add_users_when_locked">Add users from lock screen: %s\n</string>
<string name="oem_unlock_allowed">OEM unlocking allowed: %s\n</string>
<string name="system_user">Main user account: %s\n</string>
<string name="auto_reboot_timeout">Auto reboot timeout: %s\n</string>
<string name="auto_reboot_minutes_value">%d minutes</string>
<string name="auto_reboot_hours_value">%d hours</string>

<string name="usbc_port_security_mode">USB-C port: %s\n</string>
<string name="usbc_port_and_pogo_pins">USB-C port and pogo pins: %s\n</string>

<string name="usbc_port_security_mode_off">Off</string>
<string name="usbc_port_and_pogo_pins_off_title">USB-C port off, pogo pins used only for charging</string>
<string name="usbc_port_security_mode_charging_only">Charging-only</string>
<string name="usbc_port_security_mode_charging_only_when_locked">Charging-only when locked</string>
<string name="usbc_port_security_mode_charging_only_when_locked_afu">Charging-only when locked, except before first unlock</string>
<string name="usbc_port_security_mode_on">On</string>

<string name="user_count">User count: %s\n</string>

<string name="unknown_value">Unknown</string>
<string name="invalid_value">Invalid</string>

<string name="history">\n<b>Attestation history:</b>\n\n</string>
<string name="first_verified">First verified: %s\n</string>
Expand Down

0 comments on commit e19d145

Please sign in to comment.