Fix unique ID attestation.

Test: CTS test will be added.
Bug: 34671471
Change-Id: I2f36b85ba7a46e7aabe83b8e0c58a8092ee1f643
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index cd81674..434dddd 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -42,13 +42,50 @@
 namespace keystore {
 using namespace android;
 
-const size_t MAX_OPERATIONS = 15;
+namespace {
+
+constexpr size_t kMaxOperations = 15;
+constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
+const char* kTimestampFilePath = "timestamp";
 
 struct BIGNUM_Delete {
     void operator()(BIGNUM* p) const { BN_free(p); }
 };
 typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
 
+bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
+    return params.end() != std::find_if(params.begin(), params.end(),
+                                        [&](auto& param) { return param.tag == tag; });
+}
+
+std::pair<KeyStoreServiceReturnCode, bool> hadFactoryResetSinceIdRotation() {
+    struct stat sbuf;
+    if (stat(kTimestampFilePath, &sbuf) == 0) {
+        double diff_secs = difftime(time(NULL), sbuf.st_ctime);
+        return {ResponseCode::NO_ERROR, diff_secs < kIdRotationPeriod};
+    }
+
+    if (errno != ENOENT) {
+        ALOGE("Failed to stat \"timestamp\" file, with error %d", errno);
+        return {ResponseCode::SYSTEM_ERROR, false /* don't care */};
+    }
+
+    int fd = creat(kTimestampFilePath, 0600);
+    if (fd < 0) {
+        ALOGE("Couldn't create \"timestamp\" file, with error %d", errno);
+        return {ResponseCode::SYSTEM_ERROR, false /* don't care */};
+    }
+
+    if (close(fd)) {
+        ALOGE("Couldn't close \"timestamp\" file, with error %d", errno);
+        return {ResponseCode::SYSTEM_ERROR, false /* don't care */};
+    }
+
+    return {ResponseCode::NO_ERROR, true};
+}
+
+}  // anonymous namespace
+
 void KeyStoreService::binderDied(const wp<IBinder>& who) {
     auto operations = mOperationMap.getOperationsForToken(who.unsafe_get());
     for (const auto& token : operations) {
@@ -617,6 +654,10 @@
         return rc;
     }
 
+    if (containsTag(params, Tag::INCLUDE_UNIQUE_ID)) {
+        if (!checkBinderPermission(P_GEN_UNIQUE_ID)) return ResponseCode::PERMISSION_DENIED;
+    }
+
     bool usingFallback = false;
     auto& dev = mKeyStore->getDevice();
     AuthorizationSet keyCharacteristics = params;
@@ -1004,9 +1045,9 @@
         return;
     }
 
-    // If there are more than MAX_OPERATIONS, abort the oldest operation that was started as
+    // If there are more than kMaxOperations, abort the oldest operation that was started as
     // pruneable.
