diff --git a/src/main/java/app/attestation/server/AttestationProtocol.java b/src/main/java/app/attestation/server/AttestationProtocol.java index beb39f74..aecd46da 100644 --- a/src/main/java/app/attestation/server/AttestationProtocol.java +++ b/src/main/java/app/attestation/server/AttestationProtocol.java @@ -778,6 +778,7 @@ private static String toYesNoString(final boolean value) { record SecurityStateExt( int autoRebootSeconds, byte portSecurityMode, byte userCount, byte oemUnlocked) { static final int UNKNOWN_VALUE = -1; + static final int INVALID_VALUE = -2; static final SecurityStateExt UNKNOWN = new SecurityStateExt(UNKNOWN_VALUE, (byte) UNKNOWN_VALUE, (byte) UNKNOWN_VALUE, (byte) UNKNOWN_VALUE); } @@ -953,10 +954,24 @@ private static void verify(final byte[] fingerprint, update.bind(13, addUsersWhenLocked ? 1 : 0); update.bind(14, 0); // oemUnlockAllowed update.bind(15, systemUser ? 1 : 0); - update.bind(16, securityStateExt.autoRebootSeconds); - update.bind(17, securityStateExt.portSecurityMode); - update.bind(18, securityStateExt.userCount); - update.bind(19, securityStateExt.oemUnlocked); + if (securityStateExt.autoRebootSeconds == SecurityStateExt.INVALID_VALUE + || securityStateExt.autoRebootSeconds == 0 + || securityStateExt.autoRebootSeconds >= 20) { + update.bind(16, securityStateExt.autoRebootSeconds); + } + if (securityStateExt.portSecurityMode == SecurityStateExt.INVALID_VALUE + || securityStateExt.portSecurityMode >= 0) { + update.bind(17, securityStateExt.portSecurityMode); + } + if (securityStateExt.userCount == SecurityStateExt.INVALID_VALUE + || securityStateExt.userCount >= 1) { + update.bind(18, securityStateExt.userCount); + } + if (securityStateExt.oemUnlocked == SecurityStateExt.INVALID_VALUE + || securityStateExt.oemUnlocked == 0 + || securityStateExt.oemUnlocked == 1) { + update.bind(19, securityStateExt.oemUnlocked); + } update.bind(20, now); update.bind(21, fingerprint); update.step(); @@ -1021,10 +1036,24 @@ INSERT INTO Devices ( insert.bind(18, addUsersWhenLocked ? 1 : 0); insert.bind(19, 0); // oemUnlockAllowed insert.bind(20, systemUser ? 1 : 0); - insert.bind(21, securityStateExt.autoRebootSeconds); - insert.bind(22, securityStateExt.portSecurityMode); - insert.bind(23, securityStateExt.userCount); - insert.bind(24, securityStateExt.oemUnlocked); + if (securityStateExt.autoRebootSeconds == SecurityStateExt.INVALID_VALUE + || securityStateExt.autoRebootSeconds == 0 + || securityStateExt.autoRebootSeconds >= 20) { + insert.bind(21, securityStateExt.autoRebootSeconds); + } + if (securityStateExt.portSecurityMode == SecurityStateExt.INVALID_VALUE + || securityStateExt.portSecurityMode >= 0) { + insert.bind(22, securityStateExt.portSecurityMode); + } + if (securityStateExt.userCount == SecurityStateExt.INVALID_VALUE + || securityStateExt.userCount >= 1) { + insert.bind(23, securityStateExt.userCount); + } + if (securityStateExt.oemUnlocked == SecurityStateExt.INVALID_VALUE + || securityStateExt.oemUnlocked == 0 + || securityStateExt.oemUnlocked == 1) { + insert.bind(24, securityStateExt.oemUnlocked); + } insert.bind(25, now); insert.bind(26, now); insert.bind(27, userId); @@ -1080,10 +1109,24 @@ INSERT INTO Attestations ( insert.bind(15, addUsersWhenLocked ? 1 : 0); insert.bind(16, 0); // oemUnlockAllowed insert.bind(17, systemUser ? 1 : 0); - insert.bind(18, securityStateExt.autoRebootSeconds); - insert.bind(19, securityStateExt.portSecurityMode); - insert.bind(20, securityStateExt.userCount); - insert.bind(21, securityStateExt.oemUnlocked); + if (securityStateExt.autoRebootSeconds == SecurityStateExt.INVALID_VALUE + || securityStateExt.autoRebootSeconds == 0 + || securityStateExt.autoRebootSeconds >= 20) { + insert.bind(18, securityStateExt.autoRebootSeconds); + } + if (securityStateExt.portSecurityMode == SecurityStateExt.INVALID_VALUE + || securityStateExt.portSecurityMode >= 0) { + insert.bind(19, securityStateExt.portSecurityMode); + } + if (securityStateExt.userCount == SecurityStateExt.INVALID_VALUE + || securityStateExt.userCount >= 1) { + insert.bind(20, securityStateExt.userCount); + } + if (securityStateExt.oemUnlocked == SecurityStateExt.INVALID_VALUE + || securityStateExt.oemUnlocked == 0 + || securityStateExt.oemUnlocked == 1) { + insert.bind(21, securityStateExt.oemUnlocked); + } insert.step(); } finally { diff --git a/src/main/java/app/attestation/server/AttestationServer.java b/src/main/java/app/attestation/server/AttestationServer.java index 85e82e9c..61a72430 100644 --- a/src/main/java/app/attestation/server/AttestationServer.java +++ b/src/main/java/app/attestation/server/AttestationServer.java @@ -234,10 +234,10 @@ adbEnabled INTEGER NOT NULL CHECK (adbEnabled in (0, 1)), addUsersWhenLocked INTEGER NOT NULL CHECK (addUsersWhenLocked in (0, 1)), oemUnlockAllowed INTEGER NOT NULL CHECK (oemUnlockAllowed in (0, 1)), systemUser INTEGER NOT NULL CHECK (systemUser in (0, 1)), - autoRebootSeconds INTEGER NOT NULL CHECK (autoRebootSeconds == -1 OR autoRebootSeconds >= 20), - portSecurityMode INTEGER NOT NULL CHECK (portSecurityMode == -1 OR portSecurityMode >= 0), - userCount INTEGER NOT NULL CHECK (userCount == -1 OR userCount >= 1), - oemUnlockAllowed2 INTEGER NOT NULL CHECK (oemUnlockAllowed2 == -1 OR oemUnlockAllowed2 in (0, 1)), + autoRebootSeconds INTEGER CHECK (autoRebootSeconds == -2 OR autoRebootSeconds == 0 OR autoRebootSeconds >= 20), + portSecurityMode INTEGER CHECK (portSecurityMode == -2 OR portSecurityMode >= 0), + userCount INTEGER CHECK (userCount == -2 OR userCount >= 1), + oemUnlockAllowed2 INTEGER CHECK (oemUnlockAllowed2 == -2 OR oemUnlockAllowed2 in (0, 1)), verifiedTimeFirst INTEGER NOT NULL, verifiedTimeLast INTEGER NOT NULL, expiredTimeLast INTEGER, @@ -266,10 +266,10 @@ adbEnabled INTEGER NOT NULL CHECK (adbEnabled in (0, 1)), addUsersWhenLocked INTEGER NOT NULL CHECK (addUsersWhenLocked in (0, 1)), oemUnlockAllowed INTEGER NOT NULL CHECK (oemUnlockAllowed in (0, 1)), systemUser INTEGER NOT NULL CHECK (systemUser in (0, 1)), - autoRebootSeconds INTEGER NOT NULL CHECK (autoRebootSeconds == -1 OR autoRebootSeconds >= 20), - portSecurityMode INTEGER NOT NULL CHECK (portSecurityMode == -1 OR portSecurityMode >= 0), - userCount INTEGER NOT NULL CHECK (userCount == -1 OR userCount >= 1), - oemUnlockAllowed2 INTEGER NOT NULL CHECK (oemUnlockAllowed2 == -1 OR oemUnlockAllowed2 in (0, 1)) + autoRebootSeconds INTEGER CHECK (autoRebootSeconds == -2 OR autoRebootSeconds == 0 OR autoRebootSeconds >= 20), + portSecurityMode INTEGER CHECK (portSecurityMode == -2 OR portSecurityMode >= 0), + userCount INTEGER CHECK (userCount == -2 OR userCount >= 1), + oemUnlockAllowed2 INTEGER CHECK (oemUnlockAllowed2 == -2 OR oemUnlockAllowed2 in (0, 1)) ) STRICT"""; private static final String CREATE_ATTESTATION_INDICES = """ @@ -722,6 +722,145 @@ INSERT INTO Attestations ( logger.info("Migrated to schema version: " + userVersion); } + // modify autoRebootSeconds, portSecurityMode, userCount, oemUnlockAllowed2 + // columns persistable values + targetUserVersion = 16; + if (userVersion < targetUserVersion) { + conn.exec("PRAGMA foreign_keys = OFF"); + conn.exec("BEGIN IMMEDIATE TRANSACTION"); + + conn.exec("ALTER TABLE Devices RENAME TO OldDevices"); + conn.exec("ALTER TABLE Attestations RENAME TO OldAttestations"); + + conn.exec(CREATE_ATTESTATION_TABLES); + + conn.exec(""" + INSERT INTO Devices ( + fingerprint, + pinnedCertificates, + attestKey, + pinnedVerifiedBootKey, + verifiedBootHash, + pinnedOsVersion, + pinnedOsPatchLevel, + pinnedVendorPatchLevel, + pinnedBootPatchLevel, + pinnedAppVersion, + pinnedAppVariant, + pinnedSecurityLevel, + userProfileSecure, + enrolledBiometrics, + accessibility, + deviceAdmin, + adbEnabled, + addUsersWhenLocked, + oemUnlockAllowed, + systemUser, + autoRebootSeconds, + portSecurityMode, + userCount, + oemUnlockAllowed2, + verifiedTimeFirst, + verifiedTimeLast, + expiredTimeLast, + failureTimeLast, + failureAlertTime, + userId, + deletionTime) + SELECT + fingerprint, + pinnedCertificates, + attestKey, + pinnedVerifiedBootKey, + verifiedBootHash, + pinnedOsVersion, + pinnedOsPatchLevel, + pinnedVendorPatchLevel, + pinnedBootPatchLevel, + pinnedAppVersion, + pinnedAppVariant, + pinnedSecurityLevel, + userProfileSecure, + enrolledBiometrics, + accessibility, + deviceAdmin, + adbEnabled, + addUsersWhenLocked, + oemUnlockAllowed, + systemUser, + (SELECT autoRebootSeconds WHERE autoRebootSeconds >= 20), + (SELECT portSecurityMode WHERE portSecurityMode >= 0), + (SELECT userCount WHERE userCount >= 1), + (SELECT oemUnlockAllowed2 WHERE oemUnlockAllowed2 in (0, 1)), + verifiedTimeFirst, + verifiedTimeLast, + expiredTimeLast, + failureTimeLast, + failureAlertTime, + userId, + deletionTime + FROM OldDevices"""); + + conn.exec(""" + INSERT INTO Attestations ( + id, + fingerprint, + time, + strong, + osVersion, + osPatchLevel, + vendorPatchLevel, + bootPatchLevel, + verifiedBootHash, + appVersion, + userProfileSecure, + enrolledBiometrics, + accessibility, + deviceAdmin, + adbEnabled, + addUsersWhenLocked, + oemUnlockAllowed, + systemUser, + autoRebootSeconds, + portSecurityMode, + userCount, + oemUnlockAllowed2 + ) SELECT + id, + fingerprint, + time, + strong, + osVersion, + osPatchLevel, + vendorPatchLevel, + bootPatchLevel, + verifiedBootHash, + appVersion, + userProfileSecure, + enrolledBiometrics, + accessibility, + deviceAdmin, + adbEnabled, + addUsersWhenLocked, + oemUnlockAllowed, + systemUser, + (SELECT autoRebootSeconds WHERE autoRebootSeconds >= 20), + (SELECT portSecurityMode WHERE portSecurityMode >= 0), + (SELECT userCount WHERE userCount >= 1), + (SELECT oemUnlockAllowed2 WHERE oemUnlockAllowed2 in (0, 1)) + FROM OldAttestations"""); + + conn.exec("DROP TABLE OldDevices"); + conn.exec("DROP TABLE OldAttestations"); + + conn.exec(CREATE_ATTESTATION_INDICES); + conn.exec("PRAGMA user_version = " + targetUserVersion); + conn.exec("COMMIT TRANSACTION"); + userVersion = targetUserVersion; + conn.exec("PRAGMA foreign_keys = ON"); + logger.info("Migrated to schema version: " + userVersion); + } + logger.info("Finished database setup for " + ATTESTATION_DATABASE); } finally { conn.dispose(); @@ -1605,21 +1744,29 @@ private static void writeDevicesJson(final HttpExchange exchange, final long use device.add("addUsersWhenLocked", select.columnInt(17)); device.add("oemUnlockAllowed", select.columnInt(18)); device.add("systemUser", select.columnInt(19)); - final int autoRebootSeconds = select.columnInt(20); - if (autoRebootSeconds != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - device.add("autoRebootSeconds", autoRebootSeconds); + if (!select.columnNull(20)) { + final int autoRebootSeconds = select.columnInt(20); + if (autoRebootSeconds != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + device.add("autoRebootSeconds", autoRebootSeconds); + } } - final int portSecurityMode = select.columnInt(21); - if (portSecurityMode != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - device.add("portSecurityMode", portSecurityMode); + if (!select.columnNull(21)) { + final int portSecurityMode = select.columnInt(21); + if (portSecurityMode != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + device.add("portSecurityMode", portSecurityMode); + } } - final int userCount = select.columnInt(22); - if (userCount != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - device.add("userCount", userCount); + if (!select.columnNull(22)) { + final int userCount = select.columnInt(22); + if (userCount != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + device.add("userCount", userCount); + } } - final int oemUnlockAllowed2 = select.columnInt(23); - if (oemUnlockAllowed2 != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - device.add("oemUnlockAllowed2", oemUnlockAllowed2); + if (!select.columnNull(23)) { + final int oemUnlockAllowed2 = select.columnInt(23); + if (oemUnlockAllowed2 != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + device.add("oemUnlockAllowed2", oemUnlockAllowed2); + } } device.add("verifiedTimeFirst", select.columnLong(24)); device.add("verifiedTimeLast", select.columnLong(25)); @@ -1734,21 +1881,29 @@ private static void writeAttestationHistoryJson(final HttpExchange exchange, fin attestation.add("addUsersWhenLocked", history.columnInt(14)); attestation.add("oemUnlockAllowed", history.columnInt(15)); attestation.add("systemUser", history.columnInt(16)); - final int autoRebootSeconds = history.columnInt(17); - if (autoRebootSeconds != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - attestation.add("autoRebootSeconds", autoRebootSeconds); + if (!history.columnNull(17)) { + final int autoRebootSeconds = history.columnInt(17); + if (autoRebootSeconds != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + attestation.add("autoRebootSeconds", autoRebootSeconds); + } } - final int portSecurityMode = history.columnInt(18); - if (portSecurityMode != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - attestation.add("portSecurityMode", portSecurityMode); + if (!history.columnNull(18)) { + final int portSecurityMode = history.columnInt(18); + if (portSecurityMode != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + attestation.add("portSecurityMode", portSecurityMode); + } } - final int userCount = history.columnInt(19); - if (userCount != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - attestation.add("userCount", userCount); + if (!history.columnNull(19)) { + final int userCount = history.columnInt(19); + if (userCount != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + attestation.add("userCount", userCount); + } } - final int oemUnlockAllowed2 = history.columnInt(20); - if (oemUnlockAllowed2 != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { - attestation.add("oemUnlockAllowed2", oemUnlockAllowed2); + if (!history.columnNull(20)) { + final int oemUnlockAllowed2 = history.columnInt(20); + if (oemUnlockAllowed2 != AttestationProtocol.SecurityStateExt.UNKNOWN_VALUE) { + attestation.add("oemUnlockAllowed2", oemUnlockAllowed2); + } } attestations.add(attestation); rowCount += 1; diff --git a/static/monitoring.js b/static/monitoring.js index 2c2dc0a1..81f612ef 100644 --- a/static/monitoring.js +++ b/static/monitoring.js @@ -86,7 +86,7 @@ function toSecurityLevelString(securityLevel, attestKey) { } function autoRebootTimeoutString(autoRebootSeconds) { - if (autoRebootSeconds >= 0) { + if (autoRebootSeconds >= 20) { const duration = { hours: Math.floor(autoRebootSeconds / 60 / 60), minutes: Math.floor(autoRebootSeconds / 60) % 60, @@ -117,8 +117,8 @@ function autoRebootTimeoutString(autoRebootSeconds) { return durationString; } - } else if (autoRebootSeconds == -1) { - return "Unknown"; + } else if (autoRebootSeconds == 0) { + return "Off"; } else if (autoRebootSeconds == -2) { return "Invalid"; } @@ -135,8 +135,6 @@ function usbPortSecurityModeString(portSecurityMode, hasPogoPins) { case 4: return "On"; default: break; } - } else if (portSecurityMode == -1) { - return "Unknown"; } else if (portSecurityMode == -2) { return "Invalid"; } @@ -146,8 +144,6 @@ function usbPortSecurityModeString(portSecurityMode, hasPogoPins) { function userCountString(userCount) { if (userCount > 0) { return userCount; - } else if (userCount == -1) { - return "Unknown"; } else if (userCount == -2) { return "Invalid"; } @@ -155,10 +151,8 @@ function userCountString(userCount) { } function oemUnlockAllowedString(oemUnlockAllowed2) { - if (oemUnlockAllowed2 >= 0) { + if (oemUnlockAllowed2 == 0 || oemUnlockAllowed2 == 1) { return toYesNoString(oemUnlockAllowed2 > 0); - } else if (oemUnlockAllowed2 == -1) { - return "Unknown"; } else if (oemUnlockAllowed2 == -2) { return "Invalid"; } @@ -255,18 +249,23 @@ function fetchHistory(parent, nextOffset, hasPogoPins) { appendLine(parent, "Device administrator(s) enabled: " + deviceAdminStrings.get(attestation.deviceAdmin)); appendLine(parent, "Android Debug Bridge enabled: " + toYesNoString(attestation.adbEnabled)); appendLine(parent, "Add users from lock screen: " + toYesNoString(attestation.addUsersWhenLocked)); - if (attestation.oemUnlockAllowed2 !== undefined && attestation.oemUnlockedAllowed2 >= 0) { + + if (attestation.oemUnlockAllowed2 !== undefined + && (attestation.oemUnlockedAllowed2 >= 0 || attestation.oemUnlockAllowed == -2)) { appendLine(parent, "OEM unlocking allowed: " + oemUnlockAllowedString(attestation.oemUnlockAllowed2)); } appendLine(parent, "Main user account: " + toYesNoString(attestation.systemUser)); - if (attestation.autoRebootSeconds !== undefined && attestation.autoRebootSeconds >= 20) { + if (attestation.autoRebootSeconds !== undefined + && (attestation.autoRebootSeconds == -2 + || attestation.autoRebootSeconds == 0 || attestation.autoRebootSeconds >= 20)) { appendLine(parent, "Auto reboot timeout: " + autoRebootTimeoutString(attestation.autoRebootSeconds)); } - if (attestation.portSecurityMode !== undefined && attestation.portSecurityMode >= 0) { + if (attestation.portSecurityMode !== undefined + && (attestation.portSecurityMode == -2 || attestation.portSecurityMode >= 0)) { appendLine(parent, "USB-C port" + ((attestation.hasPogoPins > 0) ? " and pogo pins" : "") + " security mode: " + usbPortSecurityModeString(attestation.portSecurityMode, hasPogoPins)); } - if (attestation.userCount !== undefined && attestation.userCount >= 1) { + if (attestation.userCount !== undefined && (attestation.userCount == -2 || attestation.userCount >= 1)) { appendLine(parent, "User count: " + userCountString(attestation.userCount)); } } @@ -391,17 +390,20 @@ function fetchDevices() { appendLine(info, "Device administrator(s) enabled: " + deviceAdminStrings.get(device.deviceAdmin)); appendLine(info, "Android Debug Bridge enabled: " + toYesNoString(device.adbEnabled)); appendLine(info, "Add users from lock screen: " + toYesNoString(device.addUsersWhenLocked)); - if (device.oemUnlockAllowed2 !== undefined && device.oemUnlockAllowed2 >= 0) { + if (device.oemUnlockAllowed2 !== undefined + && (device.oemUnlockAllowed2 == -2 || device.oemUnlockAllowed2 >= 0)) { appendLine(info, "OEM unlocking allowed: " + oemUnlockAllowedString(device.oemUnlockAllowed2)); } appendLine(info, "Main user account: " + toYesNoString(device.systemUser)); - if (device.autoRebootSeconds !== undefined && device.autoRebootSeconds >= 20) { + if (device.autoRebootSeconds !== undefined + && (device.autoRebootSeconds == -2 || device.autoRebootSeconds == 0 || device.autoRebootSeconds >= 20)) { appendLine(info, "Auto reboot timeout: " + autoRebootTimeoutString(device.autoRebootSeconds)); } - if (device.portSecurityMode !== undefined && device.portSecurityMode >= 0) { + if (device.portSecurityMode !== undefined + && (device.portSecurityMode == -2 || device.portSecurityMode >= 0)) { appendLine(info, "USB-C port" + ((device.hasPogoPins > 0) ? " and pogo pins" : "") + " security mode: " + usbPortSecurityModeString(device.portSecurityMode, device.hasPogoPins)); } - if (device.userCount !== undefined && device.userCount >= 1) { + if (device.userCount !== undefined && (device.userCount == -2 || device.userCount >= 1)) { appendLine(info, "User count: " + userCountString(device.userCount)); }