Identity Credential changes for Android 12

- Add IIdentityCredential.deleteCredentialWithChallenge()
- Deprecate IIdentityCredential.deleteCredential()
- Add IIdentityCredential.proveOwership()
- Add IIdentityCredential.updateCredential()
- Add ProofOfBinding CBOR to AuthenticationKey X.509 certificate
- Document which API versions new methods/features appeared in.
- Mention need to declare android.hardware.identity_credential system
  feature (w/ feature version number) and do this for the default
  implementation.

Bug: 170146643
Test: atest VtsHalIdentityTargetTest
Change-Id: Ib47c7caa5f3d6fff6919f019eee44a735dba9cf8
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 7f342d0..8744648 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -12,6 +12,7 @@
     cflags: [
         "-Wall",
         "-Wextra",
+        "-Wno-deprecated-declarations",
     ],
     shared_libs: [
         "liblog",
@@ -28,8 +29,8 @@
         "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-ndk_platform",
-        "android.hardware.keymaster-ndk_platform",
+        "android.hardware.identity-unstable-ndk_platform",
+        "android.hardware.keymaster-unstable-ndk_platform",
     ],
 }
 
@@ -88,8 +89,8 @@
         "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-ndk_platform",
-        "android.hardware.keymaster-ndk_platform",
+        "android.hardware.identity-unstable-ndk_platform",
+        "android.hardware.keymaster-unstable-ndk_platform",
         "android.hardware.identity-libeic-hal-common",
         "android.hardware.identity-libeic-library",
     ],
@@ -97,4 +98,14 @@
         "service.cpp",
         "FakeSecureHardwareProxy.cpp",
     ],
+    required: [
+        "android.hardware.identity_credential.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "android.hardware.identity_credential.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.identity_credential.xml",
 }
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index 3f2ec8b..8ec4cc9 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -45,6 +45,7 @@
 
 #include "EicOps.h"
 
+using ::std::map;
 using ::std::optional;
 using ::std::string;
 using ::std::tuple;
@@ -212,7 +213,8 @@
         return false;
     }
     if (privKey.value().size() != EIC_P256_PRIV_KEY_SIZE) {
-        eicDebug("Private key is not %zd bytes long as expected", (size_t)EIC_P256_PRIV_KEY_SIZE);
+        eicDebug("Private key is %zd bytes, expected %zd", privKey.value().size(),
+                 (size_t)EIC_P256_PRIV_KEY_SIZE);
         return false;
     }
 
@@ -224,7 +226,7 @@
     }
     // ecKeyPairGetPublicKey() returns 0x04 | x | y, we don't want the leading 0x04.
     if (pubKey.value().size() != EIC_P256_PUB_KEY_SIZE + 1) {
-        eicDebug("Private key is %zd bytes long, expected %zd", pubKey.value().size(),
+        eicDebug("Public key is %zd bytes long, expected %zd", pubKey.value().size(),
                  (size_t)EIC_P256_PRIV_KEY_SIZE + 1);
         return false;
     }
@@ -272,7 +274,8 @@
         return false;
     }
     if (privKey.value().size() != EIC_P256_PRIV_KEY_SIZE) {
-        eicDebug("Private key is not %zd bytes long as expected", (size_t)EIC_P256_PRIV_KEY_SIZE);
+        eicDebug("Private key is %zd bytes, expected %zd", privKey.value().size(),
+                 (size_t)EIC_P256_PRIV_KEY_SIZE);
         return false;
     }
 
@@ -284,8 +287,8 @@
 bool eicOpsSignEcKey(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
                      const uint8_t signingKey[EIC_P256_PRIV_KEY_SIZE], unsigned int serial,
                      const char* issuerName, const char* subjectName, time_t validityNotBefore,
-                     time_t validityNotAfter, uint8_t* cert,
-                     size_t* certSize) {  // inout
+                     time_t validityNotAfter, const uint8_t* proofOfBinding,
+                     size_t proofOfBindingSize, uint8_t* cert, size_t* certSize) {  // inout
     vector<uint8_t> signingKeyVec(EIC_P256_PRIV_KEY_SIZE);
     memcpy(signingKeyVec.data(), signingKey, EIC_P256_PRIV_KEY_SIZE);
 
@@ -293,12 +296,18 @@
     pubKeyVec[0] = 0x04;
     memcpy(pubKeyVec.data() + 1, publicKey, EIC_P256_PUB_KEY_SIZE);
 
-    std::string serialDecimal = android::base::StringPrintf("%d", serial);
+    string serialDecimal = android::base::StringPrintf("%d", serial);
+
+    map<string, vector<uint8_t>> extensions;
+    if (proofOfBinding != nullptr) {
+        vector<uint8_t> proofOfBindingVec(proofOfBinding, proofOfBinding + proofOfBindingSize);
+        extensions["1.3.6.1.4.1.11129.2.1.26"] = proofOfBindingVec;
+    }
 
     optional<vector<uint8_t>> certVec =
             android::hardware::identity::support::ecPublicKeyGenerateCertificate(
                     pubKeyVec, signingKeyVec, serialDecimal, issuerName, subjectName,
-                    validityNotBefore, validityNotAfter);
+                    validityNotBefore, validityNotAfter, extensions);
     if (!certVec) {
         eicDebug("Error generating certificate");
         return false;
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.cpp b/identity/aidl/default/FakeSecureHardwareProxy.cpp
index de6762f..287ffb8 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.cpp
+++ b/identity/aidl/default/FakeSecureHardwareProxy.cpp
@@ -67,6 +67,13 @@
     return eicProvisioningInit(&ctx_, testCredential);
 }
 
+bool FakeSecureHardwareProvisioningProxy::initializeForUpdate(
+        bool testCredential, string docType, vector<uint8_t> encryptedCredentialKeys) {
+    return eicProvisioningInitForUpdate(&ctx_, testCredential, docType.c_str(),
+                                        encryptedCredentialKeys.data(),
+                                        encryptedCredentialKeys.size());
+}
+
 // Returns public key certificate.
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::createCredentialKey(
         const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
@@ -140,14 +147,16 @@
     return signatureOfToBeSigned;
 }
 
