/* * 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 maybeCurrentAlias = mCryptoSettings.getActiveSecondaryKeyAlias(); if (!maybeCurrentAlias.isPresent()) { Slog.w(TAG, "No active current alias. Cannot trigger a secondary rotation."); return; } String currentAlias = maybeCurrentAlias.get(); Optional 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); } } } }