Add remote key provisioning to the IC HAL

The IIdentityCredentialStore can now advertise the correct
IRemotelyProvisionedComponent that is used for getting remotely
provisioned attestation keys.

IWritableIdentityCredential has a new method so it can accept remotely
provisioned keys.

Update the VTS tests to check the new RKP functionality.

Support RKP in the default identity cred service

Test: VtsHalIdentityTargetTest
Bug: 194696876
Change-Id: I96dcf3027e0f21790c35900ddf8cc0953bd3b1ca
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index dad3b8d..e3b8191 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -15,6 +15,7 @@
     ],
     imports: [
         "android.hardware.keymaster",
+        "android.hardware.security.keymint",
     ],
     stability: "vintf",
     backend: {
@@ -25,6 +26,7 @@
             vndk: {
                 enabled: true,
             },
+            apps_enabled: false,
         },
     },
     versions: [
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl
index cd8d56b..9b96ea8 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/HardwareInformation.aidl
@@ -39,4 +39,5 @@
   int dataChunkSize;
   boolean isDirectAccess;
   @utf8InCpp String[] supportedDocTypes;
+  boolean isRemoteKeyProvisioningSupported = false;
 }
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl
index c912c52..31ca8b1 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredentialStore.aidl
@@ -38,6 +38,7 @@
   android.hardware.identity.IWritableIdentityCredential createCredential(in @utf8InCpp String docType, in boolean testCredential);
   android.hardware.identity.IIdentityCredential getCredential(in android.hardware.identity.CipherSuite cipherSuite, in byte[] credentialData);
   android.hardware.identity.IPresentationSession createPresentationSession(in android.hardware.identity.CipherSuite cipherSuite);
+  android.hardware.security.keymint.IRemotelyProvisionedComponent getRemotelyProvisionedComponent();
   const int STATUS_OK = 0;
   const int STATUS_FAILED = 1;
   const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2;
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
index 9a0fa9e..5377349 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -41,4 +41,5 @@
   byte[] addEntryValue(in byte[] content);
   @SuppressWarnings(value={"out-array"}) void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature);
   void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize);
+  void setRemotelyProvisionedAttestationKey(in byte[] attestationKeyBlob, in byte[] attestationCertificate);
 }
diff --git a/identity/aidl/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/android/hardware/identity/HardwareInformation.aidl
index d67739d..acd13b6 100644
--- a/identity/aidl/android/hardware/identity/HardwareInformation.aidl
+++ b/identity/aidl/android/hardware/identity/HardwareInformation.aidl
@@ -51,4 +51,19 @@
      *
      */
     @utf8InCpp String[] supportedDocTypes;
+
+    /**
+     * isRemoteKeyProvisioningSupported indicates whether or not the underlying implementation
+     * supports a remotely provisioned key for attestation or not. If this field is false, then
+     * the implementation only uses a factory-installed, fixed attestation key. If this field is
+     * true, then an IRemotelyProvisionedComponent is associated with the IIdentityCredentialStore,
+     * and a remotely provisioned key blob may be provided for credential key attestation.
+     *
+     * Note that remote provisioning is not required, even when it is supported. Implementations
+     * MUST use a factory-installed attestation key as a fallback for when there are no
+     * remotely provisioned keys available. This behavior mirrors keystore key attestation.
+     *
+     * This field was added in API version 4.
+     */
+    boolean isRemoteKeyProvisioningSupported = false;
 }
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
index 959ee02..d3e4da0 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
@@ -21,6 +21,7 @@
 import android.hardware.identity.IIdentityCredential;
 import android.hardware.identity.IPresentationSession;
 import android.hardware.identity.IWritableIdentityCredential;
+import android.hardware.security.keymint.IRemotelyProvisionedComponent;
 
 /**
  * IIdentityCredentialStore provides an interface to a secure store for user identity documents.
@@ -263,4 +264,23 @@
      * @return an IPresentationSession interface.
      */
     IPresentationSession createPresentationSession(in CipherSuite cipherSuite);
+
+    /**
+     * Fetch the IRemotelyProvisionedComponent that is used to generate attestation keys for
+     * remote provisionining. Keys generated by this component are to be certified by a remote
+     * provisionined authority, then used to attest to credential keys via
+     * IWritableIdentityCredential.setRemotelyProvisionedAttestationKey.
+     *
+     * Support for this method is indicated by HardwareInformation. If the
+     * |isRemoteKeyProvisioningSupported| field is false, this method will fail with
+     * EX_UNSUPPORTED_OPERATION.
+     *
+     * This method was added in API version 4.
+     *
+     * @see
+     *         android.hardware.identity.IWritableIdentityCredential#setRemotelyProvisionedAttestationKey
+     *
+     * @return an IRemotelyProvisionedComponent that is used to generate attestation keys.
+     */
+    IRemotelyProvisionedComponent getRemotelyProvisionedComponent();
 }
diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index 9dec312..756b008 100644
--- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -335,4 +335,36 @@
      * @param expectedProofOfProvisioningSize the expected size of ProofOfProvisioning.
      */
     void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize);
