Skip to content

Commit

Permalink
Support for added security state downstream
Browse files Browse the repository at this point in the history
  • Loading branch information
quh4gko8 committed Jan 6, 2025
1 parent 04c5b7c commit dee63be
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 16 deletions.
51 changes: 41 additions & 10 deletions src/main/java/app/attestation/server/AttestationProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -807,14 +807,22 @@ private static String toYesNoString(final boolean value) {
return value ? "yes" : "no";
}

record SecurityStateExt(short autoRebootMinutes, byte portSecurityMode, byte userCount) {
static int UNKNOWN_VALUE = -1;
static int INVALID_VALUE = -2;
static SecurityStateExt UNKNOWN = new SecurityStateExt(
(short) UNKNOWN_VALUE, (byte) UNKNOWN_VALUE, (byte) UNKNOWN_VALUE);
}

private static void verify(final byte[] fingerprint,
final Cache<ByteBuffer, Boolean> pendingChallenges, final long userId,
final boolean paired, final ByteBuffer signedMessage, final byte[] signature,
final Certificate[] attestationCertificates, final boolean userProfileSecure,
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,
final SecurityStateExt securityStateExt)
throws GeneralSecurityException, IOException, SQLiteException {
final String fingerprintHex = BaseEncoding.base16().encode(fingerprint);
final byte[] currentFingerprint = getFingerprint(attestationCertificates[0]);
Expand Down Expand Up @@ -952,6 +960,9 @@ private static void verify(final byte[] fingerprint,
addUsersWhenLocked = ?,
oemUnlockAllowed = ?,
systemUser = ?,
autoRebootMinutes = ?,
portSecurityMode = ?,
userCount = ?,
verifiedTimeLast = ?
WHERE fingerprint = ?""");
try {
Expand All @@ -974,8 +985,11 @@ private static void verify(final byte[] fingerprint,
update.bind(13, addUsersWhenLocked ? 1 : 0);
update.bind(14, oemUnlockAllowed ? 1 : 0);
update.bind(15, systemUser ? 1 : 0);
update.bind(16, now);
update.bind(17, fingerprint);
update.bind(16, securityStateExt.autoRebootMinutes);
update.bind(17, securityStateExt.portSecurityMode);
update.bind(18, securityStateExt.userCount);
update.bind(19, now);
update.bind(20, fingerprint);
update.step();
} finally {
update.dispose();
Expand Down Expand Up @@ -1005,10 +1019,13 @@ INSERT INTO Devices (
addUsersWhenLocked,
oemUnlockAllowed,
systemUser,
autoRebootMinutes,
portSecurityMode,
userCount,
verifiedTimeFirst,
verifiedTimeLast,
userId
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""");
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""");
try {
insert.bind(1, fingerprint);
insert.bind(2, encodeChain(DEFLATE_DICTIONARY_4, attestationCertificates));
Expand All @@ -1034,9 +1051,12 @@ INSERT INTO Devices (
insert.bind(18, addUsersWhenLocked ? 1 : 0);
insert.bind(19, oemUnlockAllowed ? 1 : 0);
insert.bind(20, systemUser ? 1 : 0);
insert.bind(21, now);
insert.bind(22, now);
insert.bind(23, userId);
insert.bind(21, securityStateExt.autoRebootMinutes);
insert.bind(22, securityStateExt.portSecurityMode);
insert.bind(23, securityStateExt.userCount);
insert.bind(24, now);
insert.bind(25, now);
insert.bind(26, userId);
insert.step();
} finally {
insert.dispose();
Expand All @@ -1061,8 +1081,11 @@ INSERT INTO Attestations (
adbEnabled,
addUsersWhenLocked,
oemUnlockAllowed,
systemUser
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""");
systemUser,
autoRebootMinutes,
portSecurityMode,
userCount
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""");
try {
insert.bind(1, fingerprint);
insert.bind(2, now);
Expand All @@ -1085,6 +1108,9 @@ INSERT INTO Attestations (
insert.bind(15, addUsersWhenLocked ? 1 : 0);
insert.bind(16, oemUnlockAllowed ? 1 : 0);
insert.bind(17, systemUser ? 1 : 0);
insert.bind(18, securityStateExt.autoRebootMinutes);
insert.bind(19, securityStateExt.portSecurityMode);
insert.bind(20, securityStateExt.userCount);

insert.step();
} finally {
Expand Down Expand Up @@ -1189,10 +1215,14 @@ static void verifySerialized(final byte[] attestationResult,
throw new GeneralSecurityException("invalid device administrator state");
}

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 @@ -1204,6 +1234,7 @@ static void verifySerialized(final byte[] attestationResult,

verify(fingerprint, pendingChallenges, userId, paired, deserializer.asReadOnlyBuffer(), signature,
certificates, userProfileSecure, accessibility, deviceAdmin, deviceAdminNonSystem,
adbEnabled, addUsersWhenLocked, enrolledBiometrics, oemUnlockAllowed, systemUser);
adbEnabled, addUsersWhenLocked, enrolledBiometrics, oemUnlockAllowed, systemUser,
securityStateExt);
}
}
164 changes: 158 additions & 6 deletions src/main/java/app/attestation/server/AttestationServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ 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)),
autoRebootMinutes INTEGER NOT NULL CHECK (autoRebootMinutes in (-2, -1) OR autoRebootMinutes >= 0),
portSecurityMode INTEGER NOT NULL CHECK (portSecurityMode in (-2, -1) OR portSecurityMode >= 0),
userCount INTEGER NOT NULL CHECK (userCount in (-2, -1) OR userCount >= 1),
verifiedTimeFirst INTEGER NOT NULL,
verifiedTimeLast INTEGER NOT NULL,
expiredTimeLast INTEGER,
Expand Down Expand Up @@ -261,7 +264,10 @@ deviceAdmin INTEGER NOT NULL CHECK (deviceAdmin in (0, 1, 2)),
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))
systemUser INTEGER NOT NULL CHECK (systemUser in (0, 1)),
autoRebootMinutes INTEGER NOT NULL CHECK (autoRebootMinutes in (-2, -1) OR autoRebootMinutes >= 0),
portSecurityMode INTEGER NOT NULL CHECK (portSecurityMode in (-2, -1) OR portSecurityMode >= 0),
userCount INTEGER NOT NULL CHECK (userCount in (-2, -1) OR userCount >= 1)
) STRICT""";

