blob: 81169e269917c77e4c9464ee365adcb1433c1af0 [file] [log] [blame]
/*
* Copyright (C) 2019 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.backup.encryption.tasks;
import android.security.keystore.recovery.InternalRecoveryServiceException;
import android.security.keystore.recovery.LockScreenRequiredException;
import android.util.Slog;
import com.android.internal.util.Preconditions;
import com.android.server.backup.encryption.CryptoSettings;
import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
import java.security.UnrecoverableKeyException;
import java.util.Objects;
import java.util.Optional;
/**
* Starts rotating to a new secondary key. Cannot complete until the screen is unlocked and the new
* key is synced.
*/
public class StartSecondaryKeyRotationTask {
private static final String TAG = "BE-StSecondaryKeyRotTsk";
private final CryptoSettings mCryptoSettings;
private final RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
public StartSecondaryKeyRotationTask(
CryptoSettings cryptoSettings,
RecoverableKeyStoreSecondaryKeyManager secondaryKeyManager) {
mCryptoSettings = Objects.requireNonNull(cryptoSettings);
mSecondaryKeyManager = Objects.requireNonNull(secondaryKeyManager);
}
/** Begin the key rotation */
public void run() {
Slog.i(TAG, "Attempting to initiate a secondary key rotation.");
Optional<String> maybeCurrentAlias = mCryptoSettings.getActiveSecondaryKeyAlias();
if (!maybeCurrentAlias.isPresent()) {
Slog.w(TAG, "No active current alias. Cannot trigger a secondary rotation.");
return;
}
String currentAlias = maybeCurrentAlias.get();
Optional<String> maybeNextAlias = mCryptoSettings.getNextSecondaryKeyAlias();
if (maybeNextAlias.isPresent()) {
String nextAlias = maybeNextAlias.get();
if (nextAlias.equals(currentAlias)) {
// Shouldn't be possible, but guard against accidentally deleting the active key.
Slog.e(TAG, "Was already trying to rotate to what is already the active key.");
} else {
Slog.w(TAG, "Was already rotating to another key. Cancelling that.");
try {
mSecondaryKeyManager.remove(nextAlias);
} catch (Exception e) {
Slog.wtf(TAG, "Could not remove old key", e);
}
}
mCryptoSettings.removeNextSecondaryKeyAlias();
}
RecoverableKeyStoreSecondaryKey newSecondaryKey;
try {
newSecondaryKey = mSecondaryKeyManager.generate();
} catch (LockScreenRequiredException e) {
Slog.e(TAG, "No lock screen is set - cannot generate a new key to rotate to.", e);
return;
} catch (InternalRecoveryServiceException e) {
Slog.e(TAG, "Internal error in Recovery Controller, failed to rotate key.", e);
return;
} catch (UnrecoverableKeyException e) {
Slog.e(TAG, "Failed to get key after generating, failed to rotate", e);
return;
}
String alias = newSecondaryKey.getAlias();
Slog.i(TAG, "Generated a new secondary key with alias '" + alias + "'.");
try {
mCryptoSettings.setNextSecondaryAlias(alias);
Slog.i(TAG, "Successfully set '" + alias + "' as next key to rotate to");
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Unexpected error setting next alias", e);
try {
mSecondaryKeyManager.remove(alias);
} catch (Exception err) {
Slog.wtf(TAG, "Failed to remove generated key after encountering error", err);
}
}
}
}