+
+    /**
+     * Sets the attestation key used to sign the credentialKey certificate. This method is used to
+     * support remotely provisioned attestation keys, removing the credential's dependency on any
+     * factory-provisioned attestation key.
+     *
+     * This method must be called before getAttestationCertificate. After this method is called,
+     * the certificate chain returned by getAttestationCertificate will contain a leaf certificate
+     * signed by attestationKeyBlob and the chain in attestationCertificate will make up the rest
+     * of the returned chain.
+     *
+     * Returns EX_UNSUPPORTED_FUNCTION if remote provisioning is not supported
+     * (see IIdentityCredentialStore.getHardwareInformation()).
+     *
+     * This method was added in API version 4.
+     *
+     * @param attestationKeyBlob is a key blob generated by the IRemotelyProvisionedComponent that
+     *     is returned by ICredentialStore.getRemotelyProvisionedComponent. The format is vendor-
+     *     specified, and matches the key blob returned by IKeyMintDevice.generateKey.
+     *
+     * @param attestationCertificate contains the X.509 certificate chain that certifies the
+     *     attestationKeyBlob. This certificate is expected to have been remotely provisioned
+     *     by a trusted authority. This parameter must contain a concatenated chain of DER-encoded
+     *     X.509 certificates. The certificates must be ordered such that the attestation key
+     *     certificate is first (starting at byte 0). The issuer certificate for the attestation
+     *     certificate immediately follows, continuing this chain to the final, root certificate.
+     *
+     * @see getAttestationCertificate
+     * @see android.hardware.identity.ICredentialStore#getRemotelyProvisionedComponent
+     */
+    void setRemotelyProvisionedAttestationKey(
+            in byte[] attestationKeyBlob, in byte[] attestationCertificate);
 }
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index ca24afa..32b3543 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -42,6 +42,7 @@
         "android.hardware.identity-support-lib",
         "android.hardware.identity-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
+        "android.hardware.security.keymint-V2-ndk",
     ],
 }
 
@@ -81,6 +82,9 @@
     init_rc: ["identity-default.rc"],
     vintf_fragments: ["identity-default.xml"],
     vendor: true,
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_static",
+    ],
     cflags: [
         "-Wall",
         "-Wextra",
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index c98a91e..3fd9f1d 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -267,25 +267,42 @@
 
 bool eicOpsCreateCredentialKey(uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE], const uint8_t* challenge,
                                size_t challengeSize, const uint8_t* applicationId,
-                               size_t applicationIdSize, bool testCredential, uint8_t* cert,
-                               size_t* certSize) {
-    vector<uint8_t> challengeVec(challengeSize);
-    memcpy(challengeVec.data(), challenge, challengeSize);
-
-    vector<uint8_t> applicationIdVec(applicationIdSize);
-    memcpy(applicationIdVec.data(), applicationId, applicationIdSize);
-
-    optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> ret =
-            android::hardware::identity::support::createEcKeyPairAndAttestation(
-                    challengeVec, applicationIdVec, testCredential);
-    if (!ret) {
-        eicDebug("Error generating CredentialKey and attestation");
-        return false;
+                               size_t applicationIdSize, bool testCredential,
+                               const uint8_t* attestationKeyBlob, size_t attestationKeyBlobSize,
+                               const uint8_t* attestationKeyCert, size_t attestationKeyCertSize,
+                               uint8_t* cert, size_t* certSize) {
+    vector<uint8_t> flatChain;
+    vector<uint8_t> keyPair;
+    vector<uint8_t> challengeVec(challenge, challenge + challengeSize);
+    vector<uint8_t> applicationIdVec(applicationId, applicationId + applicationIdSize);
+    if (attestationKeyBlob && attestationKeyBlobSize > 0 && attestationKeyCert &&
+        attestationKeyCertSize > 0) {
+        vector<uint8_t> attestationKeyBlobVec(attestationKeyBlob,
+                                              attestationKeyBlob + attestationKeyBlobSize);
+        vector<uint8_t> attestationKeyCertVec(attestationKeyCert,
+                                              attestationKeyCert + attestationKeyCertSize);
+        optional<std::pair<vector<uint8_t>, vector<uint8_t>>> keyAndCert =
+                android::hardware::identity::support::createEcKeyPairWithAttestationKey(
+                        challengeVec, applicationIdVec, attestationKeyBlobVec,
+                        attestationKeyCertVec, testCredential);
+        if (!keyAndCert) {
+            eicDebug("Error generating CredentialKey and attestation");
+            return false;
+        }
+        keyPair = std::move(keyAndCert->first);
+        flatChain = std::move(keyAndCert->second);
+    } else {
+        optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> ret =
+                android::hardware::identity::support::createEcKeyPairAndAttestation(
+                        challengeVec, applicationIdVec, testCredential);
+        if (!ret) {
+            eicDebug("Error generating CredentialKey and attestation");
+            return false;
+        }
+        keyPair = std::move(ret->first);
+        flatChain = android::hardware::identity::support::certificateChainJoin(ret->second);
     }
 
-    // Extract certificate chain.
-    vector<uint8_t> flatChain =
-            android::hardware::identity::support::certificateChainJoin(ret.value().second);
     if (*certSize < flatChain.size()) {
         eicDebug("Buffer for certificate is only %zd bytes long, need %zd bytes", *certSize,
                  flatChain.size());
@@ -296,7 +313,7 @@
 
     // Extract private key.
     optional<vector<uint8_t>> privKey =
-            android::hardware::identity::support::ecKeyPairGetPrivateKey(ret.value().first);
+            android::hardware::identity::support::ecKeyPairGetPrivateKey(keyPair);
     if (!privKey) {
         eicDebug("Error extracting private key");
         return false;
@@ -520,10 +537,12 @@
 #ifdef EIC_DEBUG
 
 void eicPrint(const char* format, ...) {
+    char buf[1024];
     va_list args;
     va_start(args, format);
-    vfprintf(stderr, format, args);
+    vsnprintf(buf, sizeof(buf), format, args);
     va_end(args);
+    LOG(INFO) << buf;
 }
 
 void eicHexdump(const char* message, const uint8_t* data, size_t dataSize) {
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.cpp b/identity/aidl/default/FakeSecureHardwareProxy.cpp
index 91e634c..9b9a749 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.cpp
+++ b/identity/aidl/default/FakeSecureHardwareProxy.cpp
@@ -155,7 +155,11 @@
     size_t publicKeyCertSize = sizeof publicKeyCert;
     if (!eicProvisioningCreateCredentialKey(&ctx_, challenge.data(), challenge.size(),
                                             applicationId.data(), applicationId.size(),
-                                            publicKeyCert, &publicKeyCertSize)) {
+                                            /*attestationKeyBlob=*/nullptr,
+                                            /*attestationKeyBlobSize=*/0,
+                                            /*attestationKeyCert=*/nullptr,
+                                            /*attestationKeyCertSize=*/0, publicKeyCert,
+                                            &publicKeyCertSize)) {
         return std::nullopt;
     }
     vector<uint8_t> pubKeyCert(publicKeyCertSize);
@@ -163,6 +167,23 @@
     return pubKeyCert;
 }
 
+optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::createCredentialKeyUsingRkp(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+        const vector<uint8_t>& attestationKeyBlob, const vector<uint8_t>& attstationKeyCert) {
+    size_t publicKeyCertSize = 4096;
+    vector<uint8_t> publicKeyCert(publicKeyCertSize);
+    if (!eicProvisioningCreateCredentialKey(&ctx_, challenge.data(), challenge.size(),
+                                            applicationId.data(), applicationId.size(),
+                                            attestationKeyBlob.data(), attestationKeyBlob.size(),
+                                            attstationKeyCert.data(), attstationKeyCert.size(),
+                                            publicKeyCert.data(), &publicKeyCertSize)) {
+        LOG(ERROR) << "error creating credential key";
+        return std::nullopt;
+    }
+    publicKeyCert.resize(publicKeyCertSize);
+    return publicKeyCert;
+}
+
 bool FakeSecureHardwareProvisioningProxy::startPersonalization(
         int accessControlProfileCount, const vector<int>& entryCounts, const string& docType,
         size_t expectedProofOfProvisioningSize) {
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.h b/identity/aidl/default/FakeSecureHardwareProxy.h
index df98c7a..2512074 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.h
+++ b/identity/aidl/default/FakeSecureHardwareProxy.h
@@ -43,6 +43,11 @@
     optional<vector<uint8_t>> createCredentialKey(const vector<uint8_t>& challenge,
                                                   const vector<uint8_t>& applicationId) override;
 
+    optional<vector<uint8_t>> createCredentialKeyUsingRkp(
+            const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+            const vector<uint8_t>& attestationKeyBlob,
+            const vector<uint8_t>& attestationKeyCert) override;
+
     bool startPersonalization(int accessControlProfileCount, const vector<int>& entryCounts,
                               const string& docType,
                               size_t expectedProofOfProvisioningSize) override;
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index 7678ecb..ff80752 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -1012,8 +1012,8 @@
                 IIdentityCredentialStore::STATUS_FAILED, "Error creating provisioning proxy"));
     }
     shared_ptr<WritableIdentityCredential> wc =
-            ndk::SharedRefBase::make<WritableIdentityCredential>(provisioningHwProxy, docType_,
-                                                                 testCredential_);
+            ndk::SharedRefBase::make<WritableIdentityCredential>(
+                    provisioningHwProxy, docType_, testCredential_, hardwareInformation_);
     if (!wc->initializeForUpdate(encryptedCredentialKeys_)) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 2935fb8..5929829 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -48,11 +48,13 @@
   public:
     IdentityCredential(sp<SecureHardwareProxyFactory> hwProxyFactory,
                        const vector<uint8_t>& credentialData,
-                       std::shared_ptr<PresentationSession> session)
+                       std::shared_ptr<PresentationSession> session,
+                       HardwareInformation hardwareInformation)
         : hwProxyFactory_(hwProxyFactory),
           credentialData_(credentialData),
           session_(std::move(session)),
           numStartRetrievalCalls_(0),