private static final String CREATE_ATTESTATION_INDICES = """
Expand Down Expand Up @@ -575,6 +581,140 @@ INSERT INTO Attestations (
logger.info("Migrated to schema version: " + userVersion);
}

// add failureAlertTime column to Devices
targetUserVersion = 15;
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,
autoRebootMinutes,
portSecurityMode,
userCount,
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,
-1,
-1,
-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,
autoRebootMinutes,
portSecurityMode,
userCount
) SELECT
id,
fingerprint,
time,
strong,
osVersion,
osPatchLevel,
vendorPatchLevel,
bootPatchLevel,
verifiedBootHash,
appVersion,
userProfileSecure,
enrolledBiometrics,
accessibility,
deviceAdmin,
adbEnabled,
addUsersWhenLocked,
oemUnlockAllowed,
systemUser,
-1,
-1,
-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();
Expand Down Expand Up @@ -1392,6 +1532,9 @@ private static void writeDevicesJson(final HttpExchange exchange, final long use
addUsersWhenLocked,
oemUnlockAllowed,
systemUser,
autoRebootMinutes,
portSecurityMode,
userCount,
verifiedTimeFirst,
verifiedTimeLast,
(SELECT min(id) FROM Attestations WHERE Attestations.fingerprint = Devices.fingerprint),
Expand Down Expand Up @@ -1460,10 +1603,13 @@ 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));
device.add("verifiedTimeFirst", select.columnLong(20));
device.add("verifiedTimeLast", select.columnLong(21));
device.add("minId", select.columnLong(22));
device.add("maxId", select.columnLong(23));
device.add("autoRebootMinutes", select.columnInt(20));
device.add("portSecurityMode", select.columnInt(21));
device.add("userCount", select.columnInt(22));
device.add("verifiedTimeFirst", select.columnLong(23));
device.add("verifiedTimeLast", select.columnLong(24));
device.add("minId", select.columnLong(25));
device.add("maxId", select.columnLong(26));
devices.add(device);
}
} finally {
Expand Down Expand Up @@ -1533,7 +1679,10 @@ private static void writeAttestationHistoryJson(final HttpExchange exchange, fin
Attestations.adbEnabled,
Attestations.addUsersWhenLocked,
Attestations.oemUnlockAllowed,
Attestations.systemUser
Attestations.systemUser,
Attestations.autoRebootMinutes,
Attestations.portSecurityMode,
Attestations.userCount
FROM Attestations INNER JOIN Devices ON
Attestations.fingerprint = Devices.fingerprint
WHERE Devices.fingerprint = ? AND userid = ?
Expand Down Expand Up @@ -1568,6 +1717,9 @@ 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));
attestation.add("autoRebootMinutes", history.columnInt(17));
attestation.add("portSecurityMode", history.columnInt(18));
attestation.add("userCount", history.columnInt(19));
attestations.add(attestation);
rowCount += 1;
}
Expand Down
Loading

0 comments on commit dee63be

Please sign in to comment.