-// Returns encryptedCredentialKeys (80 bytes).
+// Returns encryptedCredentialKeys.
 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::finishGetCredentialData(
         const string& docType) {
-    vector<uint8_t> encryptedCredentialKeys(80);
+    vector<uint8_t> encryptedCredentialKeys(116);
+    size_t size = encryptedCredentialKeys.size();
     if (!eicProvisioningFinishGetCredentialData(&ctx_, docType.c_str(),
-                                                encryptedCredentialKeys.data())) {
+                                                encryptedCredentialKeys.data(), &size)) {
         return {};
     }
+    encryptedCredentialKeys.resize(size);
     return encryptedCredentialKeys;
 }
 
@@ -162,7 +171,7 @@
     LOG(INFO) << "FakeSecureHardwarePresentationProxy created, sizeof(EicPresentation): "
               << sizeof(EicPresentation);
     return eicPresentationInit(&ctx_, testCredential, docType.c_str(),
-                               encryptedCredentialKeys.data());
+                               encryptedCredentialKeys.data(), encryptedCredentialKeys.size());
 }
 
 // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component)
@@ -312,13 +321,27 @@
 }
 
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::deleteCredential(
-        const string& docType, size_t proofOfDeletionCborSize) {
+        const string& docType, const vector<uint8_t>& challenge, bool includeChallenge,
+        size_t proofOfDeletionCborSize) {
     vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
-    if (!eicPresentationDeleteCredential(&ctx_, docType.c_str(), proofOfDeletionCborSize,
+    if (!eicPresentationDeleteCredential(&ctx_, docType.c_str(), challenge.data(), challenge.size(),
+                                         includeChallenge, proofOfDeletionCborSize,
                                          signatureOfToBeSigned.data())) {
         return {};
     }
     return signatureOfToBeSigned;
 }
 
+optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::proveOwnership(
+        const string& docType, bool testCredential, const vector<uint8_t>& challenge,
+        size_t proofOfOwnershipCborSize) {
+    vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
+    if (!eicPresentationProveOwnership(&ctx_, docType.c_str(), testCredential, challenge.data(),
+                                       challenge.size(), proofOfOwnershipCborSize,
+                                       signatureOfToBeSigned.data())) {
+        return {};
+    }
+    return signatureOfToBeSigned;
+}
+
 }  // namespace android::hardware::identity
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.h b/identity/aidl/default/FakeSecureHardwareProxy.h
index b858dd4..6852c1a 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.h
+++ b/identity/aidl/default/FakeSecureHardwareProxy.h
@@ -32,6 +32,9 @@
 
     bool initialize(bool testCredential) override;
 
+    bool initializeForUpdate(bool testCredential, string docType,
+                             vector<uint8_t> encryptedCredentialKeys) override;
+
     bool shutdown() override;
 
     // Returns public key certificate.
@@ -122,8 +125,14 @@
     optional<vector<uint8_t>> finishRetrieval() override;
 
     optional<vector<uint8_t>> deleteCredential(const string& docType,
+                                               const vector<uint8_t>& challenge,
+                                               bool includeChallenge,
                                                size_t proofOfDeletionCborSize) override;
 
+    optional<vector<uint8_t>> proveOwnership(const string& docType, bool testCredential,
+                                             const vector<uint8_t>& challenge,
+                                             size_t proofOfOwnershipCborSize) override;
+
     bool shutdown() override;
 
   protected:
diff --git a/identity/aidl/default/android.hardware.identity_credential.xml b/identity/aidl/default/android.hardware.identity_credential.xml
new file mode 100644
index 0000000..5149792
--- /dev/null
+++ b/identity/aidl/default/android.hardware.identity_credential.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 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.
+-->
+<permissions>
+  <feature name="android.hardware.identity_credential" version="202101" />
+</permissions>
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index 270fcfa..9477997 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -30,6 +30,7 @@
 #include <cppbor_parse.h>
 
 #include "FakeSecureHardwareProxy.h"
+#include "WritableIdentityCredential.h"
 
 namespace aidl::android::hardware::identity {
 
@@ -70,14 +71,8 @@
     docType_ = docTypeItem->value();
     testCredential_ = testCredentialItem->value();
 
-    const vector<uint8_t>& encryptedCredentialKeys = encryptedCredentialKeysItem->value();
-
-    if (encryptedCredentialKeys.size() != 80) {
-        LOG(ERROR) << "Unexpected size for encrypted CredentialKeys";
-        return IIdentityCredentialStore::STATUS_INVALID_DATA;
-    }
-
-    if (!hwProxy_->initialize(testCredential_, docType_, encryptedCredentialKeys)) {
+    encryptedCredentialKeys_ = encryptedCredentialKeysItem->value();
+    if (!hwProxy_->initialize(testCredential_, docType_, encryptedCredentialKeys_)) {
         LOG(ERROR) << "hwProxy->initialize failed";
         return false;
     }
@@ -87,12 +82,32 @@
 
 ndk::ScopedAStatus IdentityCredential::deleteCredential(
         vector<uint8_t>* outProofOfDeletionSignature) {
+    return deleteCredentialCommon({}, false, outProofOfDeletionSignature);
+}
+
+ndk::ScopedAStatus IdentityCredential::deleteCredentialWithChallenge(
+        const vector<uint8_t>& challenge, vector<uint8_t>* outProofOfDeletionSignature) {
+    return deleteCredentialCommon(challenge, true, outProofOfDeletionSignature);
+}
+
+ndk::ScopedAStatus IdentityCredential::deleteCredentialCommon(
+        const vector<uint8_t>& challenge, bool includeChallenge,
+        vector<uint8_t>* outProofOfDeletionSignature) {
+    if (challenge.size() > 32) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge too big"));
+    }
+
     cppbor::Array array = {"ProofOfDeletion", docType_, testCredential_};
+    if (includeChallenge) {
+        array = {"ProofOfDeletion", docType_, challenge, testCredential_};
+    }
+
     vector<uint8_t> proofOfDeletionCbor = array.encode();
     vector<uint8_t> podDigest = support::sha256(proofOfDeletionCbor);
 
-    optional<vector<uint8_t>> signatureOfToBeSigned =
-            hwProxy_->deleteCredential(docType_, proofOfDeletionCbor.size());
+    optional<vector<uint8_t>> signatureOfToBeSigned = hwProxy_->deleteCredential(
+            docType_, challenge, includeChallenge, proofOfDeletionCbor.size());
     if (!signatureOfToBeSigned) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED, "Error signing ProofOfDeletion"));
@@ -111,6 +126,38 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus IdentityCredential::proveOwnership(
+        const vector<uint8_t>& challenge, vector<uint8_t>* outProofOfOwnershipSignature) {
+    if (challenge.size() > 32) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge too big"));
+    }
+
+    cppbor::Array array;
+    array = {"ProofOfOwnership", docType_, challenge, testCredential_};
+    vector<uint8_t> proofOfOwnershipCbor = array.encode();
+    vector<uint8_t> podDigest = support::sha256(proofOfOwnershipCbor);
+
+    optional<vector<uint8_t>> signatureOfToBeSigned = hwProxy_->proveOwnership(
+            docType_, testCredential_, challenge, proofOfOwnershipCbor.size());
+    if (!signatureOfToBeSigned) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error signing ProofOfOwnership"));
+    }
+
+    optional<vector<uint8_t>> signature =
+            support::coseSignEcDsaWithSignature(signatureOfToBeSigned.value(),
+                                                proofOfOwnershipCbor,  // data
+                                                {});                   // certificateChain
+    if (!signature) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error signing data"));
+    }
+
+    *outProofOfOwnershipSignature = signature.value();
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
     optional<vector<uint8_t>> ephemeralPriv = hwProxy_->createEphemeralKeyPair();
     if (!ephemeralPriv) {
@@ -833,4 +880,19 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus IdentityCredential::updateCredential(
+        shared_ptr<IWritableIdentityCredential>* outWritableCredential) {
+    sp<SecureHardwareProvisioningProxy> hwProxy = hwProxyFactory_->createProvisioningProxy();
+    shared_ptr<WritableIdentityCredential> wc =
+            ndk::SharedRefBase::make<WritableIdentityCredential>(hwProxy, docType_,
+                                                                 testCredential_);
+    if (!wc->initializeForUpdate(encryptedCredentialKeys_)) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error initializing WritableIdentityCredential for update"));
+    }
+    *outWritableCredential = wc;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 2281821..9913b86 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -45,9 +45,11 @@
 
 class IdentityCredential : public BnIdentityCredential {
   public:
-    IdentityCredential(sp<SecureHardwarePresentationProxy> hwProxy,
+    IdentityCredential(sp<SecureHardwareProxyFactory> hwProxyFactory,
+                       sp<SecureHardwarePresentationProxy> hwProxy,
                        const vector<uint8_t>& credentialData)
-        : hwProxy_(hwProxy),
+        : hwProxyFactory_(hwProxyFactory),
+          hwProxy_(hwProxy),
           credentialData_(credentialData),
           numStartRetrievalCalls_(0),
           expectedDeviceNameSpacesSize_(0) {}
@@ -58,6 +60,11 @@
 
     // Methods from IIdentityCredential follow.
     ndk::ScopedAStatus deleteCredential(vector<uint8_t>* outProofOfDeletionSignature) override;
+    ndk::ScopedAStatus deleteCredentialWithChallenge(
+            const vector<uint8_t>& challenge,
+            vector<uint8_t>* outProofOfDeletionSignature) override;
+    ndk::ScopedAStatus proveOwnership(const vector<uint8_t>& challenge,
+                                      vector<uint8_t>* outProofOfOwnershipSignature) override;
     ndk::ScopedAStatus createEphemeralKeyPair(vector<uint8_t>* outKeyPair) override;
     ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) override;
     ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override;
@@ -79,8 +86,16 @@
     ndk::ScopedAStatus generateSigningKeyPair(vector<uint8_t>* outSigningKeyBlob,
                                               Certificate* outSigningKeyCertificate) override;
 
+    ndk::ScopedAStatus updateCredential(
+            shared_ptr<IWritableIdentityCredential>* outWritableCredential) override;
+
   private:
+    ndk::ScopedAStatus deleteCredentialCommon(const vector<uint8_t>& challenge,
+                                              bool includeChallenge,
+                                              vector<uint8_t>* outProofOfDeletionSignature);
+
     // Set by constructor
+    sp<SecureHardwareProxyFactory> hwProxyFactory_;
     sp<SecureHardwarePresentationProxy> hwProxy_;
     vector<uint8_t> credentialData_;
     int numStartRetrievalCalls_;
@@ -88,6 +103,7 @@
     // Set by initialize()
     string docType_;
     bool testCredential_;
+    vector<uint8_t> encryptedCredentialKeys_;
 
     // Set by createEphemeralKeyPair()
     vector<uint8_t> ephemeralPublicKey_;
diff --git a/identity/aidl/default/common/IdentityCredentialStore.cpp b/identity/aidl/default/common/IdentityCredentialStore.cpp
index 13f91aa..e6b5466 100644
--- a/identity/aidl/default/common/IdentityCredentialStore.cpp
+++ b/identity/aidl/default/common/IdentityCredentialStore.cpp
@@ -63,7 +63,7 @@
 
     sp<SecureHardwarePresentationProxy> hwProxy = hwProxyFactory_->createPresentationProxy();
     shared_ptr<IdentityCredential> credential =
-            ndk::SharedRefBase::make<IdentityCredential>(hwProxy, credentialData);
+            ndk::SharedRefBase::make<IdentityCredential>(hwProxyFactory_, hwProxy, credentialData);
     auto ret = credential->initialize();
     if (ret != IIdentityCredentialStore::STATUS_OK) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
diff --git a/identity/aidl/default/common/SecureHardwareProxy.h b/identity/aidl/default/common/SecureHardwareProxy.h
index b89ad87..a1ed1ef 100644
--- a/identity/aidl/default/common/SecureHardwareProxy.h
+++ b/identity/aidl/default/common/SecureHardwareProxy.h
@@ -64,6 +64,9 @@
 
     virtual bool initialize(bool testCredential) = 0;
 
+    virtual bool initializeForUpdate(bool testCredential, string docType,
+                                     vector<uint8_t> encryptedCredentialKeys) = 0;
+
     // Returns public key certificate chain with attestation.
     //
     // This must return an entire certificate chain and its implementation must
@@ -164,8 +167,14 @@
     virtual optional<vector<uint8_t>> finishRetrieval();
 
     virtual optional<vector<uint8_t>> deleteCredential(const string& docType,
+                                                       const vector<uint8_t>& challenge,
+                                                       bool includeChallenge,
                                                        size_t proofOfDeletionCborSize) = 0;
 
+    virtual optional<vector<uint8_t>> proveOwnership(const string& docType, bool testCredential,
+                                                     const vector<uint8_t>& challenge,
+                                                     size_t proofOfOwnershipCborSize) = 0;
+
     virtual bool shutdown() = 0;
 };
 
diff --git a/identity/aidl/default/common/WritableIdentityCredential.cpp b/identity/aidl/default/common/WritableIdentityCredential.cpp
index 1328f36..2d897c7 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/common/WritableIdentityCredential.cpp
@@ -40,7 +40,20 @@
 
 bool WritableIdentityCredential::initialize() {
     if (!hwProxy_->initialize(testCredential_)) {
-        LOG(ERROR) << "hwProxy->initialize failed";
+        LOG(ERROR) << "hwProxy->initialize() failed";
+        return false;
+    }
+    startPersonalizationCalled_ = false;
+    firstEntry_ = true;
+
+    return true;
+}
+
+// Used when updating a credential. Returns false on failure.
+bool WritableIdentityCredential::initializeForUpdate(
+        const vector<uint8_t>& encryptedCredentialKeys) {
+    if (!hwProxy_->initializeForUpdate(testCredential_, docType_, encryptedCredentialKeys)) {
+        LOG(ERROR) << "hwProxy->initializeForUpdate() failed";
         return false;
     }
     startPersonalizationCalled_ = false;
diff --git a/identity/aidl/default/common/WritableIdentityCredential.h b/identity/aidl/default/common/WritableIdentityCredential.h
index c6f0628..36ad430 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.h
+++ b/identity/aidl/default/common/WritableIdentityCredential.h
@@ -36,16 +36,22 @@
 
 class WritableIdentityCredential : public BnWritableIdentityCredential {
   public:
+    // For a new credential, call initialize() right after construction.
+    //
+    // For an updated credential, call initializeForUpdate() right after construction.
+    //
     WritableIdentityCredential(sp<SecureHardwareProvisioningProxy> hwProxy, const string& docType,
                                bool testCredential)
         : hwProxy_(hwProxy), docType_(docType), testCredential_(testCredential) {}
 
     ~WritableIdentityCredential();
 
-    // Creates the Credential Key. Returns false on failure. Must be called
-    // right after construction.
+    // Creates the Credential Key. Returns false on failure.
     bool initialize();
 
+    // Used when updating a credential. Returns false on failure.
+    bool initializeForUpdate(const vector<uint8_t>& encryptedCredentialKeys);
+
     // Methods from IWritableIdentityCredential follow.
     ndk::ScopedAStatus getAttestationCertificate(const vector<uint8_t>& attestationApplicationId,
                                                  const vector<uint8_t>& attestationChallenge,
diff --git a/identity/aidl/default/identity-default.xml b/identity/aidl/default/identity-default.xml
index 37d5b81..a074250 100644
--- a/identity/aidl/default/identity-default.xml
+++ b/identity/aidl/default/identity-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.identity</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IIdentityCredentialStore</name>
             <instance>default</instance>
diff --git a/identity/aidl/default/libeic/EicCbor.c b/identity/aidl/default/libeic/EicCbor.c
index ec049b1..fe131eb 100644
--- a/identity/aidl/default/libeic/EicCbor.c
+++ b/identity/aidl/default/libeic/EicCbor.c
@@ -17,6 +17,7 @@
 #include "EicCbor.h"
 
 void eicCborInit(EicCbor* cbor, uint8_t* buffer, size_t bufferSize) {
+    eicMemSet(cbor, '\0', sizeof(EicCbor));
     cbor->size = 0;
     cbor->bufferSize = bufferSize;
     cbor->buffer = buffer;
@@ -26,6 +27,7 @@
 
 void eicCborInitHmacSha256(EicCbor* cbor, uint8_t* buffer, size_t bufferSize,
                            const uint8_t* hmacKey, size_t hmacKeySize) {
+    eicMemSet(cbor, '\0', sizeof(EicCbor));
     cbor->size = 0;
     cbor->bufferSize = bufferSize;
     cbor->buffer = buffer;
@@ -33,6 +35,10 @@
     eicOpsHmacSha256Init(&cbor->digester.hmacSha256, hmacKey, hmacKeySize);
 }
 
+void eicCborEnableSecondaryDigesterSha256(EicCbor* cbor, EicSha256Ctx* sha256) {
+    cbor->secondaryDigesterSha256 = sha256;
+}
+
 void eicCborFinal(EicCbor* cbor, uint8_t digest[EIC_SHA256_DIGEST_SIZE]) {
     switch (cbor->digestType) {
         case EIC_CBOR_DIGEST_TYPE_SHA256:
@@ -53,6 +59,9 @@
             eicOpsHmacSha256Update(&cbor->digester.hmacSha256, data, size);
             break;
     }
+    if (cbor->secondaryDigesterSha256 != NULL) {
+        eicOpsSha256Update(cbor->secondaryDigesterSha256, data, size);
+    }
 
     if (cbor->size >= cbor->bufferSize) {
         cbor->size += size;
diff --git a/identity/aidl/default/libeic/EicCbor.h b/identity/aidl/default/libeic/EicCbor.h
index 4686b38..9c0f531 100644
--- a/identity/aidl/default/libeic/EicCbor.h
+++ b/identity/aidl/default/libeic/EicCbor.h
@@ -53,6 +53,9 @@
         EicHmacSha256Ctx hmacSha256;
     } digester;
 
+    // The secondary digester, may be unset.
+    EicSha256Ctx* secondaryDigesterSha256;
+
     // The buffer used for building up CBOR or NULL if bufferSize is 0.
     uint8_t* buffer;
 } EicCbor;
@@ -70,6 +73,14 @@
 void eicCborInitHmacSha256(EicCbor* cbor, uint8_t* buffer, size_t bufferSize,
                            const uint8_t* hmacKey, size_t hmacKeySize);
 
+/* Enables a secondary digester.
+ *
+ * May be enabled midway through processing, this can be used to e.g. calculate
+ * a digest of Sig_structure (for COSE_Sign1) and a separate digest of its
+ * payload.
+ */
+void eicCborEnableSecondaryDigesterSha256(EicCbor* cbor, EicSha256Ctx* sha256);
+
 /* Finishes building CBOR and returns the digest. */
 void eicCborFinal(EicCbor* cbor, uint8_t digest[EIC_SHA256_DIGEST_SIZE]);
 
diff --git a/identity/aidl/default/libeic/EicOps.h b/identity/aidl/default/libeic/EicOps.h
index da4dabf..d4fcf0e 100644
--- a/identity/aidl/default/libeic/EicOps.h
+++ b/identity/aidl/default/libeic/EicOps.h
@@ -207,14 +207,17 @@
 // Generate an X.509 certificate for the key identified by |publicKey| which
 // must be of the form returned by eicOpsCreateEcKey().
 //
+// If proofOfBinding is not NULL, it will be included as an OCTET_STRING
+// X.509 extension at OID 1.3.6.1.4.1.11129.2.1.26.
+//
 // The certificate will be signed by the key identified by |signingKey| which
 // must be of the form returned by eicOpsCreateEcKey().
 //
 bool eicOpsSignEcKey(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
                      const uint8_t signingKey[EIC_P256_PRIV_KEY_SIZE], unsigned int serial,
                      const char* issuerName, const char* subjectName, time_t validityNotBefore,
-                     time_t validityNotAfter, uint8_t* cert,
-                     size_t* certSize);  // inout
+                     time_t validityNotAfter, const uint8_t* proofOfBinding,
+                     size_t proofOfBindingSize, uint8_t* cert, size_t* certSize);  // inout
 
 // Uses |privateKey| to create an ECDSA signature of some data (the SHA-256 must
 // be given by |digestOfData|). Returns the signature in |signature|.
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index d3f5556..5e9a280 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -19,13 +19,28 @@
 #include <inttypes.h>
 
 bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
-                         const uint8_t encryptedCredentialKeys[80]) {
-    uint8_t credentialKeys[52];
+                         const uint8_t* encryptedCredentialKeys,
+                         size_t encryptedCredentialKeysSize) {
+    uint8_t credentialKeys[86];
+    bool expectPopSha256 = false;
+
+    // For feature version 202009 it's 52 bytes long and for feature version 202101 it's 86
+    // bytes (the additional data is the ProofOfProvisioning SHA-256). We need
+    // to support loading all feature versions.
+    //
+    if (encryptedCredentialKeysSize == 52 + 28) {
+        /* do nothing */
+    } else if (encryptedCredentialKeysSize == 86 + 28) {
+        expectPopSha256 = true;
+    } else {
+        eicDebug("Unexpected size %zd for encryptedCredentialKeys", encryptedCredentialKeysSize);
+        return false;
+    }
 
     eicMemSet(ctx, '\0', sizeof(EicPresentation));
 
     if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
-                                80,
+                                encryptedCredentialKeysSize,
                                 // DocType is the additionalAuthenticatedData
                                 (const uint8_t*)docType, eicStrLen(docType), credentialKeys)) {
         eicDebug("Error decrypting CredentialKeys");
@@ -34,25 +49,42 @@
 
     // It's supposed to look like this;
     //
+    // Feature version 202009:
+    //
     //         CredentialKeys = [
     //              bstr,   ; storageKey, a 128-bit AES key
-    //              bstr    ; credentialPrivKey, the private key for credentialKey
+    //              bstr,   ; credentialPrivKey, the private key for credentialKey
     //         ]
     //
-    // where storageKey is 16 bytes and credentialPrivateKey is 32 bytes.
+    // Feature version 202101:
     //
-    // So the first two bytes will be 0x82 0x50 indicating resp. an array of two elements
-    // and a bstr of 16 elements. Sixteen bytes later (offset 18 and 19) there will be
-    // a bstr of 32 bytes. It's encoded as two bytes 0x58 and 0x20.
+    //         CredentialKeys = [
+    //              bstr,   ; storageKey, a 128-bit AES key
+    //              bstr,   ; credentialPrivKey, the private key for credentialKey
+    //              bstr    ; proofOfProvisioning SHA-256
+    //         ]
     //
-    if (credentialKeys[0] != 0x82 || credentialKeys[1] != 0x50 || credentialKeys[18] != 0x58 ||
-        credentialKeys[19] != 0x20) {
+    // where storageKey is 16 bytes, credentialPrivateKey is 32 bytes, and proofOfProvisioning
+    // SHA-256 is 32 bytes.
+    //
+    if (credentialKeys[0] != (expectPopSha256 ? 0x83 : 0x82) ||  // array of two or three elements
+        credentialKeys[1] != 0x50 ||                             // 16-byte bstr
+        credentialKeys[18] != 0x58 || credentialKeys[19] != 0x20) {  // 32-byte bstr
         eicDebug("Invalid CBOR for CredentialKeys");
         return false;
     }
+    if (expectPopSha256) {
+        if (credentialKeys[52] != 0x58 || credentialKeys[53] != 0x20) {  // 32-byte bstr
+            eicDebug("Invalid CBOR for CredentialKeys");
+            return false;
+        }
+    }
     eicMemCpy(ctx->storageKey, credentialKeys + 2, EIC_AES_128_KEY_SIZE);
     eicMemCpy(ctx->credentialPrivateKey, credentialKeys + 20, EIC_P256_PRIV_KEY_SIZE);
     ctx->testCredential = testCredential;
+    if (expectPopSha256) {
+        eicMemCpy(ctx->proofOfProvisioningSha256, credentialKeys + 54, EIC_SHA256_DIGEST_SIZE);
+    }
     return true;
 }
 
@@ -61,6 +93,35 @@
                                            uint8_t signingKeyBlob[60]) {
     uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
     uint8_t signingKeyPub[EIC_P256_PUB_KEY_SIZE];
+    uint8_t cborBuf[64];
+
+    // Generate the ProofOfBinding CBOR to include in the X.509 certificate in
+    // IdentityCredentialAuthenticationKeyExtension CBOR. This CBOR is defined
+    // by the following CDDL
+    //
+    //   ProofOfBinding = [
+    //     "ProofOfBinding",
+    //     bstr,                  // Contains the SHA-256 of ProofOfProvisioning
+    //   ]
+    //
+    // This array may grow in the future if other information needs to be
+    // conveyed.
+    //
+    // The bytes of ProofOfBinding is is represented as an OCTET_STRING
+    // and stored at OID 1.3.6.1.4.1.11129.2.1.26.
+    //
+
+    EicCbor cbor;
+    eicCborInit(&cbor, cborBuf, sizeof cborBuf);
+    eicCborAppendArray(&cbor, 2);
+    eicCborAppendString(&cbor, "ProofOfBinding");
+    eicCborAppendByteString(&cbor, ctx->proofOfProvisioningSha256, EIC_SHA256_DIGEST_SIZE);
+    if (cbor.size > sizeof(cborBuf)) {
+        eicDebug("Exceeded buffer size");
+        return false;
+    }
+    const uint8_t* proofOfBinding = cborBuf;
+    size_t proofOfBindingSize = cbor.size;
 
     if (!eicOpsCreateEcKey(signingKeyPriv, signingKeyPub)) {
         eicDebug("Error creating signing key");
@@ -73,7 +134,8 @@
     if (!eicOpsSignEcKey(signingKeyPub, ctx->credentialPrivateKey, 1,
                          "Android Identity Credential Key",                 // issuer CN
                          "Android Identity Credential Authentication Key",  // subject CN
-                         validityNotBefore, validityNotAfter, publicKeyCert, publicKeyCertSize)) {
+                         validityNotBefore, validityNotAfter, proofOfBinding, proofOfBindingSize,
+                         publicKeyCert, publicKeyCertSize)) {
         eicDebug("Error creating certificate for signing key");
         return false;
     }
@@ -674,7 +736,8 @@
 }
 
 bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType,
-                                     size_t proofOfDeletionCborSize,
+                                     const uint8_t* challenge, size_t challengeSize,
+                                     bool includeChallenge, size_t proofOfDeletionCborSize,
                                      uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]) {
     EicCbor cbor;
 
@@ -712,9 +775,12 @@
     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, proofOfDeletionCborSize);
 
     // Finally, the CBOR that we're actually signing.