+          hardwareInformation_(std::move(hardwareInformation)),
           expectedDeviceNameSpacesSize_(0) {}
 
     // Parses and decrypts credentialData_, return a status code from
@@ -103,6 +105,7 @@
     vector<uint8_t> credentialData_;
     shared_ptr<PresentationSession> session_;
     int numStartRetrievalCalls_;
+    HardwareInformation hardwareInformation_;
 
     // Set by initialize()
     string docType_;
diff --git a/identity/aidl/default/common/IdentityCredentialStore.cpp b/identity/aidl/default/common/IdentityCredentialStore.cpp
index 4703ffe..bbc2cef 100644
--- a/identity/aidl/default/common/IdentityCredentialStore.cpp
+++ b/identity/aidl/default/common/IdentityCredentialStore.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "IdentityCredentialStore"
 
 #include <android-base/logging.h>
+#include <android/binder_manager.h>
 
 #include "IdentityCredential.h"
 #include "IdentityCredentialStore.h"
@@ -25,15 +26,24 @@
 
 namespace aidl::android::hardware::identity {
 
+using ::aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+
+IdentityCredentialStore::IdentityCredentialStore(sp<SecureHardwareProxyFactory> hwProxyFactory,
+                                                 optional<string> remotelyProvisionedComponent)
+    : hwProxyFactory_(hwProxyFactory),
+      remotelyProvisionedComponentName_(remotelyProvisionedComponent) {
+    hardwareInformation_.credentialStoreName = "Identity Credential Reference Implementation";
+    hardwareInformation_.credentialStoreAuthorName = "Google";
+    hardwareInformation_.dataChunkSize = kGcmChunkSize;
+    hardwareInformation_.isDirectAccess = false;
+    hardwareInformation_.supportedDocTypes = {};
+    hardwareInformation_.isRemoteKeyProvisioningSupported =
+            remotelyProvisionedComponentName_.has_value();
+}
+
 ndk::ScopedAStatus IdentityCredentialStore::getHardwareInformation(
         HardwareInformation* hardwareInformation) {
-    HardwareInformation hw;
-    hw.credentialStoreName = "Identity Credential Reference Implementation";
-    hw.credentialStoreAuthorName = "Google";
-    hw.dataChunkSize = kGcmChunkSize;
-    hw.isDirectAccess = false;
-    hw.supportedDocTypes = {};
-    *hardwareInformation = hw;
+    *hardwareInformation = hardwareInformation_;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -42,7 +52,8 @@
         shared_ptr<IWritableIdentityCredential>* outWritableCredential) {
     sp<SecureHardwareProvisioningProxy> hwProxy = hwProxyFactory_->createProvisioningProxy();
     shared_ptr<WritableIdentityCredential> wc =
-            ndk::SharedRefBase::make<WritableIdentityCredential>(hwProxy, docType, testCredential);
+            ndk::SharedRefBase::make<WritableIdentityCredential>(hwProxy, docType, testCredential,
+                                                                 hardwareInformation_);
     if (!wc->initialize()) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
@@ -63,7 +74,7 @@
     }
 
     shared_ptr<IdentityCredential> credential = ndk::SharedRefBase::make<IdentityCredential>(
-            hwProxyFactory_, credentialData, nullptr /* session */);
+            hwProxyFactory_, credentialData, nullptr /* session */, hardwareInformation_);
     auto ret = credential->initialize();
     if (ret != IIdentityCredentialStore::STATUS_OK) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -83,8 +94,8 @@
     }
 
     sp<SecureHardwareSessionProxy> hwProxy = hwProxyFactory_->createSessionProxy();
