Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7c06ea0 authored by Robert Berry's avatar Robert Berry
Browse files

Add userId to RecoverableKeyStoreDb

We need to store the userId (i.e., the uid of the *profile*, not the
app), as well as the app uid. This is because when the screen is
unlocked, the unlock is associated with a specific user profile, not
a specific app. So at that point we need to look up all keys that
are pending sync for that *user*, and upload them to the remote
storage.

Test: adb shell am instrument -w -e package com.android.server.locksettings.recoverablekeystore com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
Change-Id: I6c456cca8974f5e1a15dfde6e9dd4e6bf4c16065
parent 24721ea0
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -87,6 +87,7 @@ public class RecoverableKeyGenerator {
     * The generated key allows encrypt/decrypt only using AES/GCM/NoPadding.
     * The generated key allows encrypt/decrypt only using AES/GCM/NoPadding.
     *
     *
     * @param platformKey The user's platform key, with which to wrap the generated key.
     * @param platformKey The user's platform key, with which to wrap the generated key.
     * @param userId The user ID of the profile to which the calling app belongs.
     * @param uid The uid of the application that will own the key.
     * @param uid The uid of the application that will own the key.
     * @param alias The alias by which the key will be known in AndroidKeyStore.
     * @param alias The alias by which the key will be known in AndroidKeyStore.
     * @throws RecoverableKeyStorageException if there is some error persisting the key either to
     * @throws RecoverableKeyStorageException if there is some error persisting the key either to
@@ -96,7 +97,8 @@ public class RecoverableKeyGenerator {
     *
     *
     * @hide
     * @hide
     */
     */
    public void generateAndStoreKey(PlatformEncryptionKey platformKey, int uid, String alias)
    public void generateAndStoreKey(
            PlatformEncryptionKey platformKey, int userId, int uid, String alias)
            throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
            throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
        mKeyGenerator.init(KEY_SIZE_BITS);
        mKeyGenerator.init(KEY_SIZE_BITS);
        SecretKey key = mKeyGenerator.generateKey();
        SecretKey key = mKeyGenerator.generateKey();
@@ -134,7 +136,7 @@ public class RecoverableKeyGenerator {
        } catch (DestroyFailedException e) {
        } catch (DestroyFailedException e) {
            Log.w(TAG, "Could not destroy SecretKey.");
            Log.w(TAG, "Could not destroy SecretKey.");
        }
        }
        long result = mDatabase.insertKey(uid, alias, wrappedKey);
        long result = mDatabase.insertKey(userId, uid, alias, wrappedKey);


        if (result == RESULT_CANNOT_INSERT_ROW) {
        if (result == RESULT_CANNOT_INSERT_ROW) {
            // Attempt to clean up
            // Attempt to clean up
+10 −7
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@ import java.util.Map;
public class RecoverableKeyStoreDb {
public class RecoverableKeyStoreDb {
    private static final String TAG = "RecoverableKeyStoreDb";
    private static final String TAG = "RecoverableKeyStoreDb";
    private static final int IDLE_TIMEOUT_SECONDS = 30;
    private static final int IDLE_TIMEOUT_SECONDS = 30;
    private static final int LAST_SYNCED_AT_UNSYNCED = -1;


    private final RecoverableKeyStoreDbHelper mKeyStoreDbHelper;
    private final RecoverableKeyStoreDbHelper mKeyStoreDbHelper;


@@ -61,6 +62,7 @@ public class RecoverableKeyStoreDb {
    /**
    /**
     * Inserts a key into the database.
     * Inserts a key into the database.
     *
     *
     * @param userId The uid of the profile the application is running under.
     * @param uid Uid of the application to whom the key belongs.
     * @param uid Uid of the application to whom the key belongs.
     * @param alias The alias of the key in the AndroidKeyStore.
     * @param alias The alias of the key in the AndroidKeyStore.
     * @param wrappedKey The wrapped key.
     * @param wrappedKey The wrapped key.
@@ -68,14 +70,15 @@ public class RecoverableKeyStoreDb {
     *
     *
     * @hide
     * @hide
     */
     */
    public long insertKey(int uid, String alias, WrappedKey wrappedKey) {
    public long insertKey(int userId, int uid, String alias, WrappedKey wrappedKey) {
        SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
        SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        ContentValues values = new ContentValues();
        values.put(KeysEntry.COLUMN_NAME_USER_ID, userId);
        values.put(KeysEntry.COLUMN_NAME_UID, uid);
        values.put(KeysEntry.COLUMN_NAME_UID, uid);
        values.put(KeysEntry.COLUMN_NAME_ALIAS, alias);
        values.put(KeysEntry.COLUMN_NAME_ALIAS, alias);
        values.put(KeysEntry.COLUMN_NAME_NONCE, wrappedKey.getNonce());
        values.put(KeysEntry.COLUMN_NAME_NONCE, wrappedKey.getNonce());
        values.put(KeysEntry.COLUMN_NAME_WRAPPED_KEY, wrappedKey.getKeyMaterial());
        values.put(KeysEntry.COLUMN_NAME_WRAPPED_KEY, wrappedKey.getKeyMaterial());
        values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, -1);
        values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, LAST_SYNCED_AT_UNSYNCED);
        values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
        values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
        return db.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
        return db.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
    }
    }
@@ -130,16 +133,16 @@ public class RecoverableKeyStoreDb {
    }
    }


    /**
    /**
     * Returns all keys for the given {@code uid} and {@code platformKeyGenerationId}.
     * Returns all keys for the given {@code userId} and {@code platformKeyGenerationId}.
     *
     *
     * @param uid User id of the profile to which all the keys are associated.
     * @param userId User id of the profile to which all the keys are associated.
     * @param platformKeyGenerationId The generation ID of the platform key that wrapped these keys.
     * @param platformKeyGenerationId The generation ID of the platform key that wrapped these keys.
     *     (i.e., this should be the most recent generation ID, as older platform keys are not
     *     (i.e., this should be the most recent generation ID, as older platform keys are not
     *     usable.)
     *     usable.)
     *
     *
     * @hide
     * @hide
     */
     */
    public Map<String, WrappedKey> getAllKeys(int uid, int platformKeyGenerationId) {
    public Map<String, WrappedKey> getAllKeys(int userId, int platformKeyGenerationId) {
        SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
        SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
        String[] projection = {
        String[] projection = {
                KeysEntry._ID,
                KeysEntry._ID,
@@ -147,10 +150,10 @@ public class RecoverableKeyStoreDb {
                KeysEntry.COLUMN_NAME_WRAPPED_KEY,
                KeysEntry.COLUMN_NAME_WRAPPED_KEY,
                KeysEntry.COLUMN_NAME_ALIAS};
                KeysEntry.COLUMN_NAME_ALIAS};
        String selection =
        String selection =
                KeysEntry.COLUMN_NAME_UID + " = ? AND "
                KeysEntry.COLUMN_NAME_USER_ID + " = ? AND "
                + KeysEntry.COLUMN_NAME_GENERATION_ID + " = ?";
                + KeysEntry.COLUMN_NAME_GENERATION_ID + " = ?";
        String[] selectionArguments = {
        String[] selectionArguments = {
                Integer.toString(uid), Integer.toString(platformKeyGenerationId) };
                Integer.toString(userId), Integer.toString(platformKeyGenerationId) };


        try (
        try (
            Cursor cursor = db.query(
            Cursor cursor = db.query(
+5 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,11 @@ class RecoverableKeyStoreDbContract {
    static class KeysEntry implements BaseColumns {
    static class KeysEntry implements BaseColumns {
        static final String TABLE_NAME = "keys";
        static final String TABLE_NAME = "keys";


        /**
         * 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 generated the key.
         * The uid of the application that generated the key.
         */
         */
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@ class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
    private static final String SQL_CREATE_KEYS_ENTRY =
    private static final String SQL_CREATE_KEYS_ENTRY =
            "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
            "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
                    + KeysEntry._ID + " INTEGER PRIMARY KEY,"
                    + KeysEntry._ID + " INTEGER PRIMARY KEY,"
                    + KeysEntry.COLUMN_NAME_USER_ID + " INTEGER,"
                    + KeysEntry.COLUMN_NAME_UID + " INTEGER,"
                    + KeysEntry.COLUMN_NAME_UID + " INTEGER,"
                    + KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
                    + KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
                    + KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
                    + KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
+9 −4
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ public class RecoverableKeyGeneratorTest {
    private static final String UNSUPPORTED_CIPHER_ALGORITHM = "AES/CTR/NoPadding";
    private static final String UNSUPPORTED_CIPHER_ALGORITHM = "AES/CTR/NoPadding";
    private static final String TEST_ALIAS = "karlin";
    private static final String TEST_ALIAS = "karlin";
    private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
    private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey";
    private static final int TEST_USER_ID = 1000;
    private static final int KEYSTORE_UID_SELF = -1;
    private static final int KEYSTORE_UID_SELF = -1;
    private static final int GCM_TAG_LENGTH_BITS = 128;
    private static final int GCM_TAG_LENGTH_BITS = 128;
    private static final int GCM_NONCE_LENGTH_BYTES = 12;
    private static final int GCM_NONCE_LENGTH_BYTES = 12;
@@ -95,7 +96,8 @@ public class RecoverableKeyGeneratorTest {


    @Test
    @Test
    public void generateAndStoreKey_setsKeyInKeyStore() throws Exception {
    public void generateAndStoreKey_setsKeyInKeyStore() throws Exception {
        mRecoverableKeyGenerator.generateAndStoreKey(mPlatformKey, KEYSTORE_UID_SELF, TEST_ALIAS);
        mRecoverableKeyGenerator.generateAndStoreKey(
                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);


        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        assertTrue(keyStore.containsAlias(TEST_ALIAS));
        assertTrue(keyStore.containsAlias(TEST_ALIAS));
@@ -104,7 +106,8 @@ public class RecoverableKeyGeneratorTest {
    @Test
    @Test
    public void generateAndStoreKey_storesKeyEnabledForAesGcmNoPaddingEncryptDecrypt()
    public void generateAndStoreKey_storesKeyEnabledForAesGcmNoPaddingEncryptDecrypt()
            throws Exception {
            throws Exception {
        mRecoverableKeyGenerator.generateAndStoreKey(mPlatformKey, KEYSTORE_UID_SELF, TEST_ALIAS);
        mRecoverableKeyGenerator.generateAndStoreKey(
                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);


        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        SecretKey key = (SecretKey) keyStore.getKey(TEST_ALIAS, /*password=*/ null);
        SecretKey key = (SecretKey) keyStore.getKey(TEST_ALIAS, /*password=*/ null);
@@ -117,7 +120,8 @@ public class RecoverableKeyGeneratorTest {


    @Test
    @Test
    public void generateAndStoreKey_storesKeyDisabledForOtherModes() throws Exception {
    public void generateAndStoreKey_storesKeyDisabledForOtherModes() throws Exception {
        mRecoverableKeyGenerator.generateAndStoreKey(mPlatformKey, KEYSTORE_UID_SELF, TEST_ALIAS);
        mRecoverableKeyGenerator.generateAndStoreKey(
                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);


        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        SecretKey key = (SecretKey) keyStore.getKey(TEST_ALIAS, /*password=*/ null);
        SecretKey key = (SecretKey) keyStore.getKey(TEST_ALIAS, /*password=*/ null);
@@ -133,7 +137,8 @@ public class RecoverableKeyGeneratorTest {


    @Test
    @Test
    public void generateAndStoreKey_storesWrappedKey() throws Exception {
    public void generateAndStoreKey_storesWrappedKey() throws Exception {
        mRecoverableKeyGenerator.generateAndStoreKey(mPlatformKey, KEYSTORE_UID_SELF, TEST_ALIAS);
        mRecoverableKeyGenerator.generateAndStoreKey(
                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);


        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(KEYSTORE_UID_SELF);
        SecretKey key = (SecretKey) keyStore.getKey(TEST_ALIAS, /*password=*/ null);
        SecretKey key = (SecretKey) keyStore.getKey(TEST_ALIAS, /*password=*/ null);
Loading