Continue to decrypt other application keys if one fails to decrypt

An exception will still be thrown if all the application keys fail to
decrypt.

Test: adb shell am instrument -w -e package \
com.android.server.locksettings.recoverablekeystore \
com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
Bug: 72932279
Change-Id: I95befcd46672b77380226e61369759de5617ecea
This commit is contained in:
Bo Zhu
2018-02-06 14:34:48 -08:00
parent ac5438c501
commit 4857cb50ce
2 changed files with 55 additions and 13 deletions

View File

@@ -519,11 +519,11 @@ public class RecoverableKeyStoreManager {
byte[] locallyEncryptedKey;
try {
// TODO: Remove the extraneous logging here
Log.e(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()",
Log.d(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()",
sessionEntry.getKeyClaimant()));
Log.e(TAG, constructLoggingMessage("sessionEntry.getVaultParams()",
Log.d(TAG, constructLoggingMessage("sessionEntry.getVaultParams()",
sessionEntry.getVaultParams()));
Log.e(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse));
Log.d(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse));
locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse(
sessionEntry.getKeyClaimant(),
sessionEntry.getVaultParams(),
@@ -543,9 +543,9 @@ public class RecoverableKeyStoreManager {
try {
// TODO: Remove the extraneous logging here
Log.e(TAG, constructLoggingMessage("sessionEntry.getLskfHash()",
Log.d(TAG, constructLoggingMessage("sessionEntry.getLskfHash()",
sessionEntry.getLskfHash()));
Log.e(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey));
Log.d(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey));
return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey);
} catch (InvalidKeyException e) {
Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e);
@@ -585,8 +585,8 @@ public class RecoverableKeyStoreManager {
try {
// TODO: Remove the extraneous logging here
Log.e(TAG, constructLoggingMessage("recoveryKey", recoveryKey));
Log.e(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial));
Log.d(TAG, constructLoggingMessage("recoveryKey", recoveryKey));
Log.d(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial));
byte[] keyMaterial =
KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial);
keyMaterialByAlias.put(alias, keyMaterial);
@@ -600,13 +600,16 @@ public class RecoverableKeyStoreManager {
throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
"Failed to recover key with alias '" + alias + "': " + e.getMessage());
} catch (AEADBadTagException e) {
// TODO: Remove the extraneous logging here
Log.e(TAG, "Got AEADBadTagException during decrypting application key with alias: "
+ alias, e);
throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
"Failed to recover key with alias '" + alias + "': " + e.getMessage());
// Ignore the exception to continue to recover the other application keys.
}
}
if (keyMaterialByAlias.isEmpty()) {
Log.e(TAG, "Failed to recover any of the application keys.");
throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
"Failed to recover any of the application keys.");
}
return keyMaterialByAlias;
}

View File

@@ -125,6 +125,7 @@ public class RecoverableKeyStoreManagerTest {
private static final byte[] RECOVERY_RESPONSE_HEADER =
"V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8);
private static final String TEST_ALIAS = "nick";
private static final String TEST_ALIAS2 = "bob";
private static final int RECOVERABLE_KEY_SIZE_BYTES = 32;
private static final int GENERATION_ID = 1;
private static final byte[] NONCE = getUtf8Bytes("nonce");
@@ -424,7 +425,7 @@ public class RecoverableKeyStoreManagerTest {
}
@Test
public void recoverKeys_throwsIfFailedToDecryptAnApplicationKey() throws Exception {
public void recoverKeys_throwsIfFailedToDecryptAllApplicationKeys() throws Exception {
mRecoverableKeyStoreManager.startRecoverySession(
TEST_SESSION_ID,
TEST_PUBLIC_KEY,
@@ -442,7 +443,7 @@ public class RecoverableKeyStoreManagerTest {
keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
WrappedApplicationKey badApplicationKey = new WrappedApplicationKey(
TEST_ALIAS,
randomBytes(32));
encryptedApplicationKey(randomRecoveryKey(), randomBytes(32)));
try {
mRecoverableKeyStoreManager.recoverKeys(
@@ -451,7 +452,7 @@ public class RecoverableKeyStoreManagerTest {
/*applicationKeys=*/ ImmutableList.of(badApplicationKey));
fail("should have thrown");
} catch (ServiceSpecificException e) {
assertThat(e.getMessage()).startsWith("Failed to recover key with alias 'nick'");
assertThat(e.getMessage()).startsWith("Failed to recover any of the application keys");
}
}
@@ -486,6 +487,44 @@ public class RecoverableKeyStoreManagerTest {
assertThat(recoveredKeys.get(TEST_ALIAS)).isEqualTo(applicationKeyBytes);
}
@Test
public void recoverKeys_worksOnOtherApplicationKeysIfOneDecryptionFails() throws Exception {
mRecoverableKeyStoreManager.startRecoverySession(
TEST_SESSION_ID,
TEST_PUBLIC_KEY,
TEST_VAULT_PARAMS,
TEST_VAULT_CHALLENGE,
ImmutableList.of(new KeyChainProtectionParams(
TYPE_LOCKSCREEN,
UI_FORMAT_PASSWORD,
KeyDerivationParams.createSha256Params(TEST_SALT),
TEST_SECRET)));
byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
.getKeyClaimant();
SecretKey recoveryKey = randomRecoveryKey();
byte[] encryptedClaimResponse = encryptClaimResponse(
keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
byte[] applicationKeyBytes1 = randomBytes(32);
byte[] applicationKeyBytes2 = randomBytes(32);
WrappedApplicationKey applicationKey1 = new WrappedApplicationKey(
TEST_ALIAS,
// Use a different recovery key here, so the decryption will fail
encryptedApplicationKey(randomRecoveryKey(), applicationKeyBytes1));
WrappedApplicationKey applicationKey2 = new WrappedApplicationKey(
TEST_ALIAS2,
encryptedApplicationKey(recoveryKey, applicationKeyBytes2));
Map<String, byte[]> recoveredKeys = mRecoverableKeyStoreManager.recoverKeys(
TEST_SESSION_ID,
encryptedClaimResponse,
ImmutableList.of(applicationKey1, applicationKey2));
assertThat(recoveredKeys).hasSize(1);
assertThat(recoveredKeys.get(TEST_ALIAS2)).isEqualTo(applicationKeyBytes2);
}
@Test
public void setSnapshotCreatedPendingIntent() throws Exception {
int uid = Binder.getCallingUid();