Credstore changes for Android 12

- Add Credential.proveOwership()
- Add Credential.deleteWithChallenge()
- Add Credential.updateCredential()
- Add Credential.storeStaticAuthenticationDataWithExpirationDate()
  - Store this on disk. For entries stored without this parameter
    assume they never expire.
- Add allowUsingExpiredKeys to Credential.selectAuthKey() and
  Credential.getEntries()
  - Unless set to true, never select an expired key
- Introduce ERROR_NOT_SUPPORTED and return this if HAL does not
  support operation

Bug: 170146643
Test: atest android.security.identity.cts
Change-Id: Ic5dafc6498c9c59b82942def9d348d974f008589
diff --git a/identity/Android.bp b/identity/Android.bp
index c0f1635..dd61930 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -5,6 +5,7 @@
         // "-Werror",
         "-Wextra",
         "-Wunused",
+        "-Wno-deprecated-declarations",
     ],
     sanitize: {
         misc_undefined : ["integer"],
@@ -38,8 +39,8 @@
         "libkeystore-attestation-application-id",
     ],
     static_libs: [
-        "android.hardware.identity-cpp",
-        "android.hardware.keymaster-cpp",
+        "android.hardware.identity-unstable-cpp",
+        "android.hardware.keymaster-unstable-cpp",
         "libcppbor",
     ]
 }
diff --git a/identity/Credential.cpp b/identity/Credential.cpp
index 28ba752..4a2bae1 100644
--- a/identity/Credential.cpp
+++ b/identity/Credential.cpp
@@ -36,6 +36,7 @@
 #include "Credential.h"
 #include "CredentialData.h"
 #include "Util.h"
+#include "WritableCredential.h"
 
 namespace android {
 namespace security {
@@ -47,6 +48,8 @@
 
 using android::security::keystore::IKeystoreService;
 
+using ::android::hardware::identity::IWritableIdentityCredential;
+
 using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
 using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
 using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
@@ -58,25 +61,26 @@
 using AidlVerificationToken = android::hardware::keymaster::VerificationToken;
 
 Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
-                       const std::string& credentialName)
-    : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName) {}
+                       const std::string& credentialName, uid_t callingUid,
+                       HardwareInformation hwInfo, sp<IIdentityCredentialStore> halStoreBinder,
+                       int halApiVersion)
+    : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName),
+      callingUid_(callingUid), hwInfo_(std::move(hwInfo)), halStoreBinder_(halStoreBinder),
+      halApiVersion_(halApiVersion) {}
 
 Credential::~Credential() {}
 
-Status Credential::loadCredential(sp<IIdentityCredentialStore> halStoreBinder) {
-    uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
-    sp<CredentialData> data = new CredentialData(dataPath_, callingUid, credentialName_);
+Status Credential::ensureOrReplaceHalBinder() {
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
     if (!data->loadFromDisk()) {
         LOG(ERROR) << "Error loading data for credential";
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error loading data for credential");
     }
 
-    data_ = data;
-
     sp<IIdentityCredential> halBinder;
     Status status =
-        halStoreBinder->getCredential(cipherSuite_, data_->getCredentialData(), &halBinder);
+        halStoreBinder_->getCredential(cipherSuite_, data->getCredentialData(), &halBinder);
     if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
         int code = status.serviceSpecificErrorCode();
         if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
@@ -87,21 +91,33 @@
         LOG(ERROR) << "Error getting HAL binder";
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
     }
-
     halBinder_ = halBinder;
 
     return Status::ok();
 }
 
 Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
-    *_aidl_return = data_->getAttestationCertificate();
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+    *_aidl_return = data->getAttestationCertificate();
     return Status::ok();
 }
 
 // Returns operation handle
-Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) {
+Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
+                                 int64_t* _aidl_return) {
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
 
-    selectedAuthKey_ = data_->selectAuthKey(allowUsingExhaustedKeys);
+    selectedAuthKey_ = data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
     if (selectedAuthKey_ == nullptr) {
         return Status::fromServiceSpecificError(
             ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
@@ -174,16 +190,23 @@
                               const vector<RequestNamespaceParcel>& requestNamespaces,
                               const vector<uint8_t>& sessionTranscript,
                               const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
-                              GetEntriesResultParcel* _aidl_return) {
+                              bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) {
     GetEntriesResultParcel ret;
 
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+
     // Calculate requestCounts ahead of time and be careful not to include
     // elements that don't exist.
     //
     // Also go through and figure out which access control profiles to include
     // in the startRetrieval() call.
     vector<int32_t> requestCounts;
-    const vector<SecureAccessControlProfile>& allProfiles = data_->getSecureAccessControlProfiles();
+    const vector<SecureAccessControlProfile>& allProfiles = data->getSecureAccessControlProfiles();
 
     // We don't support ACP identifiers which isn't in the range 0 to 31. This
     // guarantee exists so it's feasible to implement the TA part of an Identity
@@ -202,13 +225,13 @@
     for (const RequestNamespaceParcel& rns : requestNamespaces) {
         size_t numEntriesInNsToRequest = 0;
         for (const RequestEntryParcel& rep : rns.entries) {
-            if (data_->hasEntryData(rns.namespaceName, rep.name)) {
+            if (data->hasEntryData(rns.namespaceName, rep.name)) {
                 numEntriesInNsToRequest++;
             }
 
-            optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
-            if (data) {
-                for (int32_t id : data.value().accessControlProfileIds) {
+            optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
+            if (eData) {
+                for (int32_t id : eData.value().accessControlProfileIds) {
                     if (id < 0 || id >= 32) {
                         LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
                                    << rns.namespaceName << ": " << rep.name;
@@ -282,7 +305,7 @@
     if (userAuthNeeded) {
         vector<uint8_t> authTokenBytes;
         vector<uint8_t> verificationTokenBytes;
-        if (!getTokensFromKeystore(selectedChallenge_, data_->getSecureUserId(),
+        if (!getTokensFromKeystore(selectedChallenge_, data->getSecureUserId(),
                                    authTokenMaxAgeMillis, authTokenBytes, verificationTokenBytes)) {
             LOG(ERROR) << "Error getting tokens from keystore";
             return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
@@ -331,7 +354,7 @@
     const AuthKeyData* authKey = selectedAuthKey_;
     if (sessionTranscript.size() > 0) {
         if (authKey == nullptr) {
-            authKey = data_->selectAuthKey(allowUsingExhaustedKeys);
+            authKey = data->selectAuthKey(allowUsingExhaustedKeys, allowUsingExpiredKeys);
             if (authKey == nullptr) {
                 return Status::fromServiceSpecificError(
                     ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
@@ -351,7 +374,7 @@
         RequestNamespace ns;
         ns.namespaceName = rns.namespaceName;
         for (const RequestEntryParcel& rep : rns.entries) {
-            optional<EntryData> entryData = data_->getEntryData(rns.namespaceName, rep.name);
+            optional<EntryData> entryData = data->getEntryData(rns.namespaceName, rep.name);
             if (entryData) {
                 RequestDataItem di;
                 di.name = rep.name;
@@ -406,16 +429,16 @@
             ResultEntryParcel resultEntryParcel;
             resultEntryParcel.name = rep.name;
 
-            optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
-            if (!data) {
+            optional<EntryData> eData = data->getEntryData(rns.namespaceName, rep.name);
+            if (!eData) {
                 resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
                 resultNamespaceParcel.entries.push_back(resultEntryParcel);
                 continue;
             }
 
             status =
-                halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, data.value().size,
-                                                    data.value().accessControlProfileIds);
+                halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, eData.value().size,
+                                                    eData.value().accessControlProfileIds);
             if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
                 int code = status.serviceSpecificErrorCode();
                 if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
@@ -441,7 +464,7 @@
             }
 
             vector<uint8_t> value;
-            for (const auto& encryptedChunk : data.value().encryptedChunks) {
+            for (const auto& encryptedChunk : eData.value().encryptedChunks) {
                 vector<uint8_t> chunk;
                 status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
                 if (!status.isOk()) {
@@ -467,7 +490,7 @@
 
     // Ensure useCount is updated on disk.
     if (authKey != nullptr) {
-        if (!data_->saveToDisk()) {
+        if (!data->saveToDisk()) {
             return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                     "Error saving data");
         }
@@ -479,11 +502,19 @@
 
 Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
     vector<uint8_t> proofOfDeletionSignature;
+
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+
     Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
     if (!status.isOk()) {
         return halStatusToGenericError(status);
     }
-    if (!data_->deleteCredential()) {
+    if (!data->deleteCredential()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error deleting credential data on disk");
     }
@@ -491,6 +522,47 @@
     return Status::ok();
 }
 
+Status Credential::deleteWithChallenge(const vector<uint8_t>& challenge,
+                                       vector<uint8_t>* _aidl_return) {
+    if (halApiVersion_ < 3) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
+                                                "Not implemented by HAL");
+    }
+    vector<uint8_t> proofOfDeletionSignature;
+
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+
+    Status status = halBinder_->deleteCredentialWithChallenge(challenge, &proofOfDeletionSignature);
+    if (!status.isOk()) {
+        return halStatusToGenericError(status);
+    }
+    if (!data->deleteCredential()) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error deleting credential data on disk");
+    }
+    *_aidl_return = proofOfDeletionSignature;
+    return Status::ok();
+}
+
+Status Credential::proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) {
+    if (halApiVersion_ < 3) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
+                                                "Not implemented by HAL");
+    }
+    vector<uint8_t> proofOfOwnershipSignature;
+    Status status = halBinder_->proveOwnership(challenge, &proofOfOwnershipSignature);
+    if (!status.isOk()) {
+        return halStatusToGenericError(status);
+    }
+    *_aidl_return = proofOfOwnershipSignature;
+    return Status::ok();
+}
+
 Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
     vector<uint8_t> keyPair;
     Status status = halBinder_->createEphemeralKeyPair(&keyPair);
@@ -522,8 +594,14 @@
 }
 
 Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
-    data_->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
-    if (!data_->saveToDisk()) {
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+    data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+    if (!data->saveToDisk()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error saving data");
     }
@@ -531,8 +609,14 @@
 }
 
 Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
     optional<vector<vector<uint8_t>>> keysNeedingCert =
-        data_->getAuthKeysNeedingCertification(halBinder_);
+        data->getAuthKeysNeedingCertification(halBinder_);
     if (!keysNeedingCert) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error getting auth keys neededing certification");
@@ -543,7 +627,7 @@
         authKeyParcel.x509cert = key;
         authKeyParcels.push_back(authKeyParcel);
     }
-    if (!data_->saveToDisk()) {
+    if (!data->saveToDisk()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error saving data");
     }
@@ -553,13 +637,48 @@
 
 Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
                                                  const vector<uint8_t>& staticAuthData) {
-    if (!data_->storeStaticAuthenticationData(authenticationKey.x509cert, staticAuthData)) {
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+    if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
+                                             std::numeric_limits<int64_t>::max(), staticAuthData)) {
         return Status::fromServiceSpecificError(
             ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
             "Error finding authentication key to store static "
             "authentication data for");
     }
-    if (!data_->saveToDisk()) {
+    if (!data->saveToDisk()) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error saving data");
+    }
+    return Status::ok();
+}
+
+Status
+Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
+                                                        int64_t expirationDateMillisSinceEpoch,
+                                                        const vector<uint8_t>& staticAuthData) {
+    if (halApiVersion_ < 3) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
+                                                "Not implemented by HAL");
+    }
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+    if (!data->storeStaticAuthenticationData(authenticationKey.x509cert,
+                                             expirationDateMillisSinceEpoch, staticAuthData)) {
+        return Status::fromServiceSpecificError(
+            ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
+            "Error finding authentication key to store static "
+            "authentication data for");
+    }
+    if (!data->saveToDisk()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error saving data");
     }
@@ -567,7 +686,13 @@
 }
 
 Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
-    const vector<AuthKeyData>& authKeyDatas = data_->getAuthKeyDatas();
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+    const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
     vector<int32_t> ret;
     for (const AuthKeyData& authKeyData : authKeyDatas) {
         ret.push_back(authKeyData.useCount);
@@ -576,6 +701,80 @@
     return Status::ok();
 }
 
+optional<string> extractDocType(const vector<uint8_t>& credentialData) {
+    auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
+    if (item == nullptr) {
+        LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
+        return {};
+    }
+    const cppbor::Array* array = item->asArray();
+    if (array == nullptr || array->size() < 1) {
+        LOG(ERROR) << "CredentialData array with at least one element";
+        return {};
+    }
+    const cppbor::Tstr* tstr = ((*array)[0])->asTstr();
+    if (tstr == nullptr) {
+        LOG(ERROR) << "First item in CredentialData is not a string";
+        return {};
+    }
+    return tstr->value();
+}
+
+Status Credential::update(sp<IWritableCredential>* _aidl_return) {
+    if (halApiVersion_ < 3) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
+                                                "Not implemented by HAL");
+    }
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+
+    sp<IWritableIdentityCredential> halWritableCredential;
+    Status status = halBinder_->updateCredential(&halWritableCredential);
+    if (!status.isOk()) {
+        return halStatusToGenericError(status);
+    }
+
+    optional<string> docType = extractDocType(data->getCredentialData());
+    if (!docType) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Unable to extract DocType from CredentialData");
+    }
+
+    // NOTE: The caller is expected to call WritableCredential::personalize() which will
+    // write brand new data to disk, specifically it will overwrite any data already
+    // have _including_ authentication keys.
+    //
+    // It is because of this we need to set the CredentialKey certificate chain,
+    // keyCount, and maxUsesPerKey below.
+    sp<WritableCredential> writableCredential =
+        new WritableCredential(dataPath_, credentialName_, docType.value(), true, hwInfo_,
+                               halWritableCredential, halApiVersion_);
+
+    writableCredential->setAttestationCertificate(data->getAttestationCertificate());
+    auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
+    writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+
+    // Because its data has changed, we need to reconnect to the HAL when the
+    // credential has been updated... otherwise the remote object will have
+    // stale data for future calls (e.g. getAuthKeysNeedingCertification().
+    //
+    // The joys and pitfalls of mutable objects...
+    //
+    writableCredential->setCredentialUpdatedCallback([this] {
+        Status status = this->ensureOrReplaceHalBinder();
+        if (!status.isOk()) {
+            LOG(ERROR) << "Error loading credential";
+        }
+    });
+
+    *_aidl_return = writableCredential;
+    return Status::ok();
+}
+
 }  // namespace identity
 }  // namespace security
 }  // namespace android
diff --git a/identity/Credential.h b/identity/Credential.h
index e2880d9..7f08515 100644
--- a/identity/Credential.h
+++ b/identity/Credential.h
@@ -36,6 +36,7 @@
 using ::std::vector;
 
 using ::android::hardware::identity::CipherSuite;
+using ::android::hardware::identity::HardwareInformation;
 using ::android::hardware::identity::IIdentityCredential;
 using ::android::hardware::identity::IIdentityCredentialStore;
 using ::android::hardware::identity::RequestDataItem;
@@ -43,10 +44,12 @@
 
 class Credential : public BnCredential {
   public:
-    Credential(CipherSuite cipherSuite, const string& dataPath, const string& credentialName);
+    Credential(CipherSuite cipherSuite, const string& dataPath, const string& credentialName,
+               uid_t callingUid, HardwareInformation hwInfo,
+               sp<IIdentityCredentialStore> halStoreBinder, int halApiVersion);
     ~Credential();
 
-    Status loadCredential(sp<IIdentityCredentialStore> halStoreBinder);
+    Status ensureOrReplaceHalBinder();
 
     // ICredential overrides
     Status createEphemeralKeyPair(vector<uint8_t>* _aidl_return) override;
@@ -55,33 +58,47 @@
 
     Status deleteCredential(vector<uint8_t>* _aidl_return) override;
 
+    Status deleteWithChallenge(const vector<uint8_t>& challenge,
+                               vector<uint8_t>* _aidl_return) override;
+
+    Status proveOwnership(const vector<uint8_t>& challenge, vector<uint8_t>* _aidl_return) override;
+
     Status getCredentialKeyCertificateChain(vector<uint8_t>* _aidl_return) override;
 
-    Status selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) override;
+    Status selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys,
+                         int64_t* _aidl_return) override;
 
     Status getEntries(const vector<uint8_t>& requestMessage,
                       const vector<RequestNamespaceParcel>& requestNamespaces,
                       const vector<uint8_t>& sessionTranscript,
                       const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
-                      GetEntriesResultParcel* _aidl_return) override;
+                      bool allowUsingExpiredKeys, GetEntriesResultParcel* _aidl_return) override;
 
     Status setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) override;
     Status getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) override;
     Status storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
                                          const vector<uint8_t>& staticAuthData) override;