-    shared_ptr<PresentationSession> session =
-            ndk::SharedRefBase::make<PresentationSession>(hwProxyFactory_, hwProxy);
+    shared_ptr<PresentationSession> session = ndk::SharedRefBase::make<PresentationSession>(
+            hwProxyFactory_, hwProxy, hardwareInformation_);
     auto ret = session->initialize();
     if (ret != IIdentityCredentialStore::STATUS_OK) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -94,4 +105,23 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus IdentityCredentialStore::getRemotelyProvisionedComponent(
+        shared_ptr<IRemotelyProvisionedComponent>* outRemotelyProvisionedComponent) {
+    if (!remotelyProvisionedComponentName_) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(
+                EX_UNSUPPORTED_OPERATION, "Remote key provisioning is not supported"));
+    }
+
+    ndk::SpAIBinder binder(
+            AServiceManager_waitForService(remotelyProvisionedComponentName_->c_str()));
+    if (binder.get() == nullptr) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Unable to get remotely provisioned component"));
+    }
+
+    *outRemotelyProvisionedComponent = IRemotelyProvisionedComponent::fromBinder(binder);
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/common/IdentityCredentialStore.h b/identity/aidl/default/common/IdentityCredentialStore.h
index 77b894d..dd1261b 100644
--- a/identity/aidl/default/common/IdentityCredentialStore.h
+++ b/identity/aidl/default/common/IdentityCredentialStore.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
 
 #include <aidl/android/hardware/identity/BnIdentityCredentialStore.h>
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
 
 #include "SecureHardwareProxy.h"
 
@@ -25,14 +26,18 @@
 
 using ::android::sp;
 using ::android::hardware::identity::SecureHardwareProxyFactory;
+using ::std::optional;
 using ::std::shared_ptr;
 using ::std::string;
 using ::std::vector;
 
 class IdentityCredentialStore : public BnIdentityCredentialStore {
   public:
-    IdentityCredentialStore(sp<SecureHardwareProxyFactory> hwProxyFactory)
-        : hwProxyFactory_(hwProxyFactory) {}
+    // If remote key provisioning is supported, pass the service name for the correct
+    // IRemotelyProvisionedComponent to the remotelyProvisionedComponent parameter. Else
+    // pass std::nullopt to indicate remote key provisioning is not supported.
+    IdentityCredentialStore(sp<SecureHardwareProxyFactory> hwProxyFactory,
+                            optional<string> remotelyProvisionedComponent);
 
     // The GCM chunk size used by this implementation is 64 KiB.
     static constexpr size_t kGcmChunkSize = 64 * 1024;
@@ -50,8 +55,14 @@
     ndk::ScopedAStatus createPresentationSession(
             CipherSuite cipherSuite, shared_ptr<IPresentationSession>* outSession) override;
 
+    ndk::ScopedAStatus getRemotelyProvisionedComponent(
+            shared_ptr<::aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent>*
+                    outRemotelyProvisionedComponent) override;
+
   private:
     sp<SecureHardwareProxyFactory> hwProxyFactory_;
+    optional<string> remotelyProvisionedComponentName_;
+    HardwareInformation hardwareInformation_;
 };
 
 }  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/common/PresentationSession.cpp b/identity/aidl/default/common/PresentationSession.cpp