-    eicCborAppendArray(&cbor, 3);
+    eicCborAppendArray(&cbor, includeChallenge ? 4 : 3);
     eicCborAppendString(&cbor, "ProofOfDeletion");
     eicCborAppendString(&cbor, docType);
+    if (includeChallenge) {
+        eicCborAppendByteString(&cbor, challenge, challengeSize);
+    }
     eicCborAppendBool(&cbor, ctx->testCredential);
 
     uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
@@ -726,3 +792,59 @@
 
     return true;
 }
+
+bool eicPresentationProveOwnership(EicPresentation* ctx, const char* docType, bool testCredential,
+                                   const uint8_t* challenge, size_t challengeSize,
+                                   size_t proofOfOwnershipCborSize,
+                                   uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]) {
+    EicCbor cbor;
+
+    eicCborInit(&cbor, NULL, 0);
+
+    // What we're going to sign is the COSE ToBeSigned structure which
+    // looks like the following:
+    //
+    // Sig_structure = [
+    //   context : "Signature" / "Signature1" / "CounterSignature",
+    //   body_protected : empty_or_serialized_map,
+    //   ? sign_protected : empty_or_serialized_map,
+    //   external_aad : bstr,
+    //   payload : bstr
+    //  ]
+    //
+    eicCborAppendArray(&cbor, 4);
+    eicCborAppendString(&cbor, "Signature1");
+
+    // The COSE Encoded protected headers is just a single field with
+    // COSE_LABEL_ALG (1) -> COSE_ALG_ECSDA_256 (-7). For simplicitly we just
+    // hard-code the CBOR encoding:
+    static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x26};
+    eicCborAppendByteString(&cbor, coseEncodedProtectedHeaders,
+                            sizeof(coseEncodedProtectedHeaders));
+
+    // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
+    // so external_aad is the empty bstr
+    static const uint8_t externalAad[0] = {};
+    eicCborAppendByteString(&cbor, externalAad, sizeof(externalAad));
+
+    // For the payload, the _encoded_ form follows here. We handle this by simply
+    // opening a bstr, and then writing the CBOR. This requires us to know the
+    // size of said bstr, ahead of time.
+    eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, proofOfOwnershipCborSize);
+
+    // Finally, the CBOR that we're actually signing.
+    eicCborAppendArray(&cbor, 4);
+    eicCborAppendString(&cbor, "ProofOfOwnership");
+    eicCborAppendString(&cbor, docType);
+    eicCborAppendByteString(&cbor, challenge, challengeSize);
+    eicCborAppendBool(&cbor, testCredential);
+
+    uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
+    eicCborFinal(&cbor, cborSha256);
+    if (!eicOpsEcDsa(ctx->credentialPrivateKey, cborSha256, signatureOfToBeSigned)) {
+        eicDebug("Error signing proofOfDeletion");
+        return false;
+    }
+
+    return true;
+}
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index d798962..7cad068 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -31,6 +31,8 @@
 #define EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE 65
 
 typedef struct {
+    int featureLevel;
+
     uint8_t storageKey[EIC_AES_128_KEY_SIZE];
     uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE];
 