+    Status
+    storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
+                                                int64_t expirationDateMillisSinceEpoch,
+                                                const vector<uint8_t>& staticAuthData) override;
     Status getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) override;
 
+    Status update(sp<IWritableCredential>* _aidl_return) override;
+
   private:
     CipherSuite cipherSuite_;
     string dataPath_;
     string credentialName_;
+    uid_t callingUid_;
+    HardwareInformation hwInfo_;
+    sp<IIdentityCredentialStore> halStoreBinder_;
 
     const AuthKeyData* selectedAuthKey_ = nullptr;
     uint64_t selectedChallenge_ = 0;
 
-    sp<CredentialData> data_;
-
     sp<IIdentityCredential> halBinder_;
+    int halApiVersion_;
 
     ssize_t
     calcExpectedDeviceNameSpacesSize(const vector<uint8_t>& requestMessage,
diff --git a/identity/CredentialData.cpp b/identity/CredentialData.cpp
index b4e6641..96c436a 100644
--- a/identity/CredentialData.cpp
+++ b/identity/CredentialData.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "CredentialData"
 
+#include <chrono>
+
 #include <fcntl.h>
 #include <stdlib.h>
 #include <sys/stat.h>
@@ -119,12 +121,15 @@
     cppbor::Array authKeyDatasArray;
     for (const AuthKeyData& data : authKeyDatas_) {
         cppbor::Array array;
+        // Fields 0-6 was in the original version in Android 11
         array.add(data.certificate);
         array.add(data.keyBlob);
         array.add(data.staticAuthenticationData);
         array.add(data.pendingCertificate);
         array.add(data.pendingKeyBlob);
         array.add(data.useCount);
+        // Field 7 was added in Android 12
+        array.add(data.expirationDateMillisSinceEpoch);
         authKeyDatasArray.add(std::move(array));
     }
     map.add("authKeyData", std::move(authKeyDatasArray));
@@ -183,9 +188,17 @@
         LOG(ERROR) << "One or more items in AuthKeyData array in CBOR is of wrong type";
         return {};
     }