index fbd8972..2eb7f2e 100644
--- a/identity/aidl/default/common/PresentationSession.cpp
+++ b/identity/aidl/default/common/PresentationSession.cpp
@@ -122,8 +122,8 @@
 ndk::ScopedAStatus PresentationSession::getCredential(
         const vector<uint8_t>& credentialData, shared_ptr<IIdentityCredential>* outCredential) {
     shared_ptr<PresentationSession> p = ref<PresentationSession>();
-    shared_ptr<IdentityCredential> credential =
-            ndk::SharedRefBase::make<IdentityCredential>(hwProxyFactory_, credentialData, p);
+    shared_ptr<IdentityCredential> credential = ndk::SharedRefBase::make<IdentityCredential>(
+            hwProxyFactory_, credentialData, p, hardwareInformation_);
     int ret = credential->initialize();
     if (ret != IIdentityCredentialStore::STATUS_OK) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
diff --git a/identity/aidl/default/common/PresentationSession.h b/identity/aidl/default/common/PresentationSession.h
index 76ca67b..4cb174a 100644
--- a/identity/aidl/default/common/PresentationSession.h
+++ b/identity/aidl/default/common/PresentationSession.h
@@ -38,8 +38,11 @@
 class PresentationSession : public BnPresentationSession {
   public:
     PresentationSession(sp<SecureHardwareProxyFactory> hwProxyFactory,
-                        sp<SecureHardwareSessionProxy> hwProxy)
-        : hwProxyFactory_(std::move(hwProxyFactory)), hwProxy_(std::move(hwProxy)) {}
+                        sp<SecureHardwareSessionProxy> hwProxy,
+                        HardwareInformation hardwareInformation)
+        : hwProxyFactory_(std::move(hwProxyFactory)),
+          hwProxy_(std::move(hwProxy)),
+          hardwareInformation_(std::move(hardwareInformation)) {}
 
     virtual ~PresentationSession();
 
@@ -65,6 +68,7 @@
     // Set by constructor
     sp<SecureHardwareProxyFactory> hwProxyFactory_;
     sp<SecureHardwareSessionProxy> hwProxy_;
+    HardwareInformation hardwareInformation_;
 
     // Set by initialize()
     uint64_t id_;
diff --git a/identity/aidl/default/common/SecureHardwareProxy.h b/identity/aidl/default/common/SecureHardwareProxy.h
index a580444..9f63ad8 100644
--- a/identity/aidl/default/common/SecureHardwareProxy.h
+++ b/identity/aidl/default/common/SecureHardwareProxy.h
@@ -82,6 +82,18 @@
     virtual optional<vector<uint8_t>> createCredentialKey(const vector<uint8_t>& challenge,
                                                           const vector<uint8_t>& applicationId) = 0;
 
+    // Returns public key certificate with a remotely provisioned attestation key.
+    //
+    // This returns a single certificate that is signed by the given |attestationKeyBlob|.
+    // The implementation of eicOpsCreateCredentialKey() on the TA side must coordinate
+    // with its corresponding keymint implementation to sign using the attestation key. The
+    // |attestationKeyCert| parameter is the certificates for |attestationKeyBlob|,
+    // formatted as concatenated, DER-encoded, X.509 certificates.
+    virtual optional<vector<uint8_t>> createCredentialKeyUsingRkp(
+            const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+            const vector<uint8_t>& attestationKeyBlob,
+            const vector<uint8_t>& attestationKeyCert) = 0;
+
     virtual bool startPersonalization(int accessControlProfileCount, const vector<int>& entryCounts,
                                       const string& docType,
                                       size_t expectedProofOfProvisioningSize) = 0;
diff --git a/identity/aidl/default/common/WritableIdentityCredential.cpp b/identity/aidl/default/common/WritableIdentityCredential.cpp
index 200ee61..e420a7b 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/common/WritableIdentityCredential.cpp
@@ -79,8 +79,15 @@
                 IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge can not be empty"));
     }
 
-    optional<vector<uint8_t>> certChain =
-            hwProxy_->createCredentialKey(attestationChallenge, attestationApplicationId);
+    optional<vector<uint8_t>> certChain;
+    if (attestationKeyBlob_ && attestationCertificateChain_) {
+        certChain = hwProxy_->createCredentialKeyUsingRkp(
+                attestationChallenge, attestationApplicationId, *attestationKeyBlob_,
+                attestationCertificateChain_->at(0));
+    } else {
+        certChain = hwProxy_->createCredentialKey(attestationChallenge, attestationApplicationId);
+    }
+
     if (!certChain) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
@@ -95,8 +102,14 @@
     }
 
     *outCertificateChain = vector<Certificate>();
-    for (const vector<uint8_t>& cert : certs.value()) {
-        Certificate c = Certificate();
+    for (vector<uint8_t>& cert : certs.value()) {
+        Certificate c;
+        c.encodedCertificate = std::move(cert);
+        outCertificateChain->push_back(std::move(c));
+    }
+
+    for (const vector<uint8_t>& cert : *attestationCertificateChain_) {
+        Certificate c;
         c.encodedCertificate = cert;
         outCertificateChain->push_back(std::move(c));
     }
@@ -402,4 +415,36 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus WritableIdentityCredential::setRemotelyProvisionedAttestationKey(
+        const vector<uint8_t>& attestationKeyBlob,
+        const vector<uint8_t>& attestationCertificateChain) {
+    if (!hardwareInformation_.isRemoteKeyProvisioningSupported) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(
+                EX_UNSUPPORTED_OPERATION, "Remote key provisioning is not supported"));
+    }
+
+    if (attestationKeyBlob.empty() || attestationCertificateChain.empty()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Empty data passed to setRemotlyProvisionedAttestationKey"));
+    }
+
+    if (attestationKeyBlob_.has_value()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Attestation key already set"));
+    }
+
+    optional<vector<vector<uint8_t>>> certs =
+            support::certificateChainSplit(attestationCertificateChain);
+    if (!certs) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error splitting chain into separate certificates"));
+    }
+
+    attestationKeyBlob_ = attestationKeyBlob;
+    attestationCertificateChain_ = *certs;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/common/WritableIdentityCredential.h b/identity/aidl/default/common/WritableIdentityCredential.h
index 36ad430..39d32c9 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.h
+++ b/identity/aidl/default/common/WritableIdentityCredential.h
@@ -30,6 +30,7 @@
 
 using ::android::sp;
 using ::android::hardware::identity::SecureHardwareProvisioningProxy;
+using ::std::optional;
 using ::std::set;
 using ::std::string;
 using ::std::vector;
@@ -41,8 +42,11 @@
     // For an updated credential, call initializeForUpdate() right after construction.
     //
     WritableIdentityCredential(sp<SecureHardwareProvisioningProxy> hwProxy, const string& docType,
-                               bool testCredential)
-        : hwProxy_(hwProxy), docType_(docType), testCredential_(testCredential) {}
+                               bool testCredential, HardwareInformation hardwareInformation)
+        : hwProxy_(hwProxy),
+          docType_(docType),
+          testCredential_(testCredential),
+          hardwareInformation_(std::move(hardwareInformation)) {}
 
     ~WritableIdentityCredential();
 
@@ -78,11 +82,16 @@
             vector<uint8_t>* outCredentialData,
             vector<uint8_t>* outProofOfProvisioningSignature) override;
 
+    ndk::ScopedAStatus setRemotelyProvisionedAttestationKey(
+            const vector<uint8_t>& attestationKeyBlob,
+            const vector<uint8_t>& attestationCertificateChain) override;
+
   private:
     // Set by constructor.
     sp<SecureHardwareProvisioningProxy> hwProxy_;
     string docType_;
     bool testCredential_;