@@ -79,12 +81,17 @@
     // SHA-256 for AdditionalData, updated for each entry.
     uint8_t additionalDataSha256[EIC_SHA256_DIGEST_SIZE];
 
+    // SHA-256 of ProofOfProvisioning. Set to NUL-bytes or initialized from CredentialKeys data
+    // if credential was created with feature version 202101 or later.
+    uint8_t proofOfProvisioningSha256[EIC_SHA256_DIGEST_SIZE];
+
     size_t expectedCborSizeAtEnd;
     EicCbor cbor;
 } EicPresentation;
 
 bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
-                         const uint8_t encryptedCredentialKeys[80]);
+                         const uint8_t* encryptedCredentialKeys,
+                         size_t encryptedCredentialKeysSize);
 
 bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* docType, time_t now,
                                            uint8_t* publicKeyCert, size_t* publicKeyCertSize,
@@ -219,9 +226,19 @@
 // where content is set to the ProofOfDeletion CBOR.
 //
 bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType,
-                                     size_t proofOfDeletionCborSize,
+                                     const uint8_t* challenge, size_t challengeSize,
+                                     bool includeChallenge, size_t proofOfDeletionCborSize,
                                      uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]);
 
+// The data returned in |signatureOfToBeSigned| contains the ECDSA signature of
+// the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process"
+// where content is set to the ProofOfOwnership CBOR.
+//
+bool eicPresentationProveOwnership(EicPresentation* ctx, const char* docType, bool testCredential,
+                                   const uint8_t* challenge, size_t challengeSize,
+                                   size_t proofOfOwnershipCborSize,
+                                   uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/identity/aidl/default/libeic/EicProvisioning.c b/identity/aidl/default/libeic/EicProvisioning.c
index f16605c..3b4148e 100644
--- a/identity/aidl/default/libeic/EicProvisioning.c
+++ b/identity/aidl/default/libeic/EicProvisioning.c
@@ -26,10 +26,84 @@
     return true;
 }
 