+    // expirationDateMillisSinceEpoch was added as the 7th element for Android 12. If not
+    // present, default to longest possible expiration date.
+    int64_t expirationDateMillisSinceEpoch = INT64_MAX;
+    if (array->size() >= 7) {
+        const cppbor::Int* itemExpirationDateMillisSinceEpoch = ((*array)[6])->asInt();
+        expirationDateMillisSinceEpoch = itemExpirationDateMillisSinceEpoch->value();
+    }
     AuthKeyData authKeyData;
     authKeyData.certificate = itemCertificate->value();
     authKeyData.keyBlob = itemKeyBlob->value();
+    authKeyData.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
     authKeyData.staticAuthenticationData = itemStaticAuthenticationData->value();
     authKeyData.pendingCertificate = itemPendingCertificate->value();
     authKeyData.pendingKeyBlob = itemPendingKeyBlob->value();
@@ -232,7 +245,6 @@
 }
 
 bool CredentialData::loadFromDisk() {
-
     // Reset all data.
     credentialData_.clear();
     attestationCertificate_.clear();
@@ -487,16 +499,28 @@
     return authKeyDatas_;
 }
 
-const AuthKeyData* CredentialData::selectAuthKey(bool allowUsingExhaustedKeys) {
+pair<int /* keyCount */, int /*maxUsersPerKey */> CredentialData::getAvailableAuthenticationKeys() {
+    return std::make_pair(keyCount_, maxUsesPerKey_);
+}
+
+AuthKeyData* CredentialData::findAuthKey_(bool allowUsingExhaustedKeys,
+                                          bool allowUsingExpiredKeys) {
     AuthKeyData* candidate = nullptr;
 
+    int64_t nowMilliSeconds =
+        std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
+
     int n = 0;
-    int candidateNum = -1;
     for (AuthKeyData& data : authKeyDatas_) {
+        if (nowMilliSeconds > data.expirationDateMillisSinceEpoch) {
+            if (!allowUsingExpiredKeys) {
+                continue;
+            }
+        }
         if (data.certificate.size() != 0) {
+            // Not expired, include in normal check
             if (candidate == nullptr || data.useCount < candidate->useCount) {
                 candidate = &data;
-                candidateNum = n;
             }
         }
         n++;
@@ -510,6 +534,28 @@
         return nullptr;
     }
 
+    return candidate;
+}
+
+const AuthKeyData* CredentialData::selectAuthKey(bool allowUsingExhaustedKeys,
+                                                 bool allowUsingExpiredKeys) {
+    AuthKeyData* candidate;
+
+    // First try to find a un-expired key..
+    candidate = findAuthKey_(allowUsingExhaustedKeys, false);
+    if (candidate == nullptr) {
+        // That didn't work, there are no un-expired keys and we don't allow using expired keys.
+        if (!allowUsingExpiredKeys) {
+            return nullptr;
+        }
+
+        // See if there's an expired key then...
+        candidate = findAuthKey_(allowUsingExhaustedKeys, true);
+        if (candidate == nullptr) {
+            return nullptr;
+        }
+    }
+
     candidate->useCount += 1;
     return candidate;
 }
@@ -519,8 +565,14 @@
 
     vector<vector<uint8_t>> keysNeedingCert;
 
+    int64_t nowMilliSeconds =
+        std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) * 1000;
+
     for (AuthKeyData& data : authKeyDatas_) {
-        bool newKeyNeeded = (data.certificate.size() == 0) || (data.useCount >= maxUsesPerKey_);
+        bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
+        bool keyBeyondExpirationDate = (nowMilliSeconds > data.expirationDateMillisSinceEpoch);
+        bool newKeyNeeded =
+            (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondExpirationDate;
         bool certificationPending = (data.pendingCertificate.size() > 0);
         if (newKeyNeeded && !certificationPending) {
             vector<uint8_t> signingKeyBlob;
@@ -543,11 +595,13 @@
 }
 
 bool CredentialData::storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
+                                                   int64_t expirationDateMillisSinceEpoch,
                                                    const vector<uint8_t>& staticAuthData) {
     for (AuthKeyData& data : authKeyDatas_) {
         if (data.pendingCertificate == authenticationKey) {
             data.certificate = data.pendingCertificate;
             data.keyBlob = data.pendingKeyBlob;
+            data.expirationDateMillisSinceEpoch = expirationDateMillisSinceEpoch;
             data.staticAuthenticationData = staticAuthData;
             data.pendingCertificate.clear();
             data.pendingKeyBlob.clear();
diff --git a/identity/CredentialData.h b/identity/CredentialData.h
index 7995828..b037997 100644
--- a/identity/CredentialData.h
+++ b/identity/CredentialData.h
@@ -55,6 +55,7 @@
 
     vector<uint8_t> certificate;
     vector<uint8_t> keyBlob;
+    int64_t expirationDateMillisSinceEpoch;
     vector<uint8_t> staticAuthenticationData;
     vector<uint8_t> pendingCertificate;
     vector<uint8_t> pendingKeyBlob;
@@ -106,17 +107,22 @@
 
     const vector<AuthKeyData>& getAuthKeyDatas() const;
 
+    pair<int /* keyCount */, int /*maxUsersPerKey */> getAvailableAuthenticationKeys();
+
     // Returns |nullptr| if a suitable key cannot be found. Otherwise returns
     // the authentication and increases its use-count.
-    const AuthKeyData* selectAuthKey(bool allowUsingExhaustedKeys);
+    const AuthKeyData* selectAuthKey(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys);
 
     optional<vector<vector<uint8_t>>>
     getAuthKeysNeedingCertification(const sp<IIdentityCredential>& halBinder);
 
     bool storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
+                                       int64_t expirationDateMillisSinceEpoch,
                                        const vector<uint8_t>& staticAuthData);
 
   private:
+    AuthKeyData* findAuthKey_(bool allowUsingExhaustedKeys, bool allowUsingExpiredKeys);
+
     // Set by constructor.
     //
     string dataPath_;
diff --git a/identity/CredentialStore.cpp b/identity/CredentialStore.cpp
index e3a825b..f77294e 100644
--- a/identity/CredentialStore.cpp
+++ b/identity/CredentialStore.cpp
@@ -41,11 +41,12 @@
         LOG(ERROR) << "Error getting hardware information: " << status.toString8();
         return false;
     }
+    halApiVersion_ = hal_->getInterfaceVersion();
 
-    LOG(INFO) << "Connected to Identity Credential HAL with name '" << hwInfo_.credentialStoreName
-              << "' authored by '" << hwInfo_.credentialStoreAuthorName << "' with chunk size "
-              << hwInfo_.dataChunkSize << " and directoAccess set to "
-              << (hwInfo_.isDirectAccess ? "true" : "false");
+    LOG(INFO) << "Connected to Identity Credential HAL with API version " << halApiVersion_
+              << " and name '" << hwInfo_.credentialStoreName << "' authored by '"
+              << hwInfo_.credentialStoreAuthorName << "' with chunk size " << hwInfo_.dataChunkSize
+              << " and directoAccess set to " << (hwInfo_.isDirectAccess ? "true" : "false");
     return true;
 }
 
@@ -89,7 +90,7 @@
     }
 
     sp<IWritableCredential> writableCredential = new WritableCredential(
-        dataPath_, credentialName, docType, hwInfo_.dataChunkSize, halWritableCredential);
+        dataPath_, credentialName, docType, false, hwInfo_, halWritableCredential, halApiVersion_);
     *_aidl_return = writableCredential;
     return Status::ok();
 }
