diff options
| author | 2017-12-27 10:53:58 +0000 | |
|---|---|---|
| committer | 2017-12-28 11:04:42 +0000 | |
| commit | aa3f4cad33c7143679d54938aae7a37749d7f035 (patch) | |
| tree | 7883ffbf2a6caf98e700f652db15fb8c9728ce99 | |
| parent | 7b27036950574a51edd6ade7b3c8d82b950b857a (diff) | |
Hook up using initialized public key in KeySyncTask
Not sure if this is correct, PTAL. We won't have a specific uid when
the phone is unlocked, only the userId. Should the public key be
uid-specific or just userId-specific?
Test: adb shell am instrument -w -e package com.android.server.locksettings.recoverablekeystore com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
Change-Id: Ic2ec442c8a283e747542fafa9d7b0462aa185532
4 files changed, 78 insertions, 32 deletions
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index f6f5e59ec159..6de2445e5dd7 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -69,7 +69,6 @@ public class KeySyncTask implements Runnable { private final int mCredentialType; private final String mCredential; private final PlatformKeyManager.Factory mPlatformKeyManagerFactory; - private final VaultKeySupplier mVaultKeySupplier; private final RecoverySnapshotStorage mRecoverySnapshotStorage; private final RecoverySnapshotListenersStorage mSnapshotListenersStorage; @@ -89,10 +88,7 @@ public class KeySyncTask implements Runnable { userId, credentialType, credential, - () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb, userId), - () -> { - throw new UnsupportedOperationException("Not implemented vault key."); - }); + () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb, userId)); } /** @@ -114,15 +110,13 @@ public class KeySyncTask implements Runnable { int userId, int credentialType, String credential, - PlatformKeyManager.Factory platformKeyManagerFactory, - VaultKeySupplier vaultKeySupplier) { + PlatformKeyManager.Factory platformKeyManagerFactory) { mSnapshotListenersStorage = recoverySnapshotListenersStorage; mRecoverableKeyStoreDb = recoverableKeyStoreDb; mUserId = userId; mCredentialType = credentialType; mCredential = credential; mPlatformKeyManagerFactory = platformKeyManagerFactory; - mVaultKeySupplier = vaultKeySupplier; mRecoverySnapshotStorage = snapshotStorage; } @@ -142,7 +136,6 @@ public class KeySyncTask implements Runnable { } int recoveryAgentUid = mRecoverableKeyStoreDb.getRecoveryAgentUid(mUserId); - if (recoveryAgentUid == -1) { Log.w(TAG, "No recovery agent initialized for user " + mUserId); return; @@ -153,6 +146,13 @@ public class KeySyncTask implements Runnable { return; } + PublicKey publicKey = getVaultPublicKey(); + + if (publicKey == null) { + Log.w(TAG, "Not initialized for KeySync: no public key set. Cancelling task."); + return; + } + byte[] salt = generateSalt(); byte[] localLskfHash = hashCredentials(salt, mCredential); @@ -197,7 +197,7 @@ public class KeySyncTask implements Runnable { byte[] encryptedRecoveryKey; try { encryptedRecoveryKey = KeySyncUtils.thmEncryptRecoveryKey( - mVaultKeySupplier.get(), + publicKey, localLskfHash, vaultParams, recoveryKey); @@ -227,8 +227,7 @@ public class KeySyncTask implements Runnable { } private PublicKey getVaultPublicKey() { - // TODO: fill this in - throw new UnsupportedOperationException("TODO: get vault public key."); + return mRecoverableKeyStoreDb.getRecoveryServicePublicKey(mUserId); } /** @@ -339,11 +338,4 @@ public class KeySyncTask implements Runnable { } return keyEntries; } - - /** - * TODO: until this is in the database, so we can test. - */ - public interface VaultKeySupplier { - PublicKey get(); - } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java index e6efad5fb4b1..838311e185e8 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java @@ -22,7 +22,6 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.security.recoverablekeystore.RecoverableKeyStoreLoader; import android.text.TextUtils; import android.util.Log; @@ -36,10 +35,8 @@ import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringJoiner; @@ -368,6 +365,7 @@ public class RecoverableKeyStoreDb { * * @hide */ + @Nullable public PublicKey getRecoveryServicePublicKey(int userId, int uid) { SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase(); @@ -409,12 +407,8 @@ public class RecoverableKeyStoreDb { return null; } byte[] keyBytes = cursor.getBlob(idx); - X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(keyBytes); try { - return KeyFactory.getInstance("EC").generatePublic(pkSpec); - } catch (NoSuchAlgorithmException e) { - // Should never happen - throw new RuntimeException(e); + return decodeX509Key(keyBytes); } catch (InvalidKeySpecException e) { Log.wtf(TAG, String.format(Locale.US, @@ -507,7 +501,7 @@ public class RecoverableKeyStoreDb { return new int[]{}; } String[] types = csv.split(","); - int[] result = new int[types.length]; + int[] result = new int[types.length]; for (int i = 0; i < types.length; i++) { try { result[i] = Integer.parseInt(types[i]); @@ -520,6 +514,48 @@ public class RecoverableKeyStoreDb { } /** + * Returns the first (and only?) public key for {@code userId}. + * + * @param userId The uid of the profile whose keys are to be synced. + * @return The public key, or null if none exists. + */ + @Nullable + public PublicKey getRecoveryServicePublicKey(int userId) { + SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase(); + + String[] projection = { RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY }; + String selection = + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ?"; + String[] selectionArguments = { Integer.toString(userId) }; + + try ( + Cursor cursor = db.query( + RecoveryServiceMetadataEntry.TABLE_NAME, + projection, + selection, + selectionArguments, + /*groupBy=*/ null, + /*having=*/ null, + /*orderBy=*/ null) + ) { + if (cursor.getCount() < 1) { + return null; + } + + cursor.moveToFirst(); + byte[] keyBytes = cursor.getBlob(cursor.getColumnIndexOrThrow( + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY)); + + try { + return decodeX509Key(keyBytes); + } catch (InvalidKeySpecException e) { + Log.wtf(TAG, "Could not decode public key for " + userId); + return null; + } + } + } + + /** * Updates the server parameters given by the application initializing the local recovery * components. * @@ -619,5 +655,14 @@ public class RecoverableKeyStoreDb { mKeyStoreDbHelper.close(); } - // TODO: Add method for updating the 'last synced' time. + @Nullable + private static PublicKey decodeX509Key(byte[] keyBytes) throws InvalidKeySpecException { + X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes); + try { + return KeyFactory.getInstance("EC").generatePublic(publicKeySpec); + } catch (NoSuchAlgorithmException e) { + // Should never happen + throw new RuntimeException(e); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 8c3bf5dcd58e..4edc89d0384a 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -109,8 +109,7 @@ public class KeySyncTaskTest { TEST_USER_ID, TEST_CREDENTIAL_TYPE, TEST_CREDENTIAL, - () -> mPlatformKeyManager, - () -> mKeyPair.getPublic()); + () -> mPlatformKeyManager); mWrappingKey = generateAndroidKeyStoreKey(); mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index a5b67af11562..a8c7d5e5adba 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -328,7 +328,6 @@ public class RecoverableKeyStoreDbTest { } @Test - public void getRecoveryAgentUid_returnsUidIfSet() throws Exception { int userId = 12; int uid = 190992; @@ -437,6 +436,17 @@ public class RecoverableKeyStoreDbTest { } @Test + public void getRecoveryServicePublicKey_returnsFirstKey() throws Exception { + int userId = 68; + int uid = 12904; + PublicKey publicKey = genRandomPublicKey(); + + mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, publicKey); + + assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId)).isEqualTo(publicKey); + } + + @Test public void setServerParameters_replaceOldValue() throws Exception { int userId = 12; int uid = 10009; |