+bool eicProvisioningInitForUpdate(EicProvisioning* ctx, bool testCredential, const char* docType,
+                                  const uint8_t* encryptedCredentialKeys,
+                                  size_t encryptedCredentialKeysSize) {
+    uint8_t credentialKeys[86];
+
+    // For feature version 202009 it's 52 bytes long and for feature version 202101 it's 86
+    // bytes (the additional data is the ProofOfProvisioning SHA-256). We need
+    // to support loading all feature versions.
+    //
+    bool expectPopSha256 = false;
+    if (encryptedCredentialKeysSize == 52 + 28) {
+        /* do nothing */
+    } else if (encryptedCredentialKeysSize == 86 + 28) {
+        expectPopSha256 = true;
+    } else {
+        eicDebug("Unexpected size %zd for encryptedCredentialKeys", encryptedCredentialKeysSize);
+        return false;
+    }
+
+    eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+    ctx->testCredential = testCredential;
+
+    if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
+                                encryptedCredentialKeysSize,
+                                // DocType is the additionalAuthenticatedData
+                                (const uint8_t*)docType, eicStrLen(docType), credentialKeys)) {
+        eicDebug("Error decrypting CredentialKeys");
+        return false;
+    }
+
+    // It's supposed to look like this;
+    //
+    // Feature version 202009:
+    //
+    //         CredentialKeys = [
+    //              bstr,   ; storageKey, a 128-bit AES key
+    //              bstr,   ; credentialPrivKey, the private key for credentialKey
+    //         ]
+    //
+    // Feature version 202101:
+    //
+    //         CredentialKeys = [
+    //              bstr,   ; storageKey, a 128-bit AES key
+    //              bstr,   ; credentialPrivKey, the private key for credentialKey
+    //              bstr    ; proofOfProvisioning SHA-256
+    //         ]
+    //
+    // where storageKey is 16 bytes, credentialPrivateKey is 32 bytes, and proofOfProvisioning
+    // SHA-256 is 32 bytes.
+    //
+    if (credentialKeys[0] != (expectPopSha256 ? 0x83 : 0x82) ||  // array of two or three elements
+        credentialKeys[1] != 0x50 ||                             // 16-byte bstr
+        credentialKeys[18] != 0x58 || credentialKeys[19] != 0x20) {  // 32-byte bstr
+        eicDebug("Invalid CBOR for CredentialKeys");
+        return false;
+    }
+    if (expectPopSha256) {
+        if (credentialKeys[52] != 0x58 || credentialKeys[53] != 0x20) {  // 32-byte bstr
+            eicDebug("Invalid CBOR for CredentialKeys");
+            return false;
+        }
+    }
+    eicMemCpy(ctx->storageKey, credentialKeys + 2, EIC_AES_128_KEY_SIZE);
+    eicMemCpy(ctx->credentialPrivateKey, credentialKeys + 20, EIC_P256_PRIV_KEY_SIZE);
+    // Note: We don't care about the previous ProofOfProvisioning SHA-256
+    ctx->isUpdate = true;
+    return true;
+}
+
 bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
                                         size_t challengeSize, const uint8_t* applicationId,
                                         size_t applicationIdSize, uint8_t* publicKeyCert,
                                         size_t* publicKeyCertSize) {
+    if (ctx->isUpdate) {
+        eicDebug("Cannot create CredentialKey on update");
+        return false;
+    }
+
     if (!eicOpsCreateCredentialKey(ctx->credentialPrivateKey, challenge, challengeSize,
                                    applicationId, applicationIdSize, ctx->testCredential,
                                    publicKeyCert, publicKeyCertSize)) {
@@ -96,6 +170,9 @@
     eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedProofOfProvisioningSize);
     ctx->expectedCborSizeAtEnd = expectedProofOfProvisioningSize + ctx->cbor.size;
 
+    eicOpsSha256Init(&ctx->proofOfProvisioningDigester);
+    eicCborEnableSecondaryDigesterSha256(&ctx->cbor, &ctx->proofOfProvisioningDigester);
+
     eicCborAppendArray(&ctx->cbor, 5);
     eicCborAppendString(&ctx->cbor, "ProofOfProvisioning");
     eicCborAppendString(&ctx->cbor, docType);
@@ -260,14 +337,23 @@
 }
 
 bool eicProvisioningFinishGetCredentialData(EicProvisioning* ctx, const char* docType,
-                                            uint8_t encryptedCredentialKeys[80]) {
+                                            uint8_t* encryptedCredentialKeys,
+                                            size_t* encryptedCredentialKeysSize) {
     EicCbor cbor;
-    uint8_t cborBuf[52];
+    uint8_t cborBuf[86];
+
+    if (*encryptedCredentialKeysSize < 86 + 28) {
+        eicDebug("encryptedCredentialKeysSize is %zd which is insufficient");
+        return false;
+    }
 
     eicCborInit(&cbor, cborBuf, sizeof(cborBuf));
-    eicCborAppendArray(&cbor, 2);
+    eicCborAppendArray(&cbor, 3);
     eicCborAppendByteString(&cbor, ctx->storageKey, EIC_AES_128_KEY_SIZE);
     eicCborAppendByteString(&cbor, ctx->credentialPrivateKey, EIC_P256_PRIV_KEY_SIZE);
+    uint8_t popSha256[EIC_SHA256_DIGEST_SIZE];
+    eicOpsSha256Final(&ctx->proofOfProvisioningDigester, popSha256);
+    eicCborAppendByteString(&cbor, popSha256, EIC_SHA256_DIGEST_SIZE);
     if (cbor.size > sizeof(cborBuf)) {
         eicDebug("Exceeded buffer size");
         return false;
@@ -285,6 +371,7 @@
         eicDebug("Error encrypting CredentialKeys");
         return false;
     }
+    *encryptedCredentialKeysSize = cbor.size + 28;
 
     return true;
 }