@@ -112,9 +113,10 @@
 
     // Note: IdentityCredentialStore.java's CipherSuite enumeration and CipherSuite from the
     // HAL is manually kept in sync. So this cast is safe.
-    sp<Credential> credential = new Credential(CipherSuite(cipherSuite), dataPath_, credentialName);
+    sp<Credential> credential = new Credential(CipherSuite(cipherSuite), dataPath_, credentialName,
+                                               callingUid, hwInfo_, hal_, halApiVersion_);
 
-    Status loadStatus = credential->loadCredential(hal_);
+    Status loadStatus = credential->ensureOrReplaceHalBinder();
     if (!loadStatus.isOk()) {
         LOG(ERROR) << "Error loading credential";
     } else {
diff --git a/identity/CredentialStore.h b/identity/CredentialStore.h
index 24b2b4d..15da4eb 100644
--- a/identity/CredentialStore.h
+++ b/identity/CredentialStore.h
@@ -57,6 +57,7 @@
     string dataPath_;
 
     sp<IIdentityCredentialStore> hal_;
+    int halApiVersion_;
 
     HardwareInformation hwInfo_;
 };
diff --git a/identity/WritableCredential.cpp b/identity/WritableCredential.cpp
index a932dcf..d0688b8 100644
--- a/identity/WritableCredential.cpp
+++ b/identity/WritableCredential.cpp
@@ -39,13 +39,19 @@
 using ::android::hardware::identity::support::chunkVector;
 
 WritableCredential::WritableCredential(const string& dataPath, const string& credentialName,
-                                       const string& docType, size_t dataChunkSize,
-                                       sp<IWritableIdentityCredential> halBinder)
-    : dataPath_(dataPath), credentialName_(credentialName), docType_(docType),
-      dataChunkSize_(dataChunkSize), halBinder_(halBinder) {}
+                                       const string& docType, bool isUpdate,
+                                       HardwareInformation hwInfo,
+                                       sp<IWritableIdentityCredential> halBinder, int halApiVersion)
+    : dataPath_(dataPath), credentialName_(credentialName), docType_(docType), isUpdate_(isUpdate),
+      hwInfo_(std::move(hwInfo)), halBinder_(halBinder), halApiVersion_(halApiVersion) {}
 
 WritableCredential::~WritableCredential() {}
 
