From 0277b66f9eb9d7cd7e6b6ac6f55d53f43f184b6d Mon Sep 17 00:00:00 2001 From: Seth Moore <sethmo@google.com> Date: Thu, 20 Oct 2022 14:14:39 -0700 Subject: [PATCH] Add remote_provisioning system service This service is callable by system components like keystore2. This service calls into a mainline module API to do all the work for remote provisioning. Also include new OWNERS for the RemoteProvisioning implementation. Bug: 254112668 Test: Locally modify keystore to call the new service Change-Id: I6708d0b415798c78a4d66f279589d9def552ae78 --- api/Android.bp | 1 + core/java/Android.bp | 14 ++ core/java/android/content/Context.java | 8 ++ .../android/security/rkp/IGetKeyCallback.aidl | 49 +++++++ .../rkp/IGetRegistrationCallback.aidl | 49 +++++++ .../android/security/rkp/IRegistration.aidl | 85 ++++++++++++ .../security/rkp/IRemoteProvisioning.aidl | 68 ++++++++++ core/java/android/security/rkp/OWNERS | 5 + .../security/rkp/RemotelyProvisionedKey.aidl | 44 ++++++ services/Android.bp | 1 + services/core/Android.bp | 1 + .../com/android/server/security/rkp/OWNERS | 1 + .../rkp/RemoteProvisioningService.java | 126 ++++++++++++++++++ .../java/com/android/server/SystemServer.java | 8 +- 14 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 core/java/android/security/rkp/IGetKeyCallback.aidl create mode 100644 core/java/android/security/rkp/IGetRegistrationCallback.aidl create mode 100644 core/java/android/security/rkp/IRegistration.aidl create mode 100644 core/java/android/security/rkp/IRemoteProvisioning.aidl create mode 100644 core/java/android/security/rkp/OWNERS create mode 100644 core/java/android/security/rkp/RemotelyProvisionedKey.aidl create mode 100644 services/core/java/com/android/server/security/rkp/OWNERS create mode 100644 services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java diff --git a/api/Android.bp b/api/Android.bp index ef8879096e4b5..fe283e1a95c65 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -116,6 +116,7 @@ combined_apis { system_server_classpath: [ "service-media-s", "service-permission", + "service-rkp", "service-sdksandbox", ], } diff --git a/core/java/Android.bp b/core/java/Android.bp index 88ee39d913f32..8d9f92ebea492 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -376,6 +376,20 @@ aidl_interface { }, } +// Build Rust bindings for remote provisioning. Needed by keystore2. +aidl_interface { + name: "android.security.rkp_aidl", + unstable: true, + srcs: [ + "android/security/rkp/*.aidl", + ], + backend: { + rust: { + enabled: true, + }, + }, +} + aidl_interface { name: "android.debug_aidl", unstable: true, diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index cc42a4c11036d..415469aec3b1d 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5906,6 +5906,14 @@ public abstract class Context { */ public static final String FILE_INTEGRITY_SERVICE = "file_integrity"; + /** + * Binder service for remote key provisioning. + * + * @see android.frameworks.rkp.IRemoteProvisioning + * @hide + */ + public static final String REMOTE_PROVISIONING_SERVICE = "remote_provisioning"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.hardware.lights.LightsManager} for controlling device lights. diff --git a/core/java/android/security/rkp/IGetKeyCallback.aidl b/core/java/android/security/rkp/IGetKeyCallback.aidl new file mode 100644 index 0000000000000..85ceae62aadc0 --- /dev/null +++ b/core/java/android/security/rkp/IGetKeyCallback.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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 android.security.rkp; + +import android.security.rkp.RemotelyProvisionedKey; + +/** + * Callback interface for receiving remotely provisioned keys from a + * {@link IRegistration}. + * + * @hide + */ +oneway interface IGetKeyCallback { + /** + * Called in response to {@link IRegistration.getKey}, indicating + * a remotely-provisioned key is available. + * + * @param key The key that was received from the remote provisioning service. + */ + void onSuccess(in RemotelyProvisionedKey key); + + /** + * Called when the key request has been successfully cancelled. + * @see IRegistration.cancelGetKey + */ + void onCancel(); + + /** + * Called when an error has occurred while trying to get a remotely provisioned key. + * + * @param error A description of what failed, suitable for logging. + */ + void onError(String error); +} + diff --git a/core/java/android/security/rkp/IGetRegistrationCallback.aidl b/core/java/android/security/rkp/IGetRegistrationCallback.aidl new file mode 100644 index 0000000000000..e375a6f97b315 --- /dev/null +++ b/core/java/android/security/rkp/IGetRegistrationCallback.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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 android.security.rkp; + +import android.security.rkp.IRegistration; + +/** + * Callback interface for receiving a remote provisioning registration. + * {@link IRegistration}. + * + * @hide + */ +oneway interface IGetRegistrationCallback { + /** + * Called in response to {@link IRemoteProvisioning.getRegistration}. + * + * @param registration an IRegistration that is used to fetch remotely + * provisioned keys for the given IRemotelyProvisionedComponent. + */ + void onSuccess(in IRegistration registration); + + /** + * Called when the get registration request has been successfully cancelled. + * @see IRemoteProvisioning.cancelGetRegistration + */ + void onCancel(); + + /** + * Called when an error has occurred while trying to get a registration. + * + * @param error A description of what failed, suitable for logging. + */ + void onError(String error); +} + diff --git a/core/java/android/security/rkp/IRegistration.aidl b/core/java/android/security/rkp/IRegistration.aidl new file mode 100644 index 0000000000000..6522a458de4e5 --- /dev/null +++ b/core/java/android/security/rkp/IRegistration.aidl @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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 android.security.rkp; + +import android.security.rkp.IGetKeyCallback; + +/** + * This interface is associated with the registration of an + * IRemotelyProvisionedComponent. Each component has a unique set of keys + * and certificates that are provisioned to the device for attestation. An + * IRegistration binder is created by calling + * {@link IRemoteProvisioning#getRegistration()}. + * + * This interface is used to query for available keys and certificates for the + * registered component. + * + * @hide + */ +oneway interface IRegistration { + /** + * Fetch a remotely provisioned key for the given keyId. Keys are unique + * per caller/keyId/registration tuple. This ensures that no two + * applications are able to correlate keys to uniquely identify a + * device/user. Callers receive their key via {@code callback}. + * + * If a key is available, this call immediately invokes {@code callback}. + * + * If no keys are immediately available, then this function contacts the + * remote provisioning server to provision a key. After provisioning is + * completed, the key is passed to {@code callback}. + * + * @param keyId This is a client-chosen key identifier, used to + * differentiate between keys for varying client-specific use-cases. For + * example, keystore2 passes the UID of the applications that call it as + * the keyId value here, so that each of keystore2's clients gets a unique + * key. + * @param callback Receives the result of the call. A callback must only + * be used with one {@code getKey} call at a time. + */ + void getKey(int keyId, IGetKeyCallback callback); + + /** + * Cancel an active request for a remotely provisioned key, as initiated via + * {@link getKey}. Upon cancellation, {@code callback.onCancel} will be invoked. + */ + void cancelGetKey(IGetKeyCallback callback); + + /** + * Replace an obsolete key blob with an upgraded key blob. + * In certain cases, such as security patch level upgrade, keys become "old". + * In these cases, the component which supports operations with the remotely + * provisioned key blobs must support upgrading the blobs to make them "new" + * and usable on the updated system. + * + * For an example of a remotely provisioned component that has an upgrade + * mechanism, see the documentation for IKeyMintDevice.upgradeKey. + * + * Once a key has been upgraded, the IRegistration where the key is stored + * needs to be told about the new blob. After calling storeUpgradedKey, + * getKey will return the new key blob instead of the old one. + * + * Note that this function does NOT extend the lifetime of key blobs. The + * certificate for the key is unchanged, and the key will still expire at + * the same time it would have if storeUpgradedKey had never been called. + * + * @param oldKeyBlob The old key blob to be replaced by {@code newKeyBlob}. + * + * @param newKeyblob The new blob to replace {@code oldKeyBlob}. + */ + void storeUpgradedKey(in byte[] oldKeyBlob, in byte[] newKeyBlob); +} diff --git a/core/java/android/security/rkp/IRemoteProvisioning.aidl b/core/java/android/security/rkp/IRemoteProvisioning.aidl new file mode 100644 index 0000000000000..23d8159f7b280 --- /dev/null +++ b/core/java/android/security/rkp/IRemoteProvisioning.aidl @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 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 android.security.rkp; + +import android.security.rkp.IRegistration; +import android.security.rkp.IGetRegistrationCallback; + +/** + * {@link IRemoteProvisioning} is the interface provided to use the remote key + * provisioning functionality from the Remote Key Provisioning Daemon (RKPD). + * This would be the first service that RKPD clients would interact with. The + * intent is for the clients to get the {@link IRegistration} object from this + * interface and use it for actual remote provisioning work. + * + * @hide + */ +oneway interface IRemoteProvisioning { + /** + * Takes a remotely provisioned component service name and gets a + * registration bound to that service and the caller's UID. + * + * @param irpcName The name of the {@code IRemotelyProvisionedComponent} + * for which remotely provisioned keys should be managed. + * @param callback Receives the result of the call. A callback must only + * be used with one {@code getRegistration} call at a time. + * + * Notes: + * - This function will attempt to get the service named by irpcName. This + * implies that a lazy/dynamic aidl service will be instantiated, and this + * function blocks until the service is up. Upon return, any binder tokens + * are dropped, allowing the lazy/dynamic service to shutdown. + * - The created registration object is unique per caller. If two different + * UIDs call getRegistration with the same irpcName, they will receive + * different registrations. This prevents two different applications from + * being able to see the same keys. + * - This function is idempotent per calling UID. Additional calls to + * getRegistration with the same parameters, from the same caller, will have + * no side effects. + * - A callback may only be associated with one getRegistration call at a time. + * If the callback is used multiple times, this API will return an error. + * + * @see IRegistration#getKey() + * @see IRemotelyProvisionedComponent + * + */ + void getRegistration(String irpcName, IGetRegistrationCallback callback); + + /** + * Cancel any active {@link getRegistration} call associated with the given + * callback. If no getRegistration call is currently active, this function is + * a noop. + */ + void cancelGetRegistration(IGetRegistrationCallback callback); +} diff --git a/core/java/android/security/rkp/OWNERS b/core/java/android/security/rkp/OWNERS new file mode 100644 index 0000000000000..fd430899fc5f8 --- /dev/null +++ b/core/java/android/security/rkp/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 1084908 + +jbires@google.com +sethmo@google.com +vikramgaur@google.com diff --git a/core/java/android/security/rkp/RemotelyProvisionedKey.aidl b/core/java/android/security/rkp/RemotelyProvisionedKey.aidl new file mode 100644 index 0000000000000..207f18f2f947d --- /dev/null +++ b/core/java/android/security/rkp/RemotelyProvisionedKey.aidl @@ -0,0 +1,44 @@ +/* + * Copyright 2022, 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 android.security.rkp; + +/** + * A {@link RemotelyProvisionedKey} holds an attestation key and the + * corresponding remotely provisioned certificate chain. + * + * @hide + */ +@RustDerive(Eq=true, PartialEq=true) +parcelable RemotelyProvisionedKey { + /** + * The remotely-provisioned key that may be used to sign attestations. The + * format of this key is opaque, and need only be understood by the + * IRemotelyProvisionedComponent that generated it. + * + * Any private key material contained within this blob must be encrypted. + * + * @see IRemotelyProvisionedComponent + */ + byte[] keyBlob; + + /** + * Sequence of DER-encoded X.509 certificates that make up the attestation + * key's certificate chain. This is the binary encoding for a chain that is + * supported by Java's CertificateFactory.generateCertificates API. + */ + byte[] encodedCertChain; +} diff --git a/services/Android.bp b/services/Android.bp index 4d38b067d3a44..2e2e51b7e86e6 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -176,6 +176,7 @@ java_library { "framework-tethering.stubs.module_lib", "service-art.stubs.system_server", "service-permission.stubs.system_server", + "service-rkp.stubs.system_server", "service-sdksandbox.stubs.system_server", ], diff --git a/services/core/Android.bp b/services/core/Android.bp index d35c07f1962af..9268fc03bd2f5 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -131,6 +131,7 @@ java_library_static { "app-compat-annotations", "framework-tethering.stubs.module_lib", "service-permission.stubs.system_server", + "service-rkp.stubs.system_server", "service-sdksandbox.stubs.system_server", ], diff --git a/services/core/java/com/android/server/security/rkp/OWNERS b/services/core/java/com/android/server/security/rkp/OWNERS new file mode 100644 index 0000000000000..348f940483111 --- /dev/null +++ b/services/core/java/com/android/server/security/rkp/OWNERS @@ -0,0 +1 @@ +file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java new file mode 100644 index 0000000000000..65a4b38629b69 --- /dev/null +++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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.security.rkp; + +import android.content.Context; +import android.os.Binder; +import android.os.OutcomeReceiver; +import android.os.RemoteException; +import android.security.rkp.IGetKeyCallback; +import android.security.rkp.IGetRegistrationCallback; +import android.security.rkp.IRegistration; +import android.security.rkp.IRemoteProvisioning; +import android.security.rkp.service.RegistrationProxy; +import android.util.Log; + +import com.android.server.SystemService; + +import java.time.Duration; + +/** + * Implements the remote provisioning system service. This service is backed by a mainline + * module, allowing the underlying implementation to be updated. The code here is a thin + * proxy for the code in android.security.rkp.service. + * + * @hide + */ +public class RemoteProvisioningService extends SystemService { + public static final String TAG = "RemoteProvisionSysSvc"; + private static final Duration CREATE_REGISTRATION_TIMEOUT = Duration.ofSeconds(10); + private final RemoteProvisioningImpl mBinderImpl = new RemoteProvisioningImpl(); + + /** @hide */ + public RemoteProvisioningService(Context context) { + super(context); + } + + @Override + public void onStart() { + publishBinderService(Context.REMOTE_PROVISIONING_SERVICE, mBinderImpl); + } + + private final class RemoteProvisioningImpl extends IRemoteProvisioning.Stub { + + final class RegistrationBinder extends IRegistration.Stub { + static final String TAG = RemoteProvisioningService.TAG; + private final RegistrationProxy mRegistration; + + RegistrationBinder(RegistrationProxy registration) { + mRegistration = registration; + } + + @Override + public void getKey(int keyId, IGetKeyCallback callback) { + Log.e(TAG, "RegistrationBinder.getKey NOT YET IMPLEMENTED"); + } + + @Override + public void cancelGetKey(IGetKeyCallback callback) { + Log.e(TAG, "RegistrationBinder.cancelGetKey NOT YET IMPLEMENTED"); + } + + @Override + public void storeUpgradedKey(byte[] oldKeyBlob, byte[] newKeyBlob) { + Log.e(TAG, "RegistrationBinder.storeUpgradedKey NOT YET IMPLEMENTED"); + } + } + + @Override + public void getRegistration(String irpcName, IGetRegistrationCallback callback) + throws RemoteException { + final int callerUid = Binder.getCallingUidOrThrow(); + final long callingIdentity = Binder.clearCallingIdentity(); + try { + Log.i(TAG, "getRegistration(" + irpcName + ")"); + RegistrationProxy.createAsync( + getContext(), + callerUid, + irpcName, + CREATE_REGISTRATION_TIMEOUT, + getContext().getMainExecutor(), + new OutcomeReceiver<>() { + @Override + public void onResult(RegistrationProxy registration) { + try { + callback.onSuccess(new RegistrationBinder(registration)); + } catch (RemoteException e) { + Log.e(TAG, "Error calling success callback", e); + } + } + + @Override + public void onError(Exception error) { + try { + callback.onError(error.toString()); + } catch (RemoteException e) { + Log.e(TAG, "Error calling error callback", e); + } + } + }); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + @Override + public void cancelGetRegistration(IGetRegistrationCallback callback) + throws RemoteException { + Log.i(TAG, "cancelGetRegistration()"); + callback.onError("cancelGetRegistration not yet implemented"); + } + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a953bcbe54537..0ceda79ae84d3 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -186,6 +186,7 @@ import com.android.server.security.AttestationVerificationManagerService; import com.android.server.security.FileIntegrityService; import com.android.server.security.KeyAttestationApplicationIdProviderService; import com.android.server.security.KeyChainSystemService; +import com.android.server.security.rkp.RemoteProvisioningService; import com.android.server.sensorprivacy.SensorPrivacyService; import com.android.server.sensors.SensorService; import com.android.server.signedconfig.SignedConfigService; @@ -1392,11 +1393,16 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(BugreportManagerService.class); t.traceEnd(); - // Serivce for GPU and GPU driver. + // Service for GPU and GPU driver. t.traceBegin("GpuService"); mSystemServiceManager.startService(GpuService.class); t.traceEnd(); + // Handles system process requests for remotely provisioned keys & data. + t.traceBegin("StartRemoteProvisioningService"); + mSystemServiceManager.startService(RemoteProvisioningService.class); + t.traceEnd(); + t.traceEnd(); // startCoreServices } -- GitLab