blob: 3e7b0a7e4c017bf6bbdc9e9985af157af917719c [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.locksettings.recoverablekeystore.storage;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RootOfTrustEntry;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
/**
* Helper for creating the recoverable key database.
*/
class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
private static final String TAG = "RecoverableKeyStoreDbHp";
static final int DATABASE_VERSION = 6; // Added user id serial number.
private static final String DATABASE_NAME = "recoverablekeystore.db";
private static final String SQL_CREATE_KEYS_ENTRY =
"CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
+ KeysEntry._ID + " INTEGER PRIMARY KEY,"
+ KeysEntry.COLUMN_NAME_USER_ID + " INTEGER,"
+ KeysEntry.COLUMN_NAME_UID + " INTEGER,"
+ KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
+ KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
+ KeysEntry.COLUMN_NAME_WRAPPED_KEY + " BLOB,"
+ KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
+ KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
+ KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
+ KeysEntry.COLUMN_NAME_KEY_METADATA + " BLOB,"
+ "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
+ KeysEntry.COLUMN_NAME_ALIAS + "))";
private static final String SQL_CREATE_USER_METADATA_ENTRY =
"CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( "
+ UserMetadataEntry._ID + " INTEGER PRIMARY KEY,"
+ UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE,"
+ UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER,"
+ UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER + " INTEGER DEFAULT -1)";
private static final String SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY =
"CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " ("
+ RecoveryServiceMetadataEntry._ID + " INTEGER PRIMARY KEY,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST + " TEXT,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
+ RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
+ "UNIQUE("
+ RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + ","
+ RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
private static final String SQL_CREATE_ROOT_OF_TRUST_ENTRY =
"CREATE TABLE " + RootOfTrustEntry.TABLE_NAME + " ("
+ RootOfTrustEntry._ID + " INTEGER PRIMARY KEY,"
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + " INTEGER,"
+ RootOfTrustEntry.COLUMN_NAME_UID + " INTEGER,"
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + " TEXT,"
+ RootOfTrustEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
+ RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
+ "UNIQUE("
+ RootOfTrustEntry.COLUMN_NAME_USER_ID + ","
+ RootOfTrustEntry.COLUMN_NAME_UID + ","
+ RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS + "))";
private static final String SQL_DELETE_KEYS_ENTRY =
"DROP TABLE IF EXISTS " + KeysEntry.TABLE_NAME;
private static final String SQL_DELETE_USER_METADATA_ENTRY =
"DROP TABLE IF EXISTS " + UserMetadataEntry.TABLE_NAME;
private static final String SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY =
"DROP TABLE IF EXISTS " + RecoveryServiceMetadataEntry.TABLE_NAME;
private static final String SQL_DELETE_ROOT_OF_TRUST_ENTRY =
"DROP TABLE IF EXISTS " + RootOfTrustEntry.TABLE_NAME;
RecoverableKeyStoreDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_KEYS_ENTRY);
db.execSQL(SQL_CREATE_USER_METADATA_ENTRY);
db.execSQL(SQL_CREATE_RECOVERY_SERVICE_METADATA_ENTRY);
db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e(TAG, "Recreating recoverablekeystore after unexpected version downgrade.");
dropAllKnownTables(db); // Wipe database.
onCreate(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
dropAllKnownTables(db); // Wipe database.
onCreate(db);
return;
}
if (oldVersion < 3 && newVersion >= 3) {
upgradeDbForVersion3(db);
oldVersion = 3;
}
if (oldVersion < 4 && newVersion >= 4) {
upgradeDbForVersion4(db);
oldVersion = 4;
}
if (oldVersion < 5 && newVersion >= 5) {
upgradeDbForVersion5(db);
oldVersion = 5;
}
if (oldVersion < 6 && newVersion >= 6) {
upgradeDbForVersion6(db);
oldVersion = 6;
}
if (oldVersion != newVersion) {
Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
}
}
private void dropAllKnownTables(SQLiteDatabase db) {
db.execSQL(SQL_DELETE_KEYS_ENTRY);
db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
db.execSQL(SQL_DELETE_ROOT_OF_TRUST_ENTRY);
}
private void upgradeDbForVersion3(SQLiteDatabase db) {
// Add the two columns for cert path and cert serial number
addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, "BLOB", /*defaultStr=*/ null);
addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, "INTEGER", /*defaultStr=*/
null);
}
private void upgradeDbForVersion4(SQLiteDatabase db) {
Log.d(TAG, "Updating recoverable keystore database to version 4");
// Add new table with two columns for cert path and cert serial number.
db.execSQL(SQL_CREATE_ROOT_OF_TRUST_ENTRY);
// adds column to store root of trust currently used by the recovery agent
addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
RecoveryServiceMetadataEntry.COLUMN_NAME_ACTIVE_ROOT_OF_TRUST, "TEXT",
/*defaultStr=*/ null);
}
private void upgradeDbForVersion5(SQLiteDatabase db) {
Log.d(TAG, "Updating recoverable keystore database to version 5");
// adds a column to store the metadata for application keys
addColumnToTable(db, KeysEntry.TABLE_NAME,
KeysEntry.COLUMN_NAME_KEY_METADATA, "BLOB", /*defaultStr=*/ null);
}
private void upgradeDbForVersion6(SQLiteDatabase db) {
Log.d(TAG, "Updating recoverable keystore database to version 6");
// adds a column to store the user serial number
addColumnToTable(db, UserMetadataEntry.TABLE_NAME,
UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER,
"INTEGER DEFAULT -1",
/*defaultStr=*/ null);
}
private static void addColumnToTable(
SQLiteDatabase db, String tableName, String column, String columnType,
String defaultStr) {
Log.d(TAG, "Adding column " + column + " to " + tableName + ".");
String alterStr = "ALTER TABLE " + tableName + " ADD COLUMN " + column + " " + columnType;
if (defaultStr != null && !defaultStr.isEmpty()) {
alterStr += " DEFAULT " + defaultStr;
}
db.execSQL(alterStr + ";");
}
}