+void WritableCredential::setCredentialUpdatedCallback(
+    std::function<void()>&& onCredentialUpdatedCallback) {
+    onCredentialUpdatedCallback_ = onCredentialUpdatedCallback;
+}
+
 Status WritableCredential::ensureAttestationCertificateExists(const vector<uint8_t>& challenge) {
     if (!attestationCertificate_.empty()) {
         return Status::ok();
@@ -79,7 +85,10 @@
 
 Status WritableCredential::getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
                                                             vector<uint8_t>* _aidl_return) {
-
+    if (isUpdate_) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Cannot be called for an update");
+    }
     Status ensureStatus = ensureAttestationCertificateExists(challenge);
     if (!ensureStatus.isOk()) {
         return ensureStatus;
@@ -89,6 +98,15 @@
     return Status::ok();
 }
 
+void WritableCredential::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
+    attestationCertificate_ = attestationCertificate;
+}
+
+void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+    keyCount_ = keyCount;
+    maxUsesPerKey_ = maxUsesPerKey;
+}
+
 ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
     const vector<AccessControlProfileParcel>& accessControlProfiles,
     const vector<EntryNamespaceParcel>& entryNamespaces) {
@@ -149,9 +167,12 @@
 WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
                                 const vector<EntryNamespaceParcel>& entryNamespaces,
                                 int64_t secureUserId, vector<uint8_t>* _aidl_return) {
-    Status ensureStatus = ensureAttestationCertificateExists({0x00});  // Challenge cannot be empty.
-    if (!ensureStatus.isOk()) {
-        return ensureStatus;
+    if (!isUpdate_) {
+        Status ensureStatus =
+            ensureAttestationCertificateExists({0x00});  // Challenge cannot be empty.
+        if (!ensureStatus.isOk()) {
+            return ensureStatus;
+        }
     }
 
     uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
@@ -203,7 +224,7 @@
 
     for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
         for (const EntryParcel& eParcel : ensParcel.entries) {
-            vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, dataChunkSize_);
+            vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, hwInfo_.dataChunkSize);
 
             vector<int32_t> ids;
             std::copy(eParcel.accessControlProfileIds.begin(),
@@ -240,11 +261,15 @@
     }
     data.setCredentialData(credentialData);
 
+    data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_);
+
     if (!data.saveToDisk()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error saving credential data to disk");
     }
 