diff --git a/identity/aidl/default/libeic/EicProvisioning.h b/identity/aidl/default/libeic/EicProvisioning.h
index 836d16e..f064787 100644
--- a/identity/aidl/default/libeic/EicProvisioning.h
+++ b/identity/aidl/default/libeic/EicProvisioning.h
@@ -31,7 +31,7 @@
 #define EIC_MAX_NUM_ACCESS_CONTROL_PROFILE_IDS 32
 
 typedef struct {
-    // Set by eicCreateCredentialKey.
+    // Set by eicCreateCredentialKey() OR eicProvisioningInitForUpdate()
     uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE];
 
     int numEntryCounts;
@@ -43,6 +43,7 @@
     size_t curEntrySize;
     size_t curEntryNumBytesReceived;
 
+    // Set by eicProvisioningInit() OR eicProvisioningInitForUpdate()
     uint8_t storageKey[EIC_AES_128_KEY_SIZE];
 
     size_t expectedCborSizeAtEnd;
@@ -50,13 +51,23 @@
     // SHA-256 for AdditionalData, updated for each entry.
     uint8_t additionalDataSha256[EIC_SHA256_DIGEST_SIZE];
 
+    // Digester just for ProofOfProvisioning (without Sig_structure).
+    EicSha256Ctx proofOfProvisioningDigester;
+
     EicCbor cbor;
 
     bool testCredential;
