Return OUT_OF_KEYS if system is rkp only

This change leverages the ro.remote_provisioning.rkp_only system
property in order to determine whether or not the system has fallback
keys. If there are no fallback keys, then ks2 will now return
OUT_OF_KEYS as a ResponseCode to the caller over the binder interface.

This will allow the caller to call generateKey() on the
RemoteProvisioner AIDL interface, blocking until the call is returned.
At this point, keys will either have been provisioned, or an actionable
error can be routed back to the developer.

Bug: 227306369
Test: atest RemoteProvisionerUnitTests
Change-Id: I8f5bc5add4ab895ab95c9e4e70e6fc9fa4422da5
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index be23ae5..afbf475 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -60,6 +60,7 @@
     security_level: SecurityLevel,
     km_uuid: Uuid,
     is_hal_present: AtomicBool,
+    is_rkp_only: bool,
 }
 
 static COSE_KEY_XCOORD: Value = Value::Integer(-2);
@@ -70,7 +71,12 @@
 impl RemProvState {
     /// Creates a RemProvState struct.
     pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
-        Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
+        Self {
+            security_level,
+            km_uuid,
+            is_hal_present: AtomicBool::new(true),
+            is_rkp_only: Self::read_is_rkp_only_property(security_level),
+        }
     }
 
     /// Returns the uuid for the KM instance attached to this RemProvState struct.
@@ -78,6 +84,19 @@
         self.km_uuid
     }
 
+    fn read_is_rkp_only_property(security_level: SecurityLevel) -> bool {
+        let default_value = false;
+
+        let property_name = match security_level {
+            SecurityLevel::STRONGBOX => "ro.remote_provisioning.strongbox.rkp_only",
+            SecurityLevel::TRUSTED_ENVIRONMENT => "ro.remote_provisioning.tee.rkp_only",
+            _ => return default_value,
+        };
+
+        rustutils::system_properties::read_bool(property_name, default_value)
+            .unwrap_or(default_value)
+    }
+
     /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
     /// remote provisioning can flip from being disabled to enabled depending on responses from the
     /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
@@ -137,12 +156,12 @@
             match get_rem_prov_attest_key(key.domain, caller_uid, db, &self.km_uuid) {
                 Err(e) => {
                     log::error!(
-                        concat!(
-                            "In get_remote_provisioning_key_and_certs: Failed to get ",
-                            "attestation key. {:?}"
-                        ),
+                        "In get_remote_provisioning_key_and_certs: Error occurred: {:?}",
                         e
                     );
+                    if self.is_rkp_only {
+                        return Err(e);
+                    }
                     log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID);
                     Ok(None)
                 }