Merge "Require security version from the android.16 profile" into main am: be22437692

Original change: https://android-review.googlesource.com/c/platform/tools/security/+/2765488

Change-Id: Ie77b5445a179cfd2496d2a0b57f6fd7090f09bf4
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/remote_provisioning/hwtrust/src/cbor/dice/entry.rs b/remote_provisioning/hwtrust/src/cbor/dice/entry.rs
index 9d01f7c..fc4c374 100644
--- a/remote_provisioning/hwtrust/src/cbor/dice/entry.rs
+++ b/remote_provisioning/hwtrust/src/cbor/dice/entry.rs
@@ -339,13 +339,20 @@
     let extensions =
         extensions.into_iter().map(|(k, v)| (k.to_string(), format!("{v:?}"))).collect();
 
+    let security_version = if profile.security_version_optional {
+        security_version.into_optional_u64()
+    } else {
+        security_version.into_u64().map(Some)
+    }
+    .context("Security version")?;
+
     Ok(ConfigDescBuilder::new()
         .component_name(component_name.into_optional_string().context("Component name")?)
         .component_version(
             validate_version(profile, component_version).context("Component version")?,
         )
         .resettable(resettable.is_null().context("Resettable")?)
-        .security_version(security_version.into_optional_u64().context("Security version")?)
+        .security_version(security_version)
         .extensions(extensions)
         .build())
 }
@@ -727,7 +734,9 @@
     #[test]
     fn config_desc_component_version_string() {
         let mut fields = valid_payload_fields();
-        let config_desc = serialize(cbor!({COMPONENT_VERSION => "It's version 4"}).unwrap());
+        let config_desc = serialize(
+            cbor!({COMPONENT_VERSION => "It's version 4", SECURITY_VERSION => 99999999}).unwrap(),
+        );
         let config_hash = sha512(&config_desc).to_vec();
         fields.insert(CONFIG_DESC, Value::Bytes(config_desc));
         fields.insert(CONFIG_HASH, Value::Bytes(config_hash));
@@ -746,7 +755,7 @@
     #[test]
     fn config_desc_security_version() {
         let mut fields = valid_payload_fields();
-        let config_desc = serialize(cbor!({SECURITY_VERSION => Value::from(0x12345678)}).unwrap());
+        let config_desc = serialize(cbor!({SECURITY_VERSION => 0x12345678}).unwrap());
         let config_hash = sha512(&config_desc).to_vec();
         fields.insert(CONFIG_DESC, Value::Bytes(config_desc));
         fields.insert(CONFIG_HASH, Value::Bytes(config_hash));
@@ -757,6 +766,21 @@
     }
 
     #[test]
+    fn config_desc_security_version_omitted() {
+        let mut fields = valid_payload_fields();
+        let config_desc = serialize(cbor!({}).unwrap());
+        let config_hash = sha512(&config_desc).to_vec();
+        fields.insert(CONFIG_DESC, Value::Bytes(config_desc));
+        fields.insert(CONFIG_HASH, Value::Bytes(config_hash));
+        let entries = encode_fields(fields);
+        Payload::from_entries(&Profile::default(), entries.clone(), ConfigFormat::Android)
+            .unwrap_err();
+        let profile = Profile { security_version_optional: true, ..Profile::default() };
+        let payload = Payload::from_entries(&profile, entries, ConfigFormat::Android).unwrap();
+        assert_eq!(payload.config_desc().security_version(), None);
+    }
+
+    #[test]
     fn config_desc_security_version_fixed_size_encoding() {
         let mut fields = valid_payload_fields();
         let config_desc = vec![
@@ -921,7 +945,9 @@
     fn valid_payload_fields() -> HashMap<i64, Value> {
         let key = PrivateKey::from_pem(ED25519_KEY_PEM[0]).public_key();
         let subject_public_key = key.to_cose_key().unwrap().to_vec().unwrap();
-        let config_desc = serialize(cbor!({COMPONENT_NAME => "component name"}).unwrap());
+        let config_desc = serialize(
+            cbor!({COMPONENT_NAME => "component name", SECURITY_VERSION => 1234}).unwrap(),
+        );
         let config_hash = sha512(&config_desc).to_vec();
         HashMap::from([
             (ISS, Value::from("issuer")),
diff --git a/remote_provisioning/hwtrust/src/cbor/dice/profile.rs b/remote_provisioning/hwtrust/src/cbor/dice/profile.rs
index 308cd72..de28d3f 100644
--- a/remote_provisioning/hwtrust/src/cbor/dice/profile.rs
+++ b/remote_provisioning/hwtrust/src/cbor/dice/profile.rs
@@ -31,6 +31,9 @@
     /// descriptor. This allows for compatibility with early versions of the RKP HAL which did not
     /// enforce the requirements on the configuration hash as defined by the Open Profile for DICE.
     pub(super) config_hash_unverified: bool,
+
+    /// Whether the security version is a required field in the configuration descriptor.
+    pub(super) security_version_optional: bool,
 }
 
 /// Type allowed for the DICE certificate mode field.
@@ -63,6 +66,7 @@
             // Context: b/273552826
             component_version_type: ComponentVersionType::Int,
             config_hash_unverified: true,
+            security_version_optional: true,
             ..Self::default()
         }
     }
@@ -74,13 +78,14 @@
             mode_type: ModeType::IntOrBytes,
             allow_big_endian_key_usage: true,
             config_hash_unverified: true,
+            security_version_optional: true,
             ..Self::default()
         }
     }
 
     /// The rules for the "android.15" profile.
     pub(super) fn android15() -> Self {
-        Self { config_hash_unverified: true, ..Self::default() }
+        Self { config_hash_unverified: true, security_version_optional: true, ..Self::default() }
     }
 
     /// The rules for the "android.16" profile..
diff --git a/remote_provisioning/hwtrust/src/cbor/field_value.rs b/remote_provisioning/hwtrust/src/cbor/field_value.rs
index ecb2ba5..fb25f86 100644
--- a/remote_provisioning/hwtrust/src/cbor/field_value.rs
+++ b/remote_provisioning/hwtrust/src/cbor/field_value.rs
@@ -214,6 +214,10 @@
             .transpose()
     }
 
+    pub fn into_u64(self) -> Result<u64, FieldValueError> {
+        require_present(self.name, self.into_optional_u64())
+    }
+
     pub fn into_optional_u64(self) -> Result<Option<u64>, FieldValueError> {
         self.value
             .map(|v| {