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/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();