+    HardwareInformation hardwareInformation_;
 
     // This is set in initialize().
     bool startPersonalizationCalled_;
@@ -109,6 +118,10 @@
     vector<int32_t> entryAccessControlProfileIds_;
     vector<uint8_t> entryBytes_;
     set<string> allNameSpaces_;
+
+    // Remotely provisioned attestation data, set via setRemotelyProvisionedAttestationKey
+    optional<vector<uint8_t>> attestationKeyBlob_;
+    optional<vector<vector<uint8_t>>> attestationCertificateChain_;
 };
 
 }  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/libeic/EicOps.h b/identity/aidl/default/libeic/EicOps.h
index aa26e62..df96c7d 100644
--- a/identity/aidl/default/libeic/EicOps.h
+++ b/identity/aidl/default/libeic/EicOps.h
@@ -196,13 +196,19 @@
 
 // Generates CredentialKey plus an attestation certificate.
 //
-// The attestation certificate will be signed by the attestation keys the secure
-// area has been provisioned with. The given |challenge| and |applicationId|
-// will be used as will |testCredential|.
+// If |attestationKeyBlob| is non-NULL, the certificate must be signed by the
+// the provided attestation key. Else, the certificate must be signed by the
+// attestation key that the secure area has been factory provisioned with. The
+// given |challenge|, |applicationId|, and |testCredential| must be signed
+// into the attestation.
 //
-// The generated certificate will be in X.509 format and returned in |cert|
-// and |certSize| must be set to the size of this array and this function will
-// set it to the size of the certification chain on successfully return.
+// When |attestationKeyBlob| is non-NULL, then |attestationKeyCert| must
+// also be passed so that the underlying implementation can properly chain up
+// the newly-generated certificate to the existing chain.
+//
+// The generated certificate must be in X.509 format and returned in |cert|
+// and |certSize| must be set to the size of this array. This function must
+// set |certSize| to the size of the certification chain on successfully return.
 //
 // This may return either a single certificate or an entire certificate
 // chain. If it returns only a single certificate, the implementation of
@@ -211,8 +217,10 @@
 //
 bool eicOpsCreateCredentialKey(uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE], const uint8_t* challenge,
                                size_t challengeSize, const uint8_t* applicationId,
-                               size_t applicationIdSize, bool testCredential, uint8_t* cert,
-                               size_t* certSize);  // inout
+                               size_t applicationIdSize, bool testCredential,
+                               const uint8_t* attestationKeyBlob, size_t attestationKeyBlobSize,
+                               const uint8_t* attestationKeyCert, size_t attestationKeyCertSize,
+                               uint8_t* /*out*/ cert, size_t* /*inout*/ certSize);
 
 // Generate an X.509 certificate for the key identified by |publicKey| which
 // must be of the form returned by eicOpsCreateEcKey().
diff --git a/identity/aidl/default/libeic/EicProvisioning.c b/identity/aidl/default/libeic/EicProvisioning.c
index a241b71..ff009dd 100644
--- a/identity/aidl/default/libeic/EicProvisioning.c
+++ b/identity/aidl/default/libeic/EicProvisioning.c
@@ -133,7 +133,10 @@
 
 bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
                                         size_t challengeSize, const uint8_t* applicationId,