+
+    // Set to true if this is an update.
+    bool isUpdate;
 } EicProvisioning;
 
 bool eicProvisioningInit(EicProvisioning* ctx, bool testCredential);
 
+bool eicProvisioningInitForUpdate(EicProvisioning* ctx, bool testCredential, const char* docType,
+                                  const uint8_t* encryptedCredentialKeys,
+                                  size_t encryptedCredentialKeysSize);
+
 bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
                                         size_t challengeSize, const uint8_t* applicationId,
                                         size_t applicationIdSize, uint8_t* publicKeyCert,
@@ -107,14 +118,18 @@
 //   CredentialKeys = [
 //     bstr,   ; storageKey, a 128-bit AES key
 //     bstr    ; credentialPrivKey, the private key for credentialKey
+//     bstr    ; SHA-256(ProofOfProvisioning)
 //   ]
 //
+// for feature version 202101. For feature version 202009 the third field was not present.
+//
 // Since |storageKey| is 16 bytes and |credentialPrivKey| is 32 bytes, the
-// encoded CBOR for CredentialKeys is 52 bytes and consequently
-// |encryptedCredentialKeys| will be 52 + 28 = 80 bytes.
+// encoded CBOR for CredentialKeys is 86 bytes and consequently
+// |encryptedCredentialKeys| will be no longer than 86 + 28 = 114 bytes.
 //
 bool eicProvisioningFinishGetCredentialData(EicProvisioning* ctx, const char* docType,
-                                            uint8_t encryptedCredentialKeys[80]);
+                                            uint8_t* encryptedCredentialKeys,
+                                            size_t* encryptedCredentialKeysSize);
 
 #ifdef __cplusplus
 }