Introduce KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION

This flag is used by system server to mark keys used during the
synthetic password auth flow. keys marked with this flag will not
be super encrypted because super encryption requires knowledge of
the synthetic password, causing a chicken-and-egg problem.

Bug: 35849499
Bug: 34600579
Test: cts-tradefed run cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.MixedProfileOwnerTest#testResetPasswordWithToken
Change-Id: Ibd900e3ede1f51c476d462085caaf216d911d693
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index 8c8267b..237d896 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -75,6 +75,10 @@
     return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
 }
 
+bool Blob::isCriticalToDeviceEncryption() const {
+    return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+}
+
 inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
     return set ? (flags | flag) : (flags & ~flag);
 }
@@ -83,11 +87,12 @@
     mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
 }
 
-void Blob::setSuperEncrypted(__attribute__((unused)) bool superEncrypted) {
-    // Do not enable super encryption yet, as it's clashing with synthetic password flow
-    // TODO: re-enables this once keystore knows about synthetic password keys
+void Blob::setSuperEncrypted(bool superEncrypted) {
+    mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
+}
 
-    //mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
+void Blob::setCriticalToDeviceEncryption(bool critical) {
+    mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
 }
 
 void Blob::setFallback(bool fallback) {
diff --git a/keystore/blob.h b/keystore/blob.h
index f710641..06f9ea5 100644
--- a/keystore/blob.h
+++ b/keystore/blob.h
@@ -98,6 +98,9 @@
     bool isSuperEncrypted() const;
     void setSuperEncrypted(bool superEncrypted);
 
+    bool isCriticalToDeviceEncryption() const;
+    void setCriticalToDeviceEncryption(bool critical);
+
     bool isFallback() const { return mBlob.flags & KEYSTORE_FLAG_FALLBACK; }
     void setFallback(bool fallback);
 
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index 6d67edb..7260363 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -57,6 +57,11 @@
     // cleared, rather than deleting blobs, and the error returned when attempting to use a
     // super-encrypted blob while keystore is locked is different.
     KEYSTORE_FLAG_SUPER_ENCRYPTED = 1 << 2,
+    // KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION is for blobs that are part of device encryption
+    // flow so it receives special treatment from keystore. For example this blob will not be super
+    // encrypted, and it will be stored separately under an unique UID instead. This flag should
+    // only be available to system uid.
+    KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3,
 };
 
 /**
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index a28a35a..d5923b5 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -658,6 +658,10 @@
     if (!rc.isOk()) {
         return rc;
     }
+    if ((flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION) && get_app_id(uid) != AID_SYSTEM) {
+        ALOGE("Non-system uid %d cannot set FLAG_CRITICAL_TO_DEVICE_ENCRYPTION", uid);
+        return ResponseCode::PERMISSION_DENIED;
+    }
 
     if (containsTag(params, Tag::INCLUDE_UNIQUE_ID)) {
         if (!checkBinderPermission(P_GEN_UNIQUE_ID)) return ResponseCode::PERMISSION_DENIED;
@@ -688,7 +692,8 @@
 
         Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
         keyBlob.setFallback(usingFallback);
-        if (isAuthenticationBound(params)) {
+        keyBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+        if (isAuthenticationBound(params) && !keyBlob.isCriticalToDeviceEncryption()) {
             keyBlob.setSuperEncrypted(true);
         }
         keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
@@ -813,6 +818,10 @@
     if (!rc.isOk()) {
         return rc;
     }
+    if ((flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION) && get_app_id(uid) != AID_SYSTEM) {
+        ALOGE("Non-system uid %d cannot set FLAG_CRITICAL_TO_DEVICE_ENCRYPTION", uid);
+        return ResponseCode::PERMISSION_DENIED;
+    }
 
     bool usingFallback = false;
     auto& dev = mKeyStore->getDevice();
@@ -835,7 +844,8 @@
 
         Blob ksBlob(&keyBlob[0], keyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
         ksBlob.setFallback(usingFallback);
-        if (isAuthenticationBound(params)) {
+        ksBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+        if (isAuthenticationBound(params) && !ksBlob.isCriticalToDeviceEncryption()) {
             ksBlob.setSuperEncrypted(true);
         }
         ksBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
@@ -1787,6 +1797,8 @@
                      0 /* infoLength */, ::TYPE_KEYMASTER_10);
         newBlob.setFallback(blob->isFallback());
         newBlob.setEncrypted(blob->isEncrypted());
+        newBlob.setSuperEncrypted(blob->isSuperEncrypted());
+        newBlob.setCriticalToDeviceEncryption(blob->isCriticalToDeviceEncryption());
 
         error = mKeyStore->put(filename.string(), &newBlob, get_user_id(uid));
         if (!error.isOk()) {