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
diff --git a/api/Android.bp b/api/Android.bp
index ef88790..fe283e1a 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -116,6 +116,7 @@
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 88ee39d..8d9f92e 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -376,6 +376,20 @@
},
}
+// 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 cc42a4c..415469a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5907,6 +5907,14 @@
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 0000000..85ceae62
--- /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 0000000..e375a6f
--- /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 0000000..6522a45
--- /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 0000000..23d8159
--- /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 0000000..fd43089
--- /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 0000000..207f18f
--- /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 4d38b06..2e2e51b 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -176,6 +176,7 @@
"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 d35c07f..9268fc0 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -131,6 +131,7 @@
"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 0000000..348f940
--- /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 0000000..65a4b38
--- /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 a953bcb..0ceda79 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.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 @@
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
}