-    while (mOperationMap.getOperationCount() >= MAX_OPERATIONS) {
+    while (mOperationMap.getOperationCount() >= kMaxOperations) {
         ALOGD("Reached or exceeded concurrent operations limit");
         if (!pruneOperation()) {
             break;
@@ -1244,17 +1285,17 @@
 bool isDeviceIdAttestationRequested(const hidl_vec<KeyParameter>& params) {
     for (size_t i = 0; i < params.size(); ++i) {
         switch (params[i].tag) {
-            case Tag::ATTESTATION_ID_BRAND:
-            case Tag::ATTESTATION_ID_DEVICE:
-            case Tag::ATTESTATION_ID_PRODUCT:
-            case Tag::ATTESTATION_ID_SERIAL:
-            case Tag::ATTESTATION_ID_IMEI:
-            case Tag::ATTESTATION_ID_MEID:
-            case Tag::ATTESTATION_ID_MANUFACTURER:
-            case Tag::ATTESTATION_ID_MODEL:
-                return true;
-            default:
-                break;
+        case Tag::ATTESTATION_ID_BRAND:
+        case Tag::ATTESTATION_ID_DEVICE:
+        case Tag::ATTESTATION_ID_IMEI:
+        case Tag::ATTESTATION_ID_MANUFACTURER:
+        case Tag::ATTESTATION_ID_MEID:
+        case Tag::ATTESTATION_ID_MODEL:
+        case Tag::ATTESTATION_ID_PRODUCT:
+        case Tag::ATTESTATION_ID_SERIAL:
+            return true;
+        default:
+            break;
         }
     }
     return false;
@@ -1282,14 +1323,22 @@
         if (!interface_cast<IPermissionController>(binder)->checkPermission(
                 String16("android.permission.READ_PRIVILEGED_PHONE_STATE"),
                 IPCThreadState::self()->getCallingPid(), callingUid)) {
-                    return ErrorCode::CANNOT_ATTEST_IDS;
+            return ErrorCode::CANNOT_ATTEST_IDS;
         }
     }
 
+    AuthorizationSet mutableParams = params;
+
+    KeyStoreServiceReturnCode responseCode;
+    bool factoryResetSinceIdRotation;
+    std::tie(responseCode, factoryResetSinceIdRotation) = hadFactoryResetSinceIdRotation();
+
+    if (!responseCode.isOk()) return responseCode;
+    if (factoryResetSinceIdRotation) mutableParams.push_back(TAG_RESET_SINCE_ID_ROTATION);
+
     Blob keyBlob;
     String8 name8(name);
-    KeyStoreServiceReturnCode responseCode =
-        mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
+    responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
     if (!responseCode.isOk()) {
         return responseCode;
     }
@@ -1305,10 +1354,9 @@
      * The attestation application ID cannot be longer than
      * KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE, so we truncate if too long.
      */
-    if (asn1_attestation_id.size() > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE)
+    if (asn1_attestation_id.size() > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
         asn1_attestation_id.resize(KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
-
-    AuthorizationSet mutableParams = params;
+    }
 
     mutableParams.push_back(TAG_ATTESTATION_APPLICATION_ID, blob2hidlVec(asn1_attestation_id));
 
@@ -1465,9 +1513,9 @@
 bool KeyStoreService::checkAllowedOperationParams(const hidl_vec<KeyParameter>& params) {
     for (size_t i = 0; i < params.size(); ++i) {
         switch (params[i].tag) {
-        case Tag::AUTH_TOKEN:
-        // fall through intended
         case Tag::ATTESTATION_APPLICATION_ID:
+        case Tag::AUTH_TOKEN:
+        case Tag::RESET_SINCE_ID_ROTATION:
             return false;
         default:
             break;
@@ -1745,4 +1793,4 @@
     return error;
 }
 
-}  // namespace android
+}  // namespace keystore
diff --git a/keystore/permissions.cpp b/keystore/permissions.cpp
index 92daa1d..1ba91d9 100644
--- a/keystore/permissions.cpp
+++ b/keystore/permissions.cpp
@@ -28,9 +28,25 @@
 
 /* perm_labels associcated with keystore_key SELinux class verbs. */
 const char* perm_labels[] = {
-    "get_state", "get",      "insert",    "delete",    "exist",    "list",
-    "reset",     "password", "lock",      "unlock",    "is_empty", "sign",
-    "verify",    "grant",    "duplicate", "clear_uid", "add_auth", "user_changed",
+    "get_state",
+    "get",
+    "insert",
+    "delete",
+    "exist",
+    "list",
+    "reset",
+    "password",
+    "lock",
+    "unlock",
+    "is_empty",
+    "sign",
+    "verify",
+    "grant",
+    "duplicate",
+    "clear_uid",
+    "add_auth",
+    "user_changed",
+    "gen_unique_id",
 };
 
 struct user_euid {
@@ -55,8 +71,9 @@
     {AID_ROOT, static_cast<perm_t>(P_GET)},
 };
 
-static const perm_t DEFAULT_PERMS = static_cast<perm_t>(P_GET_STATE | P_GET | P_INSERT | P_DELETE |
-                                                        P_EXIST | P_LIST | P_SIGN | P_VERIFY);
+static const perm_t DEFAULT_PERMS = static_cast<perm_t>(
+    P_GET_STATE | P_GET | P_INSERT | P_DELETE | P_EXIST | P_LIST | P_SIGN | P_VERIFY |
+    P_GEN_UNIQUE_ID /* Only privileged apps can do this, but enforcement is done by SELinux */);
 
 struct audit_data {
     pid_t pid;
diff --git a/keystore/permissions.h b/keystore/permissions.h
index f5f1831..80d0e04 100644
--- a/keystore/permissions.h
+++ b/keystore/permissions.h
@@ -39,6 +39,7 @@
     P_CLEAR_UID = 1 << 15,
     P_ADD_AUTH = 1 << 16,
     P_USER_CHANGED = 1 << 17,
+    P_GEN_UNIQUE_ID = 1 << 18,
 };
 
 const char* get_perm_label(perm_t perm);