blob: 3e7b0a7e4c017bf6bbdc9e9985af157af917719c [file] [log] [blame]
Robert Berrybd086f12017-12-27 13:29:39 +00001/*
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
Robert Berry76cf0832017-12-15 23:01:22 +000017package com.android.server.locksettings.recoverablekeystore.storage;
18
19import android.content.Context;
20import android.database.sqlite.SQLiteDatabase;
21import android.database.sqlite.SQLiteOpenHelper;
Bo Zhu14d993d2018-02-03 21:38:48 -080022import android.util.Log;
Robert Berry76cf0832017-12-15 23:01:22 +000023
24import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
Bo Zhu584b923f2017-12-22 16:05:15 -080025import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -070026import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
Robert Berrybc088402017-12-18 13:10:41 +000027import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
Robert Berry76cf0832017-12-15 23:01:22 +000028
29/**
30 * Helper for creating the recoverable key database.
31 */
32class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
Bo Zhu14d993d2018-02-03 21:38:48 -080033 private static final String TAG = "RecoverableKeyStoreDbHp";
34
Dmitry Dementyev89f12d52019-02-28 12:26:01 -080035 static final int DATABASE_VERSION = 6; // Added user id serial number.
Robert Berry76cf0832017-12-15 23:01:22 +000036 private static final String DATABASE_NAME = "recoverablekeystore.db";
37
Robert Berrybc088402017-12-18 13:10:41 +000038 private static final String SQL_CREATE_KEYS_ENTRY =
Robert Berry76cf0832017-12-15 23:01:22 +000039 "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
40 + KeysEntry._ID + " INTEGER PRIMARY KEY,"
Robert Berryb7c06ea2017-12-21 13:37:23 +000041 + KeysEntry.COLUMN_NAME_USER_ID + " INTEGER,"
Robert Berrybc088402017-12-18 13:10:41 +000042 + KeysEntry.COLUMN_NAME_UID + " INTEGER,"
43 + KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
Robert Berry76cf0832017-12-15 23:01:22 +000044 + KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
45 + KeysEntry.COLUMN_NAME_WRAPPED_KEY + " BLOB,"
46 + KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
Robert Berrybc088402017-12-18 13:10:41 +000047 + KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
Dmitry Dementyevad884712017-12-20 12:38:36 -080048 + KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
Bo Zhu7ebcd662019-01-04 17:00:58 -080049 + KeysEntry.COLUMN_NAME_KEY_METADATA + " BLOB,"
Robert Berrybc088402017-12-18 13:10:41 +000050 + "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
51 + KeysEntry.COLUMN_NAME_ALIAS + "))";
Robert Berry76cf0832017-12-15 23:01:22 +000052
Robert Berrybc088402017-12-18 13:10:41 +000053 private static final String SQL_CREATE_USER_METADATA_ENTRY =
54 "CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( "
55 + UserMetadataEntry._ID + " INTEGER PRIMARY KEY,"
56 + UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE,"
Dmitry Dementyev89f12d52019-02-28 12:26:01 -080057 + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER,"
58 + UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER + " INTEGER DEFAULT -1)";
Robert Berrybc088402017-12-18 13:10:41 +000059
Dmitry Dementyev77183ef2018-01-05 15:46:00 -080060 private static final String SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY =
Bo Zhu584b923f2017-12-22 16:05:15 -080061 "CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " ("
62 + RecoveryServiceMetadataEntry._ID + " INTEGER PRIMARY KEY,"
63 + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER,"
64 + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
Dmitry Dementyev77183ef2018-01-05 15:46:00 -080065 + RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
66 + RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -070067 + RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST + " TEXT,"
Bo Zhu584b923f2017-12-22 16:05:15 -080068 + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
Bo Zhu14d993d2018-02-03 21:38:48 -080069 + RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
70 + RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
Dmitry Dementyevbdfdf532017-12-27 11:58:45 -080071 + RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
Dmitry Dementyev77183ef2018-01-05 15:46:00 -080072 + RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
Dmitry Dementyev7d8c78a2018-01-12 19:14:07 -080073 + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
Bo Zhu5b81fa62017-12-21 14:36:11 -080074 + "UNIQUE("
Bo Zhu584b923f2017-12-22 16:05:15 -080075 + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + ","
76 + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
Bo Zhu5b81fa62017-12-21 14:36:11 -080077
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -070078 private static final String SQL_CREATE_ROOT_OF_TRUST_ENTRY =
79 "CREATE TABLE " + RootOfTrustEntry.TABLE_NAME + " ("
80 + RootOfTrustEntry._ID + " INTEGER PRIMARY KEY,"
81 + RootOfTrustEntry.COLUMN_NAME_USER_ID + " INTEGER,"
82 + RootOfTrustEntry.COLUMN_NAME_UID + " INTEGER,"
Dmitry Dementyev5800c902019-03-05 14:53:24 -080083 + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " TEXT,"
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -070084 + RootOfTrustEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
85 + RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
86 + "UNIQUE("
87 + RootOfTrustEntry.COLUMN_NAME_USER_ID + ","
88 + RootOfTrustEntry.COLUMN_NAME_UID + ","
89 + RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + "))";
90
Robert Berrybc088402017-12-18 13:10:41 +000091 private static final String SQL_DELETE_KEYS_ENTRY =
Robert Berry76cf0832017-12-15 23:01:22 +000092 "DROP TABLE IF EXISTS " + KeysEntry.TABLE_NAME;
93
Robert Berrybc088402017-12-18 13:10:41 +000094 private static final String SQL_DELETE_USER_METADATA_ENTRY =
95 "DROP TABLE IF EXISTS " + UserMetadataEntry.TABLE_NAME;
96
Dmitry Dementyev77183ef2018-01-05 15:46:00 -080097 private static final String SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY =
Bo Zhu584b923f2017-12-22 16:05:15 -080098 "DROP TABLE IF EXISTS " + RecoveryServiceMetadataEntry.TABLE_NAME;
Bo Zhu5b81fa62017-12-21 14:36:11 -080099
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700100 private static final String SQL_DELETE_ROOT_OF_TRUST_ENTRY =
101 "DROP TABLE IF EXISTS " + RootOfTrustEntry.TABLE_NAME;
102
Robert Berry76cf0832017-12-15 23:01:22 +0000103 RecoverableKeyStoreDbHelper(Context context) {
104 super(context, DATABASE_NAME, null, DATABASE_VERSION);
105 }
106
107 @Override
108 public void onCreate(SQLiteDatabase db) {
Robert Berrybc088402017-12-18 13:10:41 +0000109 db.execSQL(SQL_CREATE_KEYS_ENTRY);
110 db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
Dmitry Dementyev77183ef2018-01-05 15:46:00 -0800111 db.execSQL(SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY);
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700112 db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
113 }
114
115 @Override
116 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
117 Log.e(TAG, "Recreating recoverablekeystore after unexpected version downgrade.");
118 dropAllKnownTables(db); // Wipe database.
119 onCreate(db);
Robert Berry76cf0832017-12-15 23:01:22 +0000120 }
121
122 @Override
123 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Bo Zhu14d993d2018-02-03 21:38:48 -0800124 if (oldVersion < 2) {
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700125 dropAllKnownTables(db); // Wipe database.
Bo Zhu14d993d2018-02-03 21:38:48 -0800126 onCreate(db);
127 return;
128 }
129
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700130 if (oldVersion < 3 && newVersion >= 3) {
Bo Zhu14d993d2018-02-03 21:38:48 -0800131 upgradeDbForVersion3(db);
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700132 oldVersion = 3;
Bo Zhu14d993d2018-02-03 21:38:48 -0800133 }
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700134
135 if (oldVersion < 4 && newVersion >= 4) {
136 upgradeDbForVersion4(db);
137 oldVersion = 4;
138 }
139
Bo Zhu7ebcd662019-01-04 17:00:58 -0800140 if (oldVersion < 5 && newVersion >= 5) {
141 upgradeDbForVersion5(db);
142 oldVersion = 5;
143 }
144
Dmitry Dementyev89f12d52019-02-28 12:26:01 -0800145 if (oldVersion < 6 && newVersion >= 6) {
146 upgradeDbForVersion6(db);
147 oldVersion = 6;
148 }
149
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700150 if (oldVersion != newVersion) {
151 Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
152 }
153 }
154
155 private void dropAllKnownTables(SQLiteDatabase db) {
156 db.execSQL(SQL_DELETE_KEYS_ENTRY);
157 db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
158 db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
159 db.execSQL(SQL_DELETE_ROOT_OF_TRUST_ENTRY);
Bo Zhu14d993d2018-02-03 21:38:48 -0800160 }
161
162 private void upgradeDbForVersion3(SQLiteDatabase db) {
163 // Add the two columns for cert path and cert serial number
164 addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
165 RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, "BLOB", /*defaultStr=*/ null);
166 addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
167 RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, "INTEGER", /*defaultStr=*/
168 null);
169 }
170
Dmitry Dementyevf34fc7e2018-03-26 17:31:29 -0700171 private void upgradeDbForVersion4(SQLiteDatabase db) {
172 Log.d(TAG, "Updating recoverable keystore database to version 4");
173 // Add new table with two columns for cert path and cert serial number.
174 db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
175 // adds column to store root of trust currently used by the recovery agent
176 addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
177 RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, "TEXT",
178 /*defaultStr=*/ null);
179 }
180
Bo Zhu7ebcd662019-01-04 17:00:58 -0800181 private void upgradeDbForVersion5(SQLiteDatabase db) {
182 Log.d(TAG, "Updating recoverable keystore database to version 5");
183 // adds a column to store the metadata for application keys
184 addColumnToTable(db, KeysEntry.TABLE_NAME,
185 KeysEntry.COLUMN_NAME_KEY_METADATA, "BLOB", /*defaultStr=*/ null);
186 }
187
Dmitry Dementyev89f12d52019-02-28 12:26:01 -0800188 private void upgradeDbForVersion6(SQLiteDatabase db) {
189 Log.d(TAG, "Updating recoverable keystore database to version 6");
190 // adds a column to store the user serial number
191 addColumnToTable(db, UserMetadataEntry.TABLE_NAME,
192 UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER,
193 "INTEGER DEFAULT -1",
194 /*defaultStr=*/ null);
195 }
196
Bo Zhu14d993d2018-02-03 21:38:48 -0800197 private static void addColumnToTable(
198 SQLiteDatabase db, String tableName, String column, String columnType,
199 String defaultStr) {
200 Log.d(TAG, "Adding column " + column + " to " + tableName + ".");
201
202 String alterStr = "ALTER TABLE " + tableName + " ADD COLUMN " + column + " " + columnType;
203 if (defaultStr != null && !defaultStr.isEmpty()) {
204 alterStr += " DEFAULT " + defaultStr;
205 }
206
207 db.execSQL(alterStr + ";");
Robert Berry76cf0832017-12-15 23:01:22 +0000208 }
209}
Bo Zhu14d993d2018-02-03 21:38:48 -0800210