OSDN Git Service

Hook up using initialized public key in KeySyncTask
authorRobert Berry <robertberry@google.com>
Wed, 27 Dec 2017 10:53:58 +0000 (10:53 +0000)
committerRobert Berry <robertberry@google.com>
Thu, 28 Dec 2017 11:04:42 +0000 (11:04 +0000)
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

services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java

index f6f5e59..6de2445 100644 (file)
@@ -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();
-    }
 }
index e6efad5..838311e 100644 (file)
@@ -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);
+        }
+    }
 }
index 8c3bf5d..4edc89d 100644 (file)
@@ -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);
index a5b67af..a8c7d5e 100644 (file)
@@ -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;