+    onCredentialUpdatedCallback_();
+
     *_aidl_return = proofOfProvisioningSignature;
     return Status::ok();
 }
diff --git a/identity/WritableCredential.h b/identity/WritableCredential.h
index eb63aca..6ff31ae 100644
--- a/identity/WritableCredential.h
+++ b/identity/WritableCredential.h
@@ -29,6 +29,7 @@
 namespace identity {
 
 using ::android::binder::Status;
+using ::android::hardware::identity::HardwareInformation;
 using ::android::hardware::identity::IWritableIdentityCredential;
 using ::std::string;
 using ::std::vector;
@@ -36,9 +37,15 @@
 class WritableCredential : public BnWritableCredential {
   public:
     WritableCredential(const string& dataPath, const string& credentialName, const string& docType,
-                       size_t dataChunkSize, sp<IWritableIdentityCredential> halBinder);
+                       bool isUpdate, HardwareInformation hwInfo,
+                       sp<IWritableIdentityCredential> halBinder, int halApiVersion);
     ~WritableCredential();
 
+    // Used when updating a credential
+    void setAttestationCertificate(const vector<uint8_t>& attestationCertificate);
+    void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+    void setCredentialUpdatedCallback(std::function<void()>&& onCredentialUpdatedCallback);
+
     // IWritableCredential overrides
     Status getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
                                             vector<uint8_t>* _aidl_return) override;