-                                        size_t applicationIdSize, uint8_t* publicKeyCert,
+                                        size_t applicationIdSize, const uint8_t* attestationKeyBlob,
+                                        size_t attestationKeyBlobSize,
+                                        const uint8_t* attestationKeyCert,
+                                        size_t attestationKeyCertSize, uint8_t* publicKeyCert,
                                         size_t* publicKeyCertSize) {
     if (ctx->isUpdate) {
         eicDebug("Cannot create CredentialKey on update");
@@ -142,7 +145,9 @@
 
     if (!eicOpsCreateCredentialKey(ctx->credentialPrivateKey, challenge, challengeSize,
                                    applicationId, applicationIdSize, ctx->testCredential,
-                                   publicKeyCert, publicKeyCertSize)) {
+                                   attestationKeyBlob, attestationKeyBlobSize, attestationKeyCert,
+                                   attestationKeyCertSize, publicKeyCert, publicKeyCertSize)) {
+        eicDebug("Error creating credential key");
         return false;
     }
     return true;
diff --git a/identity/aidl/default/libeic/EicProvisioning.h b/identity/aidl/default/libeic/EicProvisioning.h
index d94f8f1..2619bfc 100644
--- a/identity/aidl/default/libeic/EicProvisioning.h
+++ b/identity/aidl/default/libeic/EicProvisioning.h
@@ -77,7 +77,10 @@
 
 bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
                                         size_t challengeSize, const uint8_t* applicationId,
-                                        size_t applicationIdSize, uint8_t* publicKeyCert,
+                                        size_t applicationIdSize, const uint8_t* attestationKeyBlob,
+                                        size_t attestationKeyBlobSize,
+                                        const uint8_t* attestationKeyCert,
+                                        size_t attestationKeyCertSize, uint8_t* publicKeyCert,
                                         size_t* publicKeyCertSize);
 
 bool eicProvisioningStartPersonalization(EicProvisioning* ctx, int accessControlProfileCount,
diff --git a/identity/aidl/default/service.cpp b/identity/aidl/default/service.cpp
index 1ff52f9..ed3c4cb 100644
--- a/identity/aidl/default/service.cpp
+++ b/identity/aidl/default/service.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "android.hardware.identity-service"
 
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
@@ -32,6 +33,7 @@
 using ::android::base::StderrLogger;
 
 using ::aidl::android::hardware::identity::IdentityCredentialStore;
+using ::aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
 using ::android::hardware::identity::FakeSecureHardwareProxyFactory;
 using ::android::hardware::identity::SecureHardwareProxyFactory;
 
@@ -47,10 +49,13 @@
     InitLogging(argv, ComboLogger);
 
     sp<SecureHardwareProxyFactory> hwProxyFactory = new FakeSecureHardwareProxyFactory();
+    const std::string remotelyProvisionedComponentName =
+            std::string(IRemotelyProvisionedComponent::descriptor) + "/default";
 
     ABinderProcess_setThreadPoolMaxThreadCount(0);
     std::shared_ptr<IdentityCredentialStore> store =
-            ndk::SharedRefBase::make<IdentityCredentialStore>(hwProxyFactory);
+            ndk::SharedRefBase::make<IdentityCredentialStore>(hwProxyFactory,
+                                                              remotelyProvisionedComponentName);
 
     const std::string instance = std::string() + IdentityCredentialStore::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(store->asBinder().get(), instance.c_str());
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 7b6f2c8..c5b84a1 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -11,6 +11,8 @@
     name: "VtsHalIdentityTargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "keymint_use_latest_hal_aidl_cpp_static",
+        "keymint_use_latest_hal_aidl_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
     ],
     cflags: [
@@ -32,12 +34,15 @@
     ],
     shared_libs: [
         "libbinder",
+        "libbinder_ndk",
         "libcrypto",
     ],
     static_libs: [
+        "android.hardware.security.secureclock-V1-ndk",
         "libcppbor_external",
         "libcppcose_rkp",
         "libkeymaster_portable",
+        "libkeymint_vts_test_utils",
         "libpuresoftkeymasterdevice",
         "android.hardware.keymaster@4.0",
         "android.hardware.identity-support-lib",
@@ -46,6 +51,7 @@
         "android.hardware.keymaster-V4-ndk",
         "libkeymaster4support",
         "libkeymaster4_1support",
+        "libkeymint_remote_prov_support",
     ],
     test_suites: [
         "general-tests",
diff --git a/identity/aidl/vts/Util.cpp b/identity/aidl/vts/Util.cpp
index 1148cb0..f3d7c30 100644
--- a/identity/aidl/vts/Util.cpp
+++ b/identity/aidl/vts/Util.cpp
@@ -20,12 +20,16 @@
 
 #include <android-base/logging.h>
 
+#include <KeyMintAidlTestBase.h>
 #include <aidl/Gtest.h>
+#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
 #include <android-base/stringprintf.h>
 #include <keymaster/km_openssl/openssl_utils.h>
 #include <keymasterV4_1/attestation_record.h>
-#include <charconv>
+#include <keymint_support/openssl_utils.h>
+#include <openssl/evp.h>
 
+#include <charconv>
 #include <map>
 
 namespace android::hardware::identity::test_utils {
@@ -36,10 +40,13 @@
 using std::string;
 using std::vector;
 
+using ::aidl::android::hardware::security::keymint::test::check_maced_pubkey;
+using ::aidl::android::hardware::security::keymint::test::p256_pub_key;
 using ::android::sp;
 using ::android::String16;
 using ::android::base::StringPrintf;
 using ::android::binder::Status;
+using ::android::hardware::security::keymint::MacedPublicKey;
 using ::keymaster::X509_Ptr;
 
 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
@@ -58,6 +65,77 @@
     }
 }
 
+optional<vector<vector<uint8_t>>> createFakeRemotelyProvisionedCertificateChain(
+        const MacedPublicKey& macedPublicKey) {
+    // The helper library uses the NDK symbols, so play a little trickery here to convert
+    // the data into the proper type so we can reuse the helper function to get the pubkey.
+    ::aidl::android::hardware::security::keymint::MacedPublicKey ndkMacedPublicKey;
+    ndkMacedPublicKey.macedKey = macedPublicKey.macedKey;
+
+    vector<uint8_t> publicKeyBits;
+    check_maced_pubkey(ndkMacedPublicKey, /*testMode=*/true, &publicKeyBits);
+
+    ::aidl::android::hardware::security::keymint::EVP_PKEY_Ptr publicKey;
+    p256_pub_key(publicKeyBits, &publicKey);
+
+    // Generate an arbitrary root key for our chain
+    bssl::UniquePtr<EC_KEY> ecRootKey(EC_KEY_new());
+    bssl::UniquePtr<EVP_PKEY> rootKey(EVP_PKEY_new());
+    if (ecRootKey.get() == nullptr || rootKey.get() == nullptr) {
+        LOG(ERROR) << "Memory allocation failed";
+        return {};
+    }
+
+    bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    if (group.get() == nullptr) {
+        LOG(ERROR) << "Error creating EC group by curve name";
+        return {};
+    }
+
+    if (EC_KEY_set_group(ecRootKey.get(), group.get()) != 1 ||
+        EC_KEY_generate_key(ecRootKey.get()) != 1 || EC_KEY_check_key(ecRootKey.get()) < 0) {
+        LOG(ERROR) << "Error generating key";
+        return {};
+    }
+
+    if (EVP_PKEY_set1_EC_KEY(rootKey.get(), ecRootKey.get()) != 1) {
+        LOG(ERROR) << "Error getting private key";
+        return {};
+    }
+
+    // The VTS test does not fully validate the chain, so we're ok without the proper CA extensions.
+    map<string, vector<uint8_t>> extensions;
+
+    // Now make a self-signed cert
+    optional<vector<uint8_t>> root = support::ecPublicKeyGenerateCertificate(
+            rootKey.get(), rootKey.get(),
+            /*serialDecimal=*/"31415",
+            /*subject=*/"Android IdentityCredential VTS Test Root Certificate",
+            /*subject=*/"Android IdentityCredential VTS Test Root Certificate",
+            /*validityNotBefore=*/time(nullptr),
+            /*validityNotAfter=*/time(nullptr) + 365 * 24 * 3600, extensions);
+    if (!root) {
+        LOG(ERROR) << "Error generating root cert";
+        return std::nullopt;
+    }
+
+    // Now sign a CA cert so that we have a chain that's good enough to satisfy
+    // the VTS tests.
+    optional<vector<uint8_t>> intermediate = support::ecPublicKeyGenerateCertificate(
+            publicKey.get(), rootKey.get(),
+            /*serialDecimal=*/"42",
+            /*subject=*/"Android IdentityCredential VTS Test Root Certificate",
+            /*subject=*/"Android IdentityCredential VTS Test Attestation Certificate",
+            /*validityNotBefore=*/time(nullptr),
+            /*validityNotAfter=*/time(nullptr) + 365 * 24 * 3600, extensions);
+    if (!intermediate) {
+        LOG(ERROR) << "Error generating intermediate cert";
+        return std::nullopt;
+    }
+
+    return vector<vector<uint8_t>>{std::move(*intermediate), std::move(*root)};
+}
+
 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal) {
     vector<uint8_t> privKey;
     return generateReaderCertificate(serialDecimal, &privKey);
diff --git a/identity/aidl/vts/Util.h b/identity/aidl/vts/Util.h
index 80e52a2..b120dc9 100644
--- a/identity/aidl/vts/Util.h
+++ b/identity/aidl/vts/Util.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/identity/IIdentityCredentialStore.h>
 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <android/hardware/security/keymint/MacedPublicKey.h>
 #include <cppbor.h>
 #include <cppbor_parse.h>
 #include <gtest/gtest.h>
@@ -97,6 +98,9 @@
 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
                              sp<IIdentityCredentialStore>& credentialStore, bool testCredential);
 
