Merge changes Icf10d577,Ia9d3cae7 am: 6083210d17

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1519582

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ia8d09a821357e06539bc2c71ad8c22587dac0176
This commit is contained in:
Tianjie Xu
2020-12-14 23:25:48 +00:00
committed by Automerger Merge Worker
6 changed files with 258 additions and 78 deletions

View File

@@ -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";

View File

@@ -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.
*

View File

@@ -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;
@@ -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";
@@ -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() {
@@ -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() {
@@ -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");
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
Slog.w(TAG,
"Had reboot escrow data for users, but RebootEscrowProvider 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]);
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) {
@@ -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;
}
@@ -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) {
@@ -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) {
@@ -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;
}
@@ -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);
@@ -397,7 +365,7 @@ class RebootEscrowManager {
}
boolean prepareRebootEscrow() {
if (mInjector.getRebootEscrow() == null) {
if (mInjector.getRebootEscrowProvider() == null) {
return false;
}
@@ -408,7 +376,7 @@ class RebootEscrowManager {
}
boolean clearRebootEscrow() {
if (mInjector.getRebootEscrow() == null) {
if (mInjector.getRebootEscrowProvider() == null) {
return false;
}

View File

@@ -0,0 +1,143 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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);
}

View File

@@ -95,13 +95,24 @@ public class RebootEscrowManagerTests {
static class MockInjector extends RebootEscrowManager.Injector {
private final IRebootEscrow mRebootEscrow;
private final RebootEscrowProviderInterface mRebootEscrowProvider;
private final UserManager mUserManager;
private final MockableRebootEscrowInjected mInjected;
MockInjector(Context context, UserManager userManager, IRebootEscrow rebootEscrow,
MockInjector(Context context, UserManager userManager,
IRebootEscrow rebootEscrow,
MockableRebootEscrowInjected injected) {
super(context);
mRebootEscrow = rebootEscrow;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
public IRebootEscrow getRebootEscrow() {
return mRebootEscrow;
}
};
mRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector);
mUserManager = userManager;
mInjected = injected;
}
@@ -112,8 +123,8 @@ public class RebootEscrowManagerTests {
}
@Override
public IRebootEscrow getRebootEscrow() {
return mRebootEscrow;
public RebootEscrowProviderInterface getRebootEscrowProvider() {
return mRebootEscrowProvider;
}
@Override