Home | History | Annotate | Download | only in storage
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.locksettings.recoverablekeystore.storage;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 
     21 import static java.nio.charset.StandardCharsets.UTF_8;
     22 
     23 import org.junit.After;
     24 import org.junit.Before;
     25 import org.junit.Test;
     26 import org.junit.runner.RunWith;
     27 
     28 import android.content.ContentValues;
     29 import android.content.Context;
     30 import android.database.sqlite.SQLiteDatabase;
     31 import android.support.test.InstrumentationRegistry;
     32 import android.support.test.filters.SmallTest;
     33 import android.support.test.runner.AndroidJUnit4;
     34 
     35 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
     36 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
     37 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
     38 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
     39 
     40 @SmallTest
     41 @RunWith(AndroidJUnit4.class)
     42 public class RecoverableKeyStoreDbHelperTest {
     43 
     44     private static final long TEST_USER_ID = 10L;
     45     private static final long TEST_UID = 60001L;
     46     private static final String TEST_ALIAS = "test-alias";
     47     private static final byte[] TEST_NONCE = "test-nonce".getBytes(UTF_8);
     48     private static final byte[] TEST_WRAPPED_KEY = "test-wrapped-key".getBytes(UTF_8);
     49     private static final long TEST_GENERATION_ID = 13L;
     50     private static final long TEST_LAST_SYNCED_AT = 1517990732000L;
     51     private static final int TEST_RECOVERY_STATUS = 3;
     52     private static final int TEST_PLATFORM_KEY_GENERATION_ID = 11;
     53     private static final int TEST_SNAPSHOT_VERSION = 31;
     54     private static final int TEST_SHOULD_CREATE_SNAPSHOT = 1;
     55     private static final byte[] TEST_PUBLIC_KEY = "test-public-key".getBytes(UTF_8);
     56     private static final String TEST_SECRET_TYPES = "test-secret-types";
     57     private static final long TEST_COUNTER_ID = -3981205205038476415L;
     58     private static final byte[] TEST_SERVER_PARAMS = "test-server-params".getBytes(UTF_8);
     59     private static final String TEST_ROOT_ALIAS = "root_cert_alias";
     60     private static final byte[] TEST_CERT_PATH = "test-cert-path".getBytes(UTF_8);
     61     private static final long TEST_CERT_SERIAL = 1000L;
     62 
     63     private static final String SQL_CREATE_V2_TABLE_KEYS =
     64             "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
     65                     + KeysEntry._ID + " INTEGER PRIMARY KEY,"
     66                     + KeysEntry.COLUMN_NAME_USER_ID + " INTEGER,"
     67                     + KeysEntry.COLUMN_NAME_UID + " INTEGER,"
     68                     + KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
     69                     + KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
     70                     + KeysEntry.COLUMN_NAME_WRAPPED_KEY + " BLOB,"
     71                     + KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
     72                     + KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
     73                     + KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
     74                     + "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
     75                     + KeysEntry.COLUMN_NAME_ALIAS + "))";
     76 
     77     private static final String SQL_CREATE_V2_TABLE_USER_METADATA =
     78             "CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( "
     79                     + UserMetadataEntry._ID + " INTEGER PRIMARY KEY,"
     80                     + UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE,"
     81                     + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER)";
     82 
     83     private static final String SQL_CREATE_V2_TABLE_RECOVERY_SERVICE_METADATA =
     84             "CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " ("
     85                     + RecoveryServiceMetadataEntry._ID + " INTEGER PRIMARY KEY,"
     86                     + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER,"
     87                     + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
     88                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
     89                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
     90                     + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
     91                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
     92                     + RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
     93                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
     94                     + "UNIQUE("
     95                     + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID  + ","
     96                     + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
     97 
     98     private SQLiteDatabase mDatabase;
     99     private RecoverableKeyStoreDbHelper mDatabaseHelper;
    100 
    101     @Before
    102     public void setUp() throws Exception {
    103         Context context = InstrumentationRegistry.getTargetContext();
    104         mDatabaseHelper = new RecoverableKeyStoreDbHelper(context);
    105         mDatabase = SQLiteDatabase.create(null);
    106     }
    107 
    108     @After
    109     public void tearDown() throws Exception {
    110         mDatabase.close();
    111     }
    112 
    113     private void createV2Tables() throws Exception {
    114         mDatabase.execSQL(SQL_CREATE_V2_TABLE_KEYS);
    115         mDatabase.execSQL(SQL_CREATE_V2_TABLE_USER_METADATA);
    116         mDatabase.execSQL(SQL_CREATE_V2_TABLE_RECOVERY_SERVICE_METADATA);
    117     }
    118 
    119     @Test
    120     public void onCreate() throws Exception {
    121         mDatabaseHelper.onCreate(mDatabase);
    122         checkAllColumns();
    123     }
    124 
    125     @Test
    126     public void onUpgrade_beforeV2() throws Exception {
    127         mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 1,
    128                 RecoverableKeyStoreDbHelper.DATABASE_VERSION);
    129         checkAllColumns();
    130     }
    131 
    132     @Test
    133     public void onUpgrade_fromV2() throws Exception {
    134         createV2Tables();
    135         mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2,
    136                 RecoverableKeyStoreDbHelper.DATABASE_VERSION);
    137         checkAllColumns();
    138     }
    139 
    140     @Test
    141     public void onUpgrade_v2_to_v3_to_v4() throws Exception {
    142         createV2Tables();
    143 
    144         assertThat(isRootOfTrustTableAvailable()).isFalse(); // V2 doesn't have the table;
    145 
    146         mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2, /*newVersion=*/ 3);
    147 
    148         assertThat(isRootOfTrustTableAvailable()).isFalse(); // V3 doesn't have the table;
    149 
    150         mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3,
    151                 RecoverableKeyStoreDbHelper.DATABASE_VERSION);
    152         checkAllColumns();
    153     }
    154 
    155     private boolean isRootOfTrustTableAvailable() {
    156         ContentValues values = new ContentValues();
    157         values.put(RootOfTrustEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
    158         values.put(RootOfTrustEntry.COLUMN_NAME_UID, TEST_UID);
    159         values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, TEST_ROOT_ALIAS);
    160         values.put(RootOfTrustEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
    161         values.put(RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
    162         return mDatabase.insert(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
    163                 > -1;
    164     }
    165 
    166     private void checkAllColumns() throws Exception {
    167         // Check the table containing encrypted application keys
    168         ContentValues values = new ContentValues();
    169         values.put(KeysEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
    170         values.put(KeysEntry.COLUMN_NAME_UID, TEST_UID);
    171         values.put(KeysEntry.COLUMN_NAME_ALIAS, TEST_ALIAS);
    172         values.put(KeysEntry.COLUMN_NAME_NONCE, TEST_NONCE);
    173         values.put(KeysEntry.COLUMN_NAME_WRAPPED_KEY, TEST_WRAPPED_KEY);
    174         values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, TEST_GENERATION_ID);
    175         values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, TEST_LAST_SYNCED_AT);
    176         values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, TEST_RECOVERY_STATUS);
    177         assertThat(mDatabase.insert(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
    178                 .isGreaterThan(-1L);
    179 
    180         // Check the table about user metadata
    181         values = new ContentValues();
    182         values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
    183         values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID,
    184                 TEST_PLATFORM_KEY_GENERATION_ID);
    185         assertThat(mDatabase.insert(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
    186                 .isGreaterThan(-1L);
    187 
    188         // Check the table about recovery service metadata
    189         values = new ContentValues();
    190         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
    191         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_UID, TEST_UID);
    192         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION,
    193                 TEST_SNAPSHOT_VERSION);
    194         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT,
    195                 TEST_SHOULD_CREATE_SNAPSHOT);
    196         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, TEST_ROOT_ALIAS);
    197         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY, TEST_PUBLIC_KEY);
    198         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES, TEST_SECRET_TYPES);
    199         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID, TEST_COUNTER_ID);
    200         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS, TEST_SERVER_PARAMS);
    201         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
    202         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
    203         assertThat(
    204                 mDatabase.insert(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
    205                         values))
    206                 .isGreaterThan(-1L);
    207 
    208         // Check the table about recovery service and root of trust data introduced in V4
    209         assertThat(isRootOfTrustTableAvailable()).isTrue();
    210     }
    211 }
    212