+optional<vector<vector<uint8_t>>> createFakeRemotelyProvisionedCertificateChain(
+        const ::android::hardware::security::keymint::MacedPublicKey& macedPublicKey);
+
 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal);
 
 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index bc37020..94d4c88 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -18,6 +18,8 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
 #include <android-base/logging.h>
 #include <android/hardware/identity/IIdentityCredentialStore.h>
 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
@@ -42,6 +44,8 @@
 using ::android::sp;
 using ::android::String16;
 using ::android::binder::Status;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::hardware::security::keymint::MacedPublicKey;
 
 class IdentityCredentialTests : public testing::TestWithParam<string> {
   public:
@@ -101,6 +105,103 @@
                                                attestationApplicationId, false);
 }
 
+TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithRemoteProvisioning) {
+    HardwareInformation hwInfo;
+    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+    if (!hwInfo.isRemoteKeyProvisioningSupported) {
+        GTEST_SKIP() << "Remote provisioning is not supported";
+    }
+
+    Status result;
+
+    sp<IWritableIdentityCredential> writableCredential;
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
+
+    sp<IRemotelyProvisionedComponent> rpc;
+    result = credentialStore_->getRemotelyProvisionedComponent(&rpc);
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    MacedPublicKey macedPublicKey;
+    std::vector<uint8_t> attestationKey;
+    result = rpc->generateEcdsaP256KeyPair(/*testMode=*/true, &macedPublicKey, &attestationKey);
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    optional<vector<vector<uint8_t>>> remotelyProvisionedCertChain =
+            test_utils::createFakeRemotelyProvisionedCertificateChain(macedPublicKey);
+    ASSERT_TRUE(remotelyProvisionedCertChain);
+
+    vector<uint8_t> concatenatedCerts;
+    for (const vector<uint8_t>& cert : *remotelyProvisionedCertChain) {
+        concatenatedCerts.insert(concatenatedCerts.end(), cert.begin(), cert.end());
+    }
+    result = writableCredential->setRemotelyProvisionedAttestationKey(attestationKey,
+                                                                      concatenatedCerts);
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
+    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+    vector<Certificate> attestationCertificate;
+    vector<uint8_t> attestationApplicationId = {1};
+
+    result = writableCredential->getAttestationCertificate(
+            attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    test_utils::validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                               attestationApplicationId, false);
+
+    ASSERT_EQ(remotelyProvisionedCertChain->size() + 1, attestationCertificate.size());
+    for (size_t i = 0; i < remotelyProvisionedCertChain->size(); ++i) {
+        ASSERT_EQ(remotelyProvisionedCertChain->at(i),
+                  attestationCertificate[i + 1].encodedCertificate)
+                << "Certificate mismatch (cert index " << i + 1 << " out of "
+                << attestationCertificate.size() << " total certs)";
+    }
+}
+
+TEST_P(IdentityCredentialTests, verifyRemotelyProvisionedKeyMayOnlyBeSetOnce) {
+    HardwareInformation hwInfo;
+    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+    if (!hwInfo.isRemoteKeyProvisioningSupported) {
+        GTEST_SKIP() << "Remote provisioning is not supported";
+    }
+
+    sp<IRemotelyProvisionedComponent> rpc;
+    Status result = credentialStore_->getRemotelyProvisionedComponent(&rpc);
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    MacedPublicKey macedPublicKey;
+    std::vector<uint8_t> attestationKey;
+    result = rpc->generateEcdsaP256KeyPair(/*testMode=*/true, &macedPublicKey, &attestationKey);
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    optional<vector<vector<uint8_t>>> remotelyProvisionedCertChain =
+            test_utils::createFakeRemotelyProvisionedCertificateChain(macedPublicKey);
+    ASSERT_TRUE(remotelyProvisionedCertChain);
+
+    vector<uint8_t> concatenatedCerts;
+    for (const vector<uint8_t>& cert : *remotelyProvisionedCertChain) {
+        concatenatedCerts.insert(concatenatedCerts.end(), cert.begin(), cert.end());
+    }
+
+    sp<IWritableIdentityCredential> writableCredential;
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    /*testCredential=*/false));
+
+    result = writableCredential->setRemotelyProvisionedAttestationKey(attestationKey,
+                                                                      concatenatedCerts);
+    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage();
+
+    // Now try again, and verify that the implementation rejects it.
+    result = writableCredential->setRemotelyProvisionedAttestationKey(attestationKey,
+                                                                      concatenatedCerts);
+    EXPECT_FALSE(result.isOk());
+}
+
 TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
     Status result;