Merge "Use rootAlias to index chosen cert and its version." into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
52bc5f2ae1
@@ -19,10 +19,12 @@ package com.android.server.locksettings.recoverablekeystore;
|
||||
import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_LOCKSCREEN;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.security.keystore.recovery.KeyDerivationParams;
|
||||
import android.security.keystore.recovery.KeyChainProtectionParams;
|
||||
import android.security.keystore.recovery.KeyChainSnapshot;
|
||||
import android.security.keystore.recovery.KeyDerivationParams;
|
||||
import android.security.keystore.recovery.TrustedRootCertificates;
|
||||
import android.security.keystore.recovery.WrappedApplicationKey;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -185,8 +187,12 @@ public class KeySyncTask implements Runnable {
|
||||
}
|
||||
|
||||
PublicKey publicKey;
|
||||
String rootCertAlias =
|
||||
mRecoverableKeyStoreDb.getActiveRootOfTrust(mUserId, recoveryAgentUid);
|
||||
|
||||
rootCertAlias = replaceEmptyValueWithSecureDefault(rootCertAlias);
|
||||
CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId,
|
||||
recoveryAgentUid);
|
||||
recoveryAgentUid, rootCertAlias);
|
||||
if (certPath != null) {
|
||||
Log.d(TAG, "Using the public key in stored CertPath for syncing");
|
||||
publicKey = certPath.getCertificates().get(0).getPublicKey();
|
||||
@@ -206,6 +212,14 @@ public class KeySyncTask implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
// The only place in this class which uses credential value
|
||||
if (!TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS.equals(
|
||||
rootCertAlias)) {
|
||||
// TODO: allow only whitelisted LSKF usage
|
||||
Log.w(TAG, "Untrusted root certificate is used by recovery agent "
|
||||
+ recoveryAgentUid);
|
||||
}
|
||||
|
||||
byte[] salt = generateSalt();
|
||||
byte[] localLskfHash = hashCredentials(salt, mCredential);
|
||||
|
||||
@@ -225,6 +239,8 @@ public class KeySyncTask implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: filter raw keys based on the root of trust.
|
||||
// It is the only place in the class where raw key material is used.
|
||||
SecretKey recoveryKey;
|
||||
try {
|
||||
recoveryKey = generateRecoveryKey();
|
||||
@@ -451,4 +467,14 @@ public class KeySyncTask implements Runnable {
|
||||
}
|
||||
return keyEntries;
|
||||
}
|
||||
|
||||
private @NonNull String replaceEmptyValueWithSecureDefault(
|
||||
@Nullable String rootCertificateAlias) {
|
||||
if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
|
||||
Log.e(TAG, "rootCertificateAlias is null or empty");
|
||||
// Use the default Google Key Vault Service CA certificate if the alias is not provided
|
||||
rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
|
||||
}
|
||||
return rootCertificateAlias;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,20 @@ public class RecoverableKeyStoreManager {
|
||||
checkRecoverKeyStorePermission();
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
int uid = Binder.getCallingUid();
|
||||
rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
|
||||
|
||||
// Always set active alias to the argument of the last call to initRecoveryService method,
|
||||
// even if cert file is incorrect.
|
||||
String activeRootAlias = mDatabase.getActiveRootOfTrust(userId, uid);
|
||||
if (activeRootAlias == null) {
|
||||
Log.d(TAG, "Root of trust for recovery agent + " + uid
|
||||
+ " is assigned for the first time to " + rootCertificateAlias);
|
||||
mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
|
||||
} else if (!activeRootAlias.equals(rootCertificateAlias)) {
|
||||
Log.i(TAG, "Root of trust for recovery agent " + uid + " is changed to "
|
||||
+ rootCertificateAlias + " from " + activeRootAlias);
|
||||
mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
|
||||
}
|
||||
|
||||
CertXml certXml;
|
||||
try {
|
||||
@@ -194,7 +208,7 @@ public class RecoverableKeyStoreManager {
|
||||
|
||||
// Check serial number
|
||||
long newSerial = certXml.getSerial();
|
||||
Long oldSerial = mDatabase.getRecoveryServiceCertSerial(userId, uid);
|
||||
Long oldSerial = mDatabase.getRecoveryServiceCertSerial(userId, uid, rootCertificateAlias);
|
||||
if (oldSerial != null && oldSerial >= newSerial) {
|
||||
if (oldSerial == newSerial) {
|
||||
Log.i(TAG, "The cert file serial number is the same, so skip updating.");
|
||||
@@ -217,13 +231,16 @@ public class RecoverableKeyStoreManager {
|
||||
ERROR_INVALID_CERTIFICATE, "Failed to validate certificate.");
|
||||
}
|
||||
|
||||
boolean wasInitialized = mDatabase.getRecoveryServiceCertPath(userId, uid) != null;
|
||||
boolean wasInitialized = mDatabase.getRecoveryServiceCertPath(userId, uid,
|
||||
rootCertificateAlias) != null;
|
||||
|
||||
// Save the chosen and validated certificate into database
|
||||
try {
|
||||
Log.d(TAG, "Saving the randomly chosen endpoint certificate to database");
|
||||
if (mDatabase.setRecoveryServiceCertPath(userId, uid, certPath) > 0) {
|
||||
mDatabase.setRecoveryServiceCertSerial(userId, uid, newSerial);
|
||||
if (mDatabase.setRecoveryServiceCertPath(userId, uid, rootCertificateAlias,
|
||||
certPath) > 0) {
|
||||
mDatabase.setRecoveryServiceCertSerial(userId, uid, rootCertificateAlias,
|
||||
newSerial);
|
||||
if (wasInitialized) {
|
||||
Log.i(TAG, "This is a certificate change. Snapshot pending.");
|
||||
mDatabase.setShouldCreateSnapshot(userId, uid, true);
|
||||
@@ -253,9 +270,7 @@ public class RecoverableKeyStoreManager {
|
||||
@NonNull byte[] recoveryServiceSigFile)
|
||||
throws RemoteException {
|
||||
checkRecoverKeyStorePermission();
|
||||
if (rootCertificateAlias == null) {
|
||||
Log.e(TAG, "rootCertificateAlias is null");
|
||||
}
|
||||
rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
|
||||
Preconditions.checkNotNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
|
||||
Preconditions.checkNotNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
|
||||
|
||||
@@ -509,9 +524,7 @@ public class RecoverableKeyStoreManager {
|
||||
@NonNull List<KeyChainProtectionParams> secrets)
|
||||
throws RemoteException {
|
||||
checkRecoverKeyStorePermission();
|
||||
if (rootCertificateAlias == null) {
|
||||
Log.e(TAG, "rootCertificateAlias is null");
|
||||
}
|
||||
rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
|
||||
Preconditions.checkNotNull(sessionId, "invalid session");
|
||||
Preconditions.checkNotNull(verifierCertPath, "verifierCertPath is null");
|
||||
Preconditions.checkNotNull(vaultParams, "vaultParams is null");
|
||||
@@ -953,11 +966,7 @@ public class RecoverableKeyStoreManager {
|
||||
}
|
||||
|
||||
private X509Certificate getRootCertificate(String rootCertificateAlias) throws RemoteException {
|
||||
if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
|
||||
// Use the default Google Key Vault Service CA certificate if the alias is not provided
|
||||
rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
|
||||
}
|
||||
|
||||
rootCertificateAlias = replaceEmptyValueWithSecureDefault(rootCertificateAlias);
|
||||
X509Certificate rootCertificate =
|
||||
TrustedRootCertificates.getRootCertificate(rootCertificateAlias);
|
||||
if (rootCertificate == null) {
|
||||
@@ -967,6 +976,16 @@ public class RecoverableKeyStoreManager {
|
||||
return rootCertificate;
|
||||
}
|
||||
|
||||
private @NonNull String replaceEmptyValueWithSecureDefault(
|
||||
@Nullable String rootCertificateAlias) {
|
||||
if (rootCertificateAlias == null || rootCertificateAlias.isEmpty()) {
|
||||
Log.e(TAG, "rootCertificateAlias is null or empty");
|
||||
// Use the default Google Key Vault Service CA certificate if the alias is not provided
|
||||
rootCertificateAlias = TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
|
||||
}
|
||||
return rootCertificateAlias;
|
||||
}
|
||||
|
||||
private void checkRecoverKeyStorePermission() {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.RECOVER_KEYSTORE,
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.util.Log;
|
||||
import com.android.server.locksettings.recoverablekeystore.WrappedKey;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -385,13 +386,15 @@ public class RecoverableKeyStoreDb {
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initializes the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @return The value that were previously set, or null if there's none.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public Long getRecoveryServiceCertSerial(int userId, int uid) {
|
||||
return getLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL);
|
||||
public Long getRecoveryServiceCertSerial(int userId, int uid, @NonNull String rootAlias) {
|
||||
return getLong(userId, uid, rootAlias,
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,13 +402,16 @@ public class RecoverableKeyStoreDb {
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initializes the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @param serial The serial number contained in the XML file for recovery service certificates.
|
||||
* @return The primary key of the inserted row, or -1 if failed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public long setRecoveryServiceCertSerial(int userId, int uid, long serial) {
|
||||
return setLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, serial);
|
||||
public long setRecoveryServiceCertSerial(int userId, int uid, @NonNull String rootAlias,
|
||||
long serial) {
|
||||
return setLong(userId, uid, rootAlias, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL,
|
||||
serial);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -413,13 +419,15 @@ public class RecoverableKeyStoreDb {
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initializes the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @return The value that were previously set, or null if there's none.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public CertPath getRecoveryServiceCertPath(int userId, int uid) {
|
||||
byte[] bytes = getBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH);
|
||||
public CertPath getRecoveryServiceCertPath(int userId, int uid, @NonNull String rootAlias) {
|
||||
byte[] bytes = getBytes(userId, uid, rootAlias,
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH);
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -440,16 +448,17 @@ public class RecoverableKeyStoreDb {
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initializes the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @param certPath The certificate path of the recovery service.
|
||||
* @return The primary key of the inserted row, or -1 if failed.
|
||||
* @hide
|
||||
*/
|
||||
public long setRecoveryServiceCertPath(int userId, int uid, CertPath certPath) throws
|
||||
CertificateEncodingException {
|
||||
public long setRecoveryServiceCertPath(int userId, int uid, @NonNull String rootAlias,
|
||||
CertPath certPath) throws CertificateEncodingException {
|
||||
if (certPath.getCertificates().size() == 0) {
|
||||
throw new CertificateEncodingException("No certificate contained in the cert path.");
|
||||
}
|
||||
return setBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH,
|
||||
return setBytes(userId, uid, rootAlias, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH,
|
||||
certPath.getEncoded(CERT_PATH_ENCODING));
|
||||
}
|
||||
|
||||
@@ -607,6 +616,85 @@ public class RecoverableKeyStoreDb {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Active root of trust for the recovery agent.
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @return The primary key of the updated row, or -1 if failed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public long setActiveRootOfTrust(int userId, int uid, @Nullable String rootAlias) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, rootAlias);
|
||||
String selection =
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
|
||||
ensureRecoveryServiceMetadataEntryExists(userId, uid);
|
||||
return db.update(RecoveryServiceMetadataEntry.TABLE_NAME, values,
|
||||
selection, new String[] {String.valueOf(userId), String.valueOf(uid)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Active root of trust for the recovery agent.
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initialized the local recovery components.
|
||||
* @return Active root of trust alias of null if it was not set
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @Nullable String getActiveRootOfTrust(int userId, int uid) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
|
||||
|
||||
String[] projection = {
|
||||
RecoveryServiceMetadataEntry._ID,
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID,
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_UID,
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST};
|
||||
String selection =
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ? AND "
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " = ?";
|
||||
String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid)};
|
||||
|
||||
try (
|
||||
Cursor cursor = db.query(
|
||||
RecoveryServiceMetadataEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArguments,
|
||||
/*groupBy=*/ null,
|
||||
/*having=*/ null,
|
||||
/*orderBy=*/ null)
|
||||
) {
|
||||
int count = cursor.getCount();
|
||||
if (count == 0) {
|
||||
return null;
|
||||
}
|
||||
if (count > 1) {
|
||||
Log.wtf(TAG,
|
||||
String.format(Locale.US,
|
||||
"%d deviceId entries found for userId=%d uid=%d. "
|
||||
+ "Should only ever be 0 or 1.", count, userId, uid));
|
||||
return null;
|
||||
}
|
||||
cursor.moveToFirst();
|
||||
int idx = cursor.getColumnIndexOrThrow(
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST);
|
||||
if (cursor.isNull(idx)) {
|
||||
return null;
|
||||
}
|
||||
String result = cursor.getString(idx);
|
||||
if (TextUtils.isEmpty(result)) {
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the counterId
|
||||
*
|
||||
@@ -874,7 +962,6 @@ public class RecoverableKeyStoreDb {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
private long setBytes(int userId, int uid, String key, byte[] value) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
@@ -889,6 +976,176 @@ public class RecoverableKeyStoreDb {
|
||||
RecoveryServiceMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given binary value from the database.
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initialized the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @param key from {@code RootOfTrustEntry}
|
||||
* @return The value that were previously set, or null if there's none.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private byte[] getBytes(int userId, int uid, String rootAlias, String key) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
|
||||
|
||||
String[] projection = {
|
||||
RootOfTrustEntry._ID,
|
||||
RootOfTrustEntry.COLUMN_NAME_USER_ID,
|
||||
RootOfTrustEntry.COLUMN_NAME_UID,
|
||||
RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS,
|
||||
key};
|
||||
String selection =
|
||||
RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
|
||||
String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
|
||||
|
||||
try (
|
||||
Cursor cursor = db.query(
|
||||
RootOfTrustEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArguments,
|
||||
/*groupBy=*/ null,
|
||||
/*having=*/ null,
|
||||
/*orderBy=*/ null)
|
||||
) {
|
||||
int count = cursor.getCount();
|
||||
if (count == 0) {
|
||||
return null;
|
||||
}
|
||||
if (count > 1) {
|
||||
Log.wtf(TAG,
|
||||
String.format(Locale.US,
|
||||
"%d entries found for userId=%d uid=%d. "
|
||||
+ "Should only ever be 0 or 1.", count, userId, uid));
|
||||
return null;
|
||||
}
|
||||
cursor.moveToFirst();
|
||||
int idx = cursor.getColumnIndexOrThrow(key);
|
||||
if (cursor.isNull(idx)) {
|
||||
return null;
|
||||
} else {
|
||||
return cursor.getBlob(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a binary value in the database.
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initialized the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @param key defined in {@code RootOfTrustEntry}
|
||||
* @param value new value.
|
||||
* @return The primary key of the inserted row, or -1 if failed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private long setBytes(int userId, int uid, String rootAlias, String key, byte[] value) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(key, value);
|
||||
String selection =
|
||||
RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
|
||||
String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
|
||||
|
||||
ensureRootOfTrustEntryExists(userId, uid, rootAlias);
|
||||
return db.update(
|
||||
RootOfTrustEntry.TABLE_NAME, values, selection, selectionArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given long value from the database.
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initialized the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @param key from {@code RootOfTrustEntry}
|
||||
* @return The value that were previously set, or null if there's none.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private Long getLong(int userId, int uid, String rootAlias, String key) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
|
||||
|
||||
String[] projection = {
|
||||
RootOfTrustEntry._ID,
|
||||
RootOfTrustEntry.COLUMN_NAME_USER_ID,
|
||||
RootOfTrustEntry.COLUMN_NAME_UID,
|
||||
RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS,
|
||||
key};
|
||||
String selection =
|
||||
RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
|
||||
String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
|
||||
|
||||
try (
|
||||
Cursor cursor = db.query(
|
||||
RootOfTrustEntry.TABLE_NAME,
|
||||
projection,
|
||||
selection,
|
||||
selectionArguments,
|
||||
/*groupBy=*/ null,
|
||||
/*having=*/ null,
|
||||
/*orderBy=*/ null)
|
||||
) {
|
||||
int count = cursor.getCount();
|
||||
if (count == 0) {
|
||||
return null;
|
||||
}
|
||||
if (count > 1) {
|
||||
Log.wtf(TAG,
|
||||
String.format(Locale.US,
|
||||
"%d entries found for userId=%d uid=%d. "
|
||||
+ "Should only ever be 0 or 1.", count, userId, uid));
|
||||
return null;
|
||||
}
|
||||
cursor.moveToFirst();
|
||||
int idx = cursor.getColumnIndexOrThrow(key);
|
||||
if (cursor.isNull(idx)) {
|
||||
return null;
|
||||
} else {
|
||||
return cursor.getLong(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a long value in the database.
|
||||
*
|
||||
* @param userId The userId of the profile the application is running under.
|
||||
* @param uid The uid of the application who initialized the local recovery components.
|
||||
* @param rootAlias The root of trust alias.
|
||||
* @param key defined in {@code RootOfTrustEntry}
|
||||
* @param value new value.
|
||||
* @return The primary key of the inserted row, or -1 if failed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
|
||||
private long setLong(int userId, int uid, String rootAlias, String key, long value) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(key, value);
|
||||
String selection =
|
||||
RootOfTrustEntry.COLUMN_NAME_USER_ID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_UID + " = ? AND "
|
||||
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " = ?";
|
||||
String[] selectionArguments = {Integer.toString(userId), Integer.toString(uid), rootAlias};
|
||||
|
||||
ensureRootOfTrustEntryExists(userId, uid, rootAlias);
|
||||
return db.update(
|
||||
RootOfTrustEntry.TABLE_NAME, values, selection, selectionArguments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an empty row in the recovery service metadata table if such a row doesn't exist for
|
||||
* the given userId and uid, so db.update will succeed.
|
||||
@@ -902,6 +1159,20 @@ public class RecoverableKeyStoreDb {
|
||||
values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty row in the root of trust table if such a row doesn't exist for
|
||||
* the given userId and uid, so db.update will succeed.
|
||||
*/
|
||||
private void ensureRootOfTrustEntryExists(int userId, int uid, String rootAlias) {
|
||||
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_USER_ID, userId);
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_UID, uid);
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, rootAlias);
|
||||
db.insertWithOnConflict(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null,
|
||||
values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all open connections to the database.
|
||||
*/
|
||||
|
||||
@@ -230,16 +230,19 @@ class RecoverableKeyStoreDbContract {
|
||||
|
||||
/**
|
||||
* The public key of the recovery service.
|
||||
* Deprecated.
|
||||
*/
|
||||
static final String COLUMN_NAME_PUBLIC_KEY = "public_key";
|
||||
|
||||
/**
|
||||
* The certificate path of the recovery service.
|
||||
* Deprecated.
|
||||
*/
|
||||
static final String COLUMN_NAME_CERT_PATH = "cert_path";
|
||||
|
||||
/**
|
||||
* The serial number contained in the certificate XML file of the recovery service.
|
||||
* Deprecated.
|
||||
*/
|
||||
static final String COLUMN_NAME_CERT_SERIAL = "cert_serial";
|
||||
|
||||
@@ -257,5 +260,42 @@ class RecoverableKeyStoreDbContract {
|
||||
* The server parameters of the recovery service.
|
||||
*/
|
||||
static final String COLUMN_NAME_SERVER_PARAMS = "server_params";
|
||||
|
||||
/**
|
||||
* Active root of trust
|
||||
*/
|
||||
static final String COLUMN_NAME_ACTIVE_ROOT_OF_TRUST = "active_root_of_trust";
|
||||
}
|
||||
|
||||
/**
|
||||
* Table data for given recovery agent and root of trust pair.
|
||||
*/
|
||||
static class RootOfTrustEntry implements BaseColumns {
|
||||
static final String TABLE_NAME = "root_of_trust";
|
||||
|
||||
/**
|
||||
* The user id of the profile the application is running under.
|
||||
*/
|
||||
static final String COLUMN_NAME_USER_ID = "user_id";
|
||||
|
||||
/**
|
||||
* The uid of the application that initializes the local recovery components.
|
||||
*/
|
||||
static final String COLUMN_NAME_UID = "uid";
|
||||
|
||||
/**
|
||||
* Root of trust alias
|
||||
*/
|
||||
static final String COLUMN_NAME_ROOT_ALIAS = "root_alias";
|
||||
|
||||
/**
|
||||
* The certificate path of the recovery service.
|
||||
*/
|
||||
static final String COLUMN_NAME_CERT_PATH = "cert_path";
|
||||
|
||||
/**
|
||||
* The serial number contained in the certificate XML file of the recovery service.
|
||||
*/
|
||||
static final String COLUMN_NAME_CERT_SERIAL = "cert_serial";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.util.Log;
|
||||
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
|
||||
|
||||
/**
|
||||
@@ -31,7 +32,7 @@ import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKe
|
||||
class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
|
||||
private static final String TAG = "RecoverableKeyStoreDbHp";
|
||||
|
||||
static final int DATABASE_VERSION = 3;
|
||||
static final int DATABASE_VERSION = 4;
|
||||
private static final String DATABASE_NAME = "recoverablekeystore.db";
|
||||
|
||||
private static final String SQL_CREATE_KEYS_ENTRY =
|
||||
@@ -61,6 +62,7 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST + " TEXT,"
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
|
||||
@@ -71,6 +73,19 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + ","
|
||||
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
|
||||
|
||||
private static final String SQL_CREATE_ROOT_OF_TRUST_ENTRY =
|
||||
"CREATE TABLE " + RootOfTrustEntry.TABLE_NAME + " ("
|
||||
+ RootOfTrustEntry._ID + " INTEGER PRIMARY KEY,"
|
||||
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + " INTEGER,"
|
||||
+ RootOfTrustEntry.COLUMN_NAME_UID + " INTEGER,"
|
||||
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " TEST,"
|
||||
+ RootOfTrustEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
|
||||
+ RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
|
||||
+ "UNIQUE("
|
||||
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + ","
|
||||
+ RootOfTrustEntry.COLUMN_NAME_UID + ","
|
||||
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + "))";
|
||||
|
||||
private static final String SQL_DELETE_KEYS_ENTRY =
|
||||
"DROP TABLE IF EXISTS " + KeysEntry.TABLE_NAME;
|
||||
|
||||
@@ -80,6 +95,9 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
|
||||
private static final String SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY =
|
||||
"DROP TABLE IF EXISTS " + RecoveryServiceMetadataEntry.TABLE_NAME;
|
||||
|
||||
private static final String SQL_DELETE_ROOT_OF_TRUST_ENTRY =
|
||||
"DROP TABLE IF EXISTS " + RootOfTrustEntry.TABLE_NAME;
|
||||
|
||||
RecoverableKeyStoreDbHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
@@ -89,21 +107,44 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(SQL_CREATE_KEYS_ENTRY);
|
||||
db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
|
||||
db.execSQL(SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY);
|
||||
db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.e(TAG, "Recreating recoverablekeystore after unexpected version downgrade.");
|
||||
dropAllKnownTables(db); // Wipe database.
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion < 2) {
|
||||
db.execSQL(SQL_DELETE_KEYS_ENTRY);
|
||||
db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
|
||||
db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
|
||||
dropAllKnownTables(db); // Wipe database.
|
||||
onCreate(db);
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldVersion < 3) {
|
||||
if (oldVersion < 3 && newVersion >= 3) {
|
||||
upgradeDbForVersion3(db);
|
||||
oldVersion = 3;
|
||||
}
|
||||
|
||||
if (oldVersion < 4 && newVersion >= 4) {
|
||||
upgradeDbForVersion4(db);
|
||||
oldVersion = 4;
|
||||
}
|
||||
|
||||
if (oldVersion != newVersion) {
|
||||
Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
|
||||
}
|
||||
}
|
||||
|
||||
private void dropAllKnownTables(SQLiteDatabase db) {
|
||||
db.execSQL(SQL_DELETE_KEYS_ENTRY);
|
||||
db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
|
||||
db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
|
||||
db.execSQL(SQL_DELETE_ROOT_OF_TRUST_ENTRY);
|
||||
}
|
||||
|
||||
private void upgradeDbForVersion3(SQLiteDatabase db) {
|
||||
@@ -115,6 +156,16 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
|
||||
null);
|
||||
}
|
||||
|
||||
private void upgradeDbForVersion4(SQLiteDatabase db) {
|
||||
Log.d(TAG, "Updating recoverable keystore database to version 4");
|
||||
// Add new table with two columns for cert path and cert serial number.
|
||||
db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
|
||||
// adds column to store root of trust currently used by the recovery agent
|
||||
addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
|
||||
RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, "TEXT",
|
||||
/*defaultStr=*/ null);
|
||||
}
|
||||
|
||||
private static void addColumnToTable(
|
||||
SQLiteDatabase db, String tableName, String column, String columnType,
|
||||
String defaultStr) {
|
||||
|
||||
@@ -74,6 +74,7 @@ import javax.crypto.SecretKey;
|
||||
public class KeySyncTaskTest {
|
||||
private static final String KEY_ALGORITHM = "AES";
|
||||
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
|
||||
private static final String TEST_ROOT_CERT_ALIAS = "trusted_root";
|
||||
private static final String WRAPPING_KEY_ALIAS = "KeySyncTaskTest/WrappingKey";
|
||||
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
|
||||
private static final int TEST_USER_ID = 1000;
|
||||
@@ -111,6 +112,11 @@ public class KeySyncTaskTest {
|
||||
new int[] {TYPE_LOCKSCREEN});
|
||||
mRecoverableKeyStoreDb.setRecoverySecretTypes(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
|
||||
new int[] {TYPE_LOCKSCREEN});
|
||||
|
||||
mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID,
|
||||
TEST_ROOT_CERT_ALIAS);
|
||||
mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
|
||||
TEST_ROOT_CERT_ALIAS);
|
||||
mRecoverySnapshotStorage = new RecoverySnapshotStorage();
|
||||
|
||||
mKeySyncTask = new KeySyncTask(
|
||||
@@ -247,7 +253,7 @@ public class KeySyncTaskTest {
|
||||
TEST_APP_KEY_ALIAS,
|
||||
WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
|
||||
mKeySyncTask.run();
|
||||
@@ -263,7 +269,7 @@ public class KeySyncTaskTest {
|
||||
mRecoverableKeyStoreDb.setPlatformKeyGenerationId(TEST_USER_ID, TEST_GENERATION_ID);
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
|
||||
mKeySyncTask.run();
|
||||
|
||||
@@ -273,7 +279,7 @@ public class KeySyncTaskTest {
|
||||
@Test
|
||||
public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
|
||||
mRecoverableKeyStoreDb.setServerParams(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
|
||||
@@ -320,7 +326,7 @@ public class KeySyncTaskTest {
|
||||
@Test
|
||||
public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath() throws Exception {
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setServerParams(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
@@ -339,7 +345,7 @@ public class KeySyncTaskTest {
|
||||
@Test
|
||||
public void run_setsCorrectSnapshotVersion() throws Exception {
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
|
||||
@@ -358,7 +364,7 @@ public class KeySyncTaskTest {
|
||||
@Test
|
||||
public void run_recreatesMissingSnapshot() throws Exception {
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
|
||||
@@ -388,7 +394,7 @@ public class KeySyncTaskTest {
|
||||
mPlatformKeyManager);
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
SecretKey applicationKey =
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
@@ -414,7 +420,7 @@ public class KeySyncTaskTest {
|
||||
mPlatformKeyManager);
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
SecretKey applicationKey =
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
@@ -441,7 +447,7 @@ public class KeySyncTaskTest {
|
||||
mPlatformKeyManager);
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
SecretKey applicationKey =
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
@@ -457,9 +463,9 @@ public class KeySyncTaskTest {
|
||||
@Test
|
||||
public void run_sendsEncryptedKeysWithTwoRegisteredAgents() throws Exception {
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
@@ -479,9 +485,9 @@ public class KeySyncTaskTest {
|
||||
new int[] {1000});
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(true);
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
@@ -496,9 +502,9 @@ public class KeySyncTaskTest {
|
||||
@Test
|
||||
public void run_notifiesNonregisteredAgent() throws Exception {
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TestData.CERT_PATH_1);
|
||||
TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
|
||||
when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID2)).thenReturn(false);
|
||||
addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
|
||||
|
||||
@@ -44,9 +44,10 @@ import android.security.keystore.AndroidKeyStoreProvider;
|
||||
import android.security.keystore.AndroidKeyStoreSecretKey;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyProperties;
|
||||
import android.security.keystore.recovery.KeyDerivationParams;
|
||||
import android.security.keystore.recovery.KeyChainProtectionParams;
|
||||
import android.security.keystore.recovery.KeyDerivationParams;
|
||||
import android.security.keystore.recovery.RecoveryCertPath;
|
||||
import android.security.keystore.recovery.TrustedRootCertificates;
|
||||
import android.security.keystore.recovery.WrappedApplicationKey;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
@@ -90,6 +91,8 @@ public class RecoverableKeyStoreManagerTest {
|
||||
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
|
||||
|
||||
private static final String ROOT_CERTIFICATE_ALIAS = "";
|
||||
private static final String DEFAULT_ROOT_CERT_ALIAS =
|
||||
TrustedRootCertificates.GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_ALIAS;
|
||||
private static final String TEST_SESSION_ID = "karlin";
|
||||
private static final byte[] TEST_PUBLIC_KEY = new byte[] {
|
||||
(byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
|
||||
@@ -143,7 +146,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
private static final String KEY_ALGORITHM = "AES";
|
||||
private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
|
||||
private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyStoreManagerTest/WrappingKey";
|
||||
private static final String TEST_ROOT_CERT_ALIAS = "";
|
||||
private static final String TEST_DEFAULT_ROOT_CERT_ALIAS = "";
|
||||
private static final KeyChainProtectionParams TEST_PROTECTION_PARAMS =
|
||||
new KeyChainProtectionParams.Builder()
|
||||
.setUserSecretType(TYPE_LOCKSCREEN)
|
||||
@@ -299,10 +302,10 @@ public class RecoverableKeyStoreManagerTest {
|
||||
TestData.getCertXmlWithSerial(certSerial));
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
|
||||
TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(
|
||||
certSerial);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(certSerial);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
|
||||
}
|
||||
|
||||
@@ -328,7 +331,8 @@ public class RecoverableKeyStoreManagerTest {
|
||||
byte[] modifiedCertXml = TestData.getCertXml();
|
||||
modifiedCertXml[modifiedCertXml.length - 50] ^= 1; // Flip a bit in the certificate
|
||||
try {
|
||||
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, modifiedCertXml);
|
||||
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
|
||||
modifiedCertXml);
|
||||
fail("should have thrown");
|
||||
} catch (ServiceSpecificException e) {
|
||||
assertThat(e.getMessage()).contains("validate cert");
|
||||
@@ -346,8 +350,8 @@ public class RecoverableKeyStoreManagerTest {
|
||||
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
|
||||
TestData.getCertXmlWithSerial(certSerial + 1));
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid))
|
||||
.isEqualTo(certSerial + 1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(certSerial + 1);
|
||||
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
|
||||
}
|
||||
|
||||
@@ -362,8 +366,8 @@ public class RecoverableKeyStoreManagerTest {
|
||||
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
|
||||
TestData.getCertXmlWithSerial(certSerial - 1));
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid))
|
||||
.isEqualTo(certSerial);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(certSerial);
|
||||
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
|
||||
}
|
||||
|
||||
@@ -391,8 +395,10 @@ public class RecoverableKeyStoreManagerTest {
|
||||
mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, TEST_PUBLIC_KEY);
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNotNull();
|
||||
}
|
||||
|
||||
@@ -406,8 +412,8 @@ public class RecoverableKeyStoreManagerTest {
|
||||
ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml());
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
|
||||
TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
DEFAULT_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
|
||||
}
|
||||
|
||||
@@ -480,7 +486,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
public void startRecoverySessionWithCertPath_storesTheSessionInfo() throws Exception {
|
||||
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
|
||||
TEST_SESSION_ID,
|
||||
TEST_ROOT_CERT_ALIAS,
|
||||
TEST_DEFAULT_ROOT_CERT_ALIAS,
|
||||
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
|
||||
TEST_VAULT_PARAMS,
|
||||
TEST_VAULT_CHALLENGE,
|
||||
@@ -497,7 +503,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
public void startRecoverySessionWithCertPath_checksPermissionFirst() throws Exception {
|
||||
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
|
||||
TEST_SESSION_ID,
|
||||
TEST_ROOT_CERT_ALIAS,
|
||||
TEST_DEFAULT_ROOT_CERT_ALIAS,
|
||||
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
|
||||
TEST_VAULT_PARAMS,
|
||||
TEST_VAULT_CHALLENGE,
|
||||
@@ -601,7 +607,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
try {
|
||||
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
|
||||
TEST_SESSION_ID,
|
||||
TEST_ROOT_CERT_ALIAS,
|
||||
TEST_DEFAULT_ROOT_CERT_ALIAS,
|
||||
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
|
||||
TEST_VAULT_PARAMS,
|
||||
TEST_VAULT_CHALLENGE,
|
||||
@@ -620,7 +626,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
try {
|
||||
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
|
||||
TEST_SESSION_ID,
|
||||
TEST_ROOT_CERT_ALIAS,
|
||||
TEST_DEFAULT_ROOT_CERT_ALIAS,
|
||||
RecoveryCertPath.createRecoveryCertPath(TestData.CERT_PATH_1),
|
||||
vaultParams,
|
||||
TEST_VAULT_CHALLENGE,
|
||||
@@ -638,7 +644,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
try {
|
||||
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
|
||||
TEST_SESSION_ID,
|
||||
TEST_ROOT_CERT_ALIAS,
|
||||
TEST_DEFAULT_ROOT_CERT_ALIAS,
|
||||
RecoveryCertPath.createRecoveryCertPath(emptyCertPath),
|
||||
TEST_VAULT_PARAMS,
|
||||
TEST_VAULT_CHALLENGE,
|
||||
@@ -658,7 +664,7 @@ public class RecoverableKeyStoreManagerTest {
|
||||
try {
|
||||
mRecoverableKeyStoreManager.startRecoverySessionWithCertPath(
|
||||
TEST_SESSION_ID,
|
||||
TEST_ROOT_CERT_ALIAS,
|
||||
TEST_DEFAULT_ROOT_CERT_ALIAS,
|
||||
RecoveryCertPath.createRecoveryCertPath(shortCertPath),
|
||||
TEST_VAULT_PARAMS,
|
||||
TEST_VAULT_CHALLENGE,
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
|
||||
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
|
||||
|
||||
@SmallTest
|
||||
@@ -55,6 +56,7 @@ public class RecoverableKeyStoreDbHelperTest {
|
||||
private static final String TEST_SECRET_TYPES = "test-secret-types";
|
||||
private static final long TEST_COUNTER_ID = -3981205205038476415L;
|
||||
private static final byte[] TEST_SERVER_PARAMS = "test-server-params".getBytes(UTF_8);
|
||||
private static final String TEST_ROOT_ALIAS = "root_cert_alias";
|
||||
private static final byte[] TEST_CERT_PATH = "test-cert-path".getBytes(UTF_8);
|
||||
private static final long TEST_CERT_SERIAL = 1000L;
|
||||
|
||||
@@ -135,6 +137,32 @@ public class RecoverableKeyStoreDbHelperTest {
|
||||
checkAllColumns();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onUpgrade_v2_to_v3_to_v4() throws Exception {
|
||||
createV2Tables();
|
||||
|
||||
assertThat(isRootOfTrustTableAvailable()).isFalse(); // V2 doesn't have the table;
|
||||
|
||||
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2, /*newVersion=*/ 3);
|
||||
|
||||
assertThat(isRootOfTrustTableAvailable()).isFalse(); // V3 doesn't have the table;
|
||||
|
||||
mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3,
|
||||
RecoverableKeyStoreDbHelper.DATABASE_VERSION);
|
||||
checkAllColumns();
|
||||
}
|
||||
|
||||
private boolean isRootOfTrustTableAvailable() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_UID, TEST_UID);
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, TEST_ROOT_ALIAS);
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
|
||||
values.put(RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
|
||||
return mDatabase.insert(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
|
||||
> -1;
|
||||
}
|
||||
|
||||
private void checkAllColumns() throws Exception {
|
||||
// Check the table containing encrypted application keys
|
||||
ContentValues values = new ContentValues();
|
||||
@@ -165,6 +193,7 @@ public class RecoverableKeyStoreDbHelperTest {
|
||||
TEST_SNAPSHOT_VERSION);
|
||||
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT,
|
||||
TEST_SHOULD_CREATE_SNAPSHOT);
|
||||
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, TEST_ROOT_ALIAS);
|
||||
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY, TEST_PUBLIC_KEY);
|
||||
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES, TEST_SECRET_TYPES);
|
||||
values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID, TEST_COUNTER_ID);
|
||||
@@ -175,5 +204,8 @@ public class RecoverableKeyStoreDbHelperTest {
|
||||
mDatabase.insert(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
|
||||
values))
|
||||
.isGreaterThan(-1L);
|
||||
|
||||
// Check the table about recovery service and root of trust data introduced in V4
|
||||
assertThat(isRootOfTrustTableAvailable()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ import java.util.Map;
|
||||
public class RecoverableKeyStoreDbTest {
|
||||
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
|
||||
|
||||
private static final String TEST_ROOT_CERT_ALIAS = "trusted_root";
|
||||
private static final String TEST_ROOT_CERT_ALIAS2 = "another_trusted_root";
|
||||
|
||||
private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
|
||||
private File mDatabaseFile;
|
||||
|
||||
@@ -284,7 +287,8 @@ public class RecoverableKeyStoreDbTest {
|
||||
|
||||
Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
|
||||
assertThat(statuses).hasSize(3);
|
||||
assertThat(statuses).containsEntry(alias, RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
|
||||
assertThat(statuses).containsEntry(alias,
|
||||
RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
|
||||
assertThat(statuses).containsEntry(alias2, status);
|
||||
assertThat(statuses).containsEntry(alias3, status);
|
||||
|
||||
@@ -401,26 +405,53 @@ public class RecoverableKeyStoreDbTest {
|
||||
public void setRecoveryServiceCertPath_replaceOldValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_2);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
|
||||
TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
|
||||
TestData.CERT_PATH_2);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRecoveryServiceCertPath_updateValuesForCorrectRootCert() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
|
||||
TestData.CERT_PATH_1);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS2,
|
||||
TestData.CERT_PATH_1);
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS2)).isEqualTo(TestData.CERT_PATH_1);
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS2,
|
||||
TestData.CERT_PATH_2);
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS2)).isEqualTo(TestData.CERT_PATH_2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecoveryServiceCertPath_returnsNullIfNoValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecoveryServiceCertPath_returnsInsertedValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TEST_ROOT_CERT_ALIAS,
|
||||
TestData.CERT_PATH_1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(TestData.CERT_PATH_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -428,25 +459,50 @@ public class RecoverableKeyStoreDbTest {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 1L);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 3L);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(3L);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 1L);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 3L);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRecoveryServiceCertSerial_updateValuesForCorrectRootCert() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS, 1L);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS2, 1L);
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(1L);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS2)).isEqualTo(1L);
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, TEST_ROOT_CERT_ALIAS2, 3L);
|
||||
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(1L);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS2)).isEqualTo(3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecoveryServiceCertSerial_returnsNullIfNoValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isNull();
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS2)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRecoveryServiceCertSerial_returnsInsertedValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 1234L);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(
|
||||
1234L);
|
||||
mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS, 1234L);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid,
|
||||
TEST_ROOT_CERT_ALIAS)).isEqualTo(1234L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -479,6 +535,24 @@ public class RecoverableKeyStoreDbTest {
|
||||
assertThat(agents).contains(uid2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setActiveRootOfTrust_emptyDefaultValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setActiveRootOfTrust_updateValue() throws Exception {
|
||||
int userId = 12;
|
||||
int uid = 10009;
|
||||
mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root");
|
||||
assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo("root");
|
||||
|
||||
mRecoverableKeyStoreDb.setActiveRootOfTrust(userId, uid, "root2");
|
||||
assertThat(mRecoverableKeyStoreDb.getActiveRootOfTrust(userId, uid)).isEqualTo("root2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRecoverySecretTypes_emptyDefaultValue() throws Exception {
|
||||
int userId = 12;
|
||||
@@ -495,11 +569,9 @@ public class RecoverableKeyStoreDbTest {
|
||||
int[] types2 = new int[]{2};
|
||||
|
||||
mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
|
||||
types1);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(types1);
|
||||
mRecoverableKeyStoreDb.setRecoverySecretTypes(userId, uid, types2);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(
|
||||
types2);
|
||||
assertThat(mRecoverableKeyStoreDb.getRecoverySecretTypes(userId, uid)).isEqualTo(types2);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user