@@ -51,9 +58,16 @@
     string dataPath_;
     string credentialName_;
     string docType_;
-    size_t dataChunkSize_;
+    bool isUpdate_;
+    HardwareInformation hwInfo_;
     sp<IWritableIdentityCredential> halBinder_;
+    int halApiVersion_;
+
     vector<uint8_t> attestationCertificate_;
+    int keyCount_ = 0;
+    int maxUsesPerKey_ = 1;
+
+    std::function<void()> onCredentialUpdatedCallback_ = []() {};
 
     ssize_t calcExpectedProofOfProvisioningSize(
         const vector<AccessControlProfileParcel>& accessControlProfiles,
diff --git a/identity/binder/android/security/identity/ICredential.aidl b/identity/binder/android/security/identity/ICredential.aidl
index 7bd0df7..2165810 100644
--- a/identity/binder/android/security/identity/ICredential.aidl
+++ b/identity/binder/android/security/identity/ICredential.aidl
@@ -16,6 +16,8 @@
 
 package android.security.identity;
 
+import android.security.identity.IWritableCredential;
+
 import android.security.identity.RequestNamespaceParcel;
 import android.security.identity.GetEntriesResultParcel;
 import android.security.identity.AuthKeyParcel;
@@ -40,23 +42,35 @@
     void setReaderEphemeralPublicKey(in byte[] publicKey);
 
     byte[] deleteCredential();
+    byte[] deleteWithChallenge(in byte[] challenge);
+
+    byte[] proveOwnership(in byte[] challenge);
 
     byte[] getCredentialKeyCertificateChain();
 
-    long selectAuthKey(in boolean allowUsingExhaustedKeys);
+    long selectAuthKey(in boolean allowUsingExhaustedKeys,
+                       in boolean allowUsingExpiredKeys);
 
     GetEntriesResultParcel getEntries(in byte[] requestMessage,
                                       in RequestNamespaceParcel[] requestNamespaces,
                                       in byte[] sessionTranscript,
                                       in byte[] readerSignature,
-                                      in boolean allowUsingExhaustedKeys);
+                                      in boolean allowUsingExhaustedKeys,
+                                      in boolean allowUsingExpiredKeys);
 
     void setAvailableAuthenticationKeys(in int keyCount, in int maxUsesPerKey);
 
     AuthKeyParcel[] getAuthKeysNeedingCertification();
 
-    void storeStaticAuthenticationData(in AuthKeyParcel authenticationKey, in byte[] staticAuthData);
+    void storeStaticAuthenticationData(in AuthKeyParcel authenticationKey,
+                                       in byte[] staticAuthData);
+
+    void storeStaticAuthenticationDataWithExpiration(in AuthKeyParcel authenticationKey,
+                                       in long expirationDateMillisSinceEpoch,
+                                       in byte[] staticAuthData);
 
     int[] getAuthenticationDataUsageCount();
+
+    IWritableCredential update();
 }
 
diff --git a/identity/binder/android/security/identity/ICredentialStore.aidl b/identity/binder/android/security/identity/ICredentialStore.aidl
index 1039831..8357f47 100644
--- a/identity/binder/android/security/identity/ICredentialStore.aidl
+++ b/identity/binder/android/security/identity/ICredentialStore.aidl
@@ -39,6 +39,7 @@
     const int ERROR_AUTHENTICATION_KEY_NOT_FOUND = 9;
     const int ERROR_INVALID_ITEMS_REQUEST_MESSAGE = 10;
     const int ERROR_SESSION_TRANSCRIPT_MISMATCH = 11;
+    const int ERROR_NOT_SUPPORTED = 12;
 
     SecurityHardwareInfoParcel getSecurityHardwareInfo();