Loading core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7886,6 +7886,7 @@ package android.provider { field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention"; field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; field public static final String NAMESPACE_NETD_NATIVE = "netd_native"; field public static final String NAMESPACE_OTA = "ota"; field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service"; field public static final String NAMESPACE_PERMISSIONS = "permissions"; field public static final String NAMESPACE_PRIVACY = "privacy"; core/java/android/provider/DeviceConfig.java +8 −0 Original line number Diff line number Diff line Loading @@ -402,6 +402,14 @@ public final class DeviceConfig { @SystemApi public static final String NAMESPACE_PERMISSIONS = "permissions"; /** * Namespace for ota related features. * * @hide */ @SystemApi public static final String NAMESPACE_OTA = "ota"; /** * Namespace for all widget related features. * Loading services/core/java/com/android/server/locksettings/RebootEscrowManager.java +43 −75 Original line number Diff line number Diff line Loading @@ -15,20 +15,15 @@ */ package com.android.server.locksettings; import static android.os.UserHandle.USER_SYSTEM; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.hardware.rebootescrow.IRebootEscrow; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.SystemClock; import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.Settings; import android.util.Slog; Loading @@ -44,7 +39,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; class RebootEscrowManager { private static final String TAG = "RebootEscrowManager"; Loading Loading @@ -116,8 +110,24 @@ class RebootEscrowManager { static class Injector { protected Context mContext; private final RebootEscrowProviderInterface mRebootEscrowProvider; Injector(Context context) { mContext = context; RebootEscrowProviderInterface rebootEscrowProvider = null; // TODO(xunchang) add implementation for server based ror. if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, "server_based_ror_enabled", false)) { Slog.e(TAG, "Server based ror isn't implemented yet."); } else { rebootEscrowProvider = new RebootEscrowProviderHalImpl(); } if (rebootEscrowProvider != null && rebootEscrowProvider.hasRebootEscrowSupport()) { mRebootEscrowProvider = rebootEscrowProvider; } else { mRebootEscrowProvider = null; } } public Context getContext() { Loading @@ -128,15 +138,8 @@ class RebootEscrowManager { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } @Nullable public IRebootEscrow getRebootEscrow() { try { return IRebootEscrow.Stub.asInterface(ServiceManager.getService( "android.hardware.rebootescrow.IRebootEscrow/default")); } catch (NoSuchElementException e) { Slog.i(TAG, "Device doesn't implement RebootEscrow HAL"); } return null; public RebootEscrowProviderInterface getRebootEscrowProvider() { return mRebootEscrowProvider; } public int getBootCount() { Loading Loading @@ -210,45 +213,18 @@ class RebootEscrowManager { } private RebootEscrowKey getAndClearRebootEscrowKey() { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable"); return null; } try { byte[] escrowKeyBytes = rebootEscrow.retrieveKey(); if (escrowKeyBytes == null) { Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key"); return null; } else if (escrowKeyBytes.length != 32) { Slog.e(TAG, "IRebootEscrow returned key of incorrect size " + escrowKeyBytes.length); return null; } // Make sure we didn't get the null key. int zero = 0; for (int i = 0; i < escrowKeyBytes.length; i++) { zero |= escrowKeyBytes[i]; } if (zero == 0) { Slog.w(TAG, "IRebootEscrow returned an all-zeroes key"); RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return null; } // Overwrite the existing key with the null key rebootEscrow.storeKey(new byte[32]); RebootEscrowKey key = rebootEscrowProvider.getAndClearRebootEscrowKey(null); if (key != null) { mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_STORED_KEK); return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (RemoteException e) { Slog.w(TAG, "Could not retrieve escrow data"); return null; } catch (ServiceSpecificException e) { Slog.w(TAG, "Got service-specific exception: " + e.errorCode); return null; } return key; } private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey key) { Loading Loading @@ -279,9 +255,9 @@ class RebootEscrowManager { return; } IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Reboot escrow requested, but RebootEscrow HAL is unavailable"); if (mInjector.getRebootEscrowProvider() == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return; } Loading @@ -293,6 +269,7 @@ class RebootEscrowManager { final RebootEscrowData escrowData; try { // TODO(xunchang) further wrap the escrowData with a key from keystore. escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion, syntheticPassword); } catch (IOException e) { Loading Loading @@ -330,18 +307,16 @@ class RebootEscrowManager { mRebootEscrowWanted = false; setRebootEscrowReady(false); IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return; } mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); try { rebootEscrow.storeKey(new byte[32]); } catch (RemoteException | ServiceSpecificException e) { Slog.w(TAG, "Could not call RebootEscrow HAL to shred key"); } rebootEscrowProvider.clearRebootEscrowKey(); List<UserInfo> users = mUserManager.getUsers(); for (UserInfo user : users) { Loading @@ -356,9 +331,10 @@ class RebootEscrowManager { return false; } IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable"); RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return false; } Loading @@ -372,15 +348,7 @@ class RebootEscrowManager { return false; } boolean armedRebootEscrow = false; try { rebootEscrow.storeKey(escrowKey.getKeyBytes()); armedRebootEscrow = true; Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL"); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e); } boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, null); if (armedRebootEscrow) { mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM); mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS); Loading @@ -397,7 +365,7 @@ class RebootEscrowManager { } boolean prepareRebootEscrow() { if (mInjector.getRebootEscrow() == null) { if (mInjector.getRebootEscrowProvider() == null) { return false; } Loading @@ -408,7 +376,7 @@ class RebootEscrowManager { } boolean clearRebootEscrow() { if (mInjector.getRebootEscrow() == null) { if (mInjector.getRebootEscrowProvider() == null) { return false; } Loading services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java 0 → 100644 +143 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import android.annotation.Nullable; import android.hardware.rebootescrow.IRebootEscrow; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.NoSuchElementException; import javax.crypto.SecretKey; /** * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL. */ class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface { private static final String TAG = "RebootEscrowProvider"; private final Injector mInjector; static class Injector { @Nullable public IRebootEscrow getRebootEscrow() { try { return IRebootEscrow.Stub.asInterface(ServiceManager.getService( "android.hardware.rebootescrow.IRebootEscrow/default")); } catch (NoSuchElementException e) { Slog.i(TAG, "Device doesn't implement RebootEscrow HAL"); } return null; } } RebootEscrowProviderHalImpl() { mInjector = new Injector(); } @VisibleForTesting RebootEscrowProviderHalImpl(Injector injector) { mInjector = injector; } @Override public boolean hasRebootEscrowSupport() { return mInjector.getRebootEscrow() != null; } @Override public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable"); return null; } try { byte[] escrowKeyBytes = rebootEscrow.retrieveKey(); if (escrowKeyBytes == null) { Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key"); return null; } else if (escrowKeyBytes.length != 32) { Slog.e(TAG, "IRebootEscrow returned key of incorrect size " + escrowKeyBytes.length); return null; } // Make sure we didn't get the null key. int zero = 0; for (int i = 0; i < escrowKeyBytes.length; i++) { zero |= escrowKeyBytes[i]; } if (zero == 0) { Slog.w(TAG, "IRebootEscrow returned an all-zeroes key"); return null; } // Overwrite the existing key with the null key rebootEscrow.storeKey(new byte[32]); return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (RemoteException e) { Slog.w(TAG, "Could not retrieve escrow data"); return null; } catch (ServiceSpecificException e) { Slog.w(TAG, "Got service-specific exception: " + e.errorCode); return null; } } @Override public void clearRebootEscrowKey() { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { return; } try { rebootEscrow.storeKey(new byte[32]); } catch (RemoteException | ServiceSpecificException e) { Slog.w(TAG, "Could not call RebootEscrow HAL to shred key"); } } @Override public boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey) { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable"); return false; } try { // The HAL interface only accept 32 bytes data. And the encrypted bytes for the escrow // key may exceed that limit. So we just store the raw key bytes here. rebootEscrow.storeKey(escrowKey.getKeyBytes()); Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL"); return true; } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e); } return false; } } services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import javax.crypto.SecretKey; /** * Provides APIs for {@link RebootEscrowManager} to access and manage the reboot escrow key. * Implementations need to find a way to persist the key across a reboot, and securely discards the * persisted copy. * * @hide */ public interface RebootEscrowProviderInterface { /** * Returns true if the secure store/discard of reboot escrow key is supported. */ boolean hasRebootEscrowSupport(); /** * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted, * use the input key to decrypt the RebootEscrowKey. Returns null on failure. */ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey); /** * Clears the stored RebootEscrowKey. */ void clearRebootEscrowKey(); /** * Saves the given RebootEscrowKey, optionally encrypt the storage with the encryptionKey. */ boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey); } Loading
core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7886,6 +7886,7 @@ package android.provider { field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention"; field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; field public static final String NAMESPACE_NETD_NATIVE = "netd_native"; field public static final String NAMESPACE_OTA = "ota"; field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service"; field public static final String NAMESPACE_PERMISSIONS = "permissions"; field public static final String NAMESPACE_PRIVACY = "privacy";
core/java/android/provider/DeviceConfig.java +8 −0 Original line number Diff line number Diff line Loading @@ -402,6 +402,14 @@ public final class DeviceConfig { @SystemApi public static final String NAMESPACE_PERMISSIONS = "permissions"; /** * Namespace for ota related features. * * @hide */ @SystemApi public static final String NAMESPACE_OTA = "ota"; /** * Namespace for all widget related features. * Loading
services/core/java/com/android/server/locksettings/RebootEscrowManager.java +43 −75 Original line number Diff line number Diff line Loading @@ -15,20 +15,15 @@ */ package com.android.server.locksettings; import static android.os.UserHandle.USER_SYSTEM; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.hardware.rebootescrow.IRebootEscrow; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.SystemClock; import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.Settings; import android.util.Slog; Loading @@ -44,7 +39,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; class RebootEscrowManager { private static final String TAG = "RebootEscrowManager"; Loading Loading @@ -116,8 +110,24 @@ class RebootEscrowManager { static class Injector { protected Context mContext; private final RebootEscrowProviderInterface mRebootEscrowProvider; Injector(Context context) { mContext = context; RebootEscrowProviderInterface rebootEscrowProvider = null; // TODO(xunchang) add implementation for server based ror. if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, "server_based_ror_enabled", false)) { Slog.e(TAG, "Server based ror isn't implemented yet."); } else { rebootEscrowProvider = new RebootEscrowProviderHalImpl(); } if (rebootEscrowProvider != null && rebootEscrowProvider.hasRebootEscrowSupport()) { mRebootEscrowProvider = rebootEscrowProvider; } else { mRebootEscrowProvider = null; } } public Context getContext() { Loading @@ -128,15 +138,8 @@ class RebootEscrowManager { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } @Nullable public IRebootEscrow getRebootEscrow() { try { return IRebootEscrow.Stub.asInterface(ServiceManager.getService( "android.hardware.rebootescrow.IRebootEscrow/default")); } catch (NoSuchElementException e) { Slog.i(TAG, "Device doesn't implement RebootEscrow HAL"); } return null; public RebootEscrowProviderInterface getRebootEscrowProvider() { return mRebootEscrowProvider; } public int getBootCount() { Loading Loading @@ -210,45 +213,18 @@ class RebootEscrowManager { } private RebootEscrowKey getAndClearRebootEscrowKey() { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable"); return null; } try { byte[] escrowKeyBytes = rebootEscrow.retrieveKey(); if (escrowKeyBytes == null) { Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key"); return null; } else if (escrowKeyBytes.length != 32) { Slog.e(TAG, "IRebootEscrow returned key of incorrect size " + escrowKeyBytes.length); return null; } // Make sure we didn't get the null key. int zero = 0; for (int i = 0; i < escrowKeyBytes.length; i++) { zero |= escrowKeyBytes[i]; } if (zero == 0) { Slog.w(TAG, "IRebootEscrow returned an all-zeroes key"); RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return null; } // Overwrite the existing key with the null key rebootEscrow.storeKey(new byte[32]); RebootEscrowKey key = rebootEscrowProvider.getAndClearRebootEscrowKey(null); if (key != null) { mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_STORED_KEK); return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (RemoteException e) { Slog.w(TAG, "Could not retrieve escrow data"); return null; } catch (ServiceSpecificException e) { Slog.w(TAG, "Got service-specific exception: " + e.errorCode); return null; } return key; } private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey key) { Loading Loading @@ -279,9 +255,9 @@ class RebootEscrowManager { return; } IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Reboot escrow requested, but RebootEscrow HAL is unavailable"); if (mInjector.getRebootEscrowProvider() == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return; } Loading @@ -293,6 +269,7 @@ class RebootEscrowManager { final RebootEscrowData escrowData; try { // TODO(xunchang) further wrap the escrowData with a key from keystore. escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion, syntheticPassword); } catch (IOException e) { Loading Loading @@ -330,18 +307,16 @@ class RebootEscrowManager { mRebootEscrowWanted = false; setRebootEscrowReady(false); IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return; } mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); try { rebootEscrow.storeKey(new byte[32]); } catch (RemoteException | ServiceSpecificException e) { Slog.w(TAG, "Could not call RebootEscrow HAL to shred key"); } rebootEscrowProvider.clearRebootEscrowKey(); List<UserInfo> users = mUserManager.getUsers(); for (UserInfo user : users) { Loading @@ -356,9 +331,10 @@ class RebootEscrowManager { return false; } IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable"); RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); return false; } Loading @@ -372,15 +348,7 @@ class RebootEscrowManager { return false; } boolean armedRebootEscrow = false; try { rebootEscrow.storeKey(escrowKey.getKeyBytes()); armedRebootEscrow = true; Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL"); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e); } boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, null); if (armedRebootEscrow) { mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM); mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS); Loading @@ -397,7 +365,7 @@ class RebootEscrowManager { } boolean prepareRebootEscrow() { if (mInjector.getRebootEscrow() == null) { if (mInjector.getRebootEscrowProvider() == null) { return false; } Loading @@ -408,7 +376,7 @@ class RebootEscrowManager { } boolean clearRebootEscrow() { if (mInjector.getRebootEscrow() == null) { if (mInjector.getRebootEscrowProvider() == null) { return false; } Loading
services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java 0 → 100644 +143 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import android.annotation.Nullable; import android.hardware.rebootescrow.IRebootEscrow; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.NoSuchElementException; import javax.crypto.SecretKey; /** * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL. */ class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface { private static final String TAG = "RebootEscrowProvider"; private final Injector mInjector; static class Injector { @Nullable public IRebootEscrow getRebootEscrow() { try { return IRebootEscrow.Stub.asInterface(ServiceManager.getService( "android.hardware.rebootescrow.IRebootEscrow/default")); } catch (NoSuchElementException e) { Slog.i(TAG, "Device doesn't implement RebootEscrow HAL"); } return null; } } RebootEscrowProviderHalImpl() { mInjector = new Injector(); } @VisibleForTesting RebootEscrowProviderHalImpl(Injector injector) { mInjector = injector; } @Override public boolean hasRebootEscrowSupport() { return mInjector.getRebootEscrow() != null; } @Override public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable"); return null; } try { byte[] escrowKeyBytes = rebootEscrow.retrieveKey(); if (escrowKeyBytes == null) { Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key"); return null; } else if (escrowKeyBytes.length != 32) { Slog.e(TAG, "IRebootEscrow returned key of incorrect size " + escrowKeyBytes.length); return null; } // Make sure we didn't get the null key. int zero = 0; for (int i = 0; i < escrowKeyBytes.length; i++) { zero |= escrowKeyBytes[i]; } if (zero == 0) { Slog.w(TAG, "IRebootEscrow returned an all-zeroes key"); return null; } // Overwrite the existing key with the null key rebootEscrow.storeKey(new byte[32]); return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (RemoteException e) { Slog.w(TAG, "Could not retrieve escrow data"); return null; } catch (ServiceSpecificException e) { Slog.w(TAG, "Got service-specific exception: " + e.errorCode); return null; } } @Override public void clearRebootEscrowKey() { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { return; } try { rebootEscrow.storeKey(new byte[32]); } catch (RemoteException | ServiceSpecificException e) { Slog.w(TAG, "Could not call RebootEscrow HAL to shred key"); } } @Override public boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey) { IRebootEscrow rebootEscrow = mInjector.getRebootEscrow(); if (rebootEscrow == null) { Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable"); return false; } try { // The HAL interface only accept 32 bytes data. And the encrypted bytes for the escrow // key may exceed that limit. So we just store the raw key bytes here. rebootEscrow.storeKey(escrowKey.getKeyBytes()); Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL"); return true; } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e); } return false; } }
services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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; import javax.crypto.SecretKey; /** * Provides APIs for {@link RebootEscrowManager} to access and manage the reboot escrow key. * Implementations need to find a way to persist the key across a reboot, and securely discards the * persisted copy. * * @hide */ public interface RebootEscrowProviderInterface { /** * Returns true if the secure store/discard of reboot escrow key is supported. */ boolean hasRebootEscrowSupport(); /** * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted, * use the input key to decrypt the RebootEscrowKey. Returns null on failure. */ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey); /** * Clears the stored RebootEscrowKey. */ void clearRebootEscrowKey(); /** * Saves the given RebootEscrowKey, optionally encrypt the storage with the encryptionKey. */ boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey); }