diff --git a/api/Android.bp b/api/Android.bp index ef8879096e4b58162331ebecf2779317ce40a538..fe283e1a95c65ab4971fd12e449091e9ba334760 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 88ee39d913f321f3d4872cb63b6e7931a5228742..8d9f92ebea4922b41bdd8b6a885311f24f1d1d44 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 cc42a4c11036db4e4b838b164a0e24fa24a902af..415469aec3b1d5fc0d064ca22aa617da1edcda5c 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 0000000000000000000000000000000000000000..85ceae62aadc03146ea4ca7cc91c481831984b89 --- /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 0000000000000000000000000000000000000000..e375a6f97b31505e632f6937449d58cffbd2fcf7 --- /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 0000000000000000000000000000000000000000..6522a458de4e58e79b1055719f202d433b2fef7d --- /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 0000000000000000000000000000000000000000..23d8159f7b28099a8302ecf8883e7a4a996e8aa4 --- /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 0000000000000000000000000000000000000000..fd430899fc5f80c1d8f617f14dd3ee12b110b0b9 --- /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 0000000000000000000000000000000000000000..207f18f2f947dd96e18da45363efb18540603e1f --- /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 4d38b067d3a44eb727c618bbb7e2aa939c86fb78..2e2e51b7e86e6cf2d74dbf00987d2c3cfc1aad75 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 d35c07f1962af78a26766bcf762382e34372d423..9268fc03bd2f57c327fc7c5957e3750213131f4c 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 0000000000000000000000000000000000000000..348f940483111b84262f9522284b6b02ba23c1e9 --- /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 0000000000000000000000000000000000000000..65a4b38629b6993bce98fcc3c2cb54c93cc1486e --- /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 a953bcbe54537053231623ce40d6ef70c8f91571..0ceda79ae84d34d79d7457a036b7ffd2a4526a19 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 }