1 use crate::cbor::field_value::FieldValue; 2 use crate::rkp::{ 3 DeviceInfo, DeviceInfoBootloaderState, DeviceInfoSecurityLevel, DeviceInfoVbState, 4 DeviceInfoVersion, 5 }; 6 use anyhow::{bail, ensure, Result}; 7 use chrono::NaiveDate; 8 use ciborium::value::Value; 9 10 impl DeviceInfo { 11 /// Create a new DeviceInfo struct from Values parsed by ciborium from_cbor_values( values: Vec<(Value, Value)>, device_info_version: Option<DeviceInfoVersion>, is_factory: bool, ) -> Result<Self>12 pub fn from_cbor_values( 13 values: Vec<(Value, Value)>, 14 device_info_version: Option<DeviceInfoVersion>, 15 is_factory: bool, 16 ) -> Result<Self> { 17 let mut brand = FieldValue::new("brand"); 18 let mut manufacturer = FieldValue::new("manufacturer"); 19 let mut product = FieldValue::new("product"); 20 let mut model = FieldValue::new("model"); 21 let mut device = FieldValue::new("device"); 22 let mut vb_state = FieldValue::new("vb_state"); 23 let mut bootloader_state = FieldValue::new("bootloader_state"); 24 let mut vbmeta_digest = FieldValue::new("vbmeta_digest"); 25 let mut os_version = FieldValue::new("os_version"); 26 let mut system_patch_level = FieldValue::new("system_patch_level"); 27 let mut boot_patch_level = FieldValue::new("boot_patch_level"); 28 let mut vendor_patch_level = FieldValue::new("vendor_patch_level"); 29 let mut security_level = FieldValue::new("security_level"); 30 let mut version = FieldValue::new("version"); 31 let mut fused = FieldValue::new("fused"); 32 33 for (key, value) in values { 34 let field_value = match key.as_text() { 35 Some("brand") => &mut brand, 36 Some("manufacturer") => &mut manufacturer, 37 Some("product") => &mut product, 38 Some("model") => &mut model, 39 Some("device") => &mut device, 40 Some("vb_state") => &mut vb_state, 41 Some("bootloader_state") => &mut bootloader_state, 42 Some("vbmeta_digest") => &mut vbmeta_digest, 43 Some("os_version") => &mut os_version, 44 Some("system_patch_level") => &mut system_patch_level, 45 Some("boot_patch_level") => &mut boot_patch_level, 46 Some("vendor_patch_level") => &mut vendor_patch_level, 47 Some("security_level") => &mut security_level, 48 Some("fused") => &mut fused, 49 Some("version") => &mut version, 50 _ => bail!("Unexpected DeviceInfo kv-pair: ({key:?},{value:?})"), 51 }; 52 field_value.set_once(value)?; 53 } 54 55 let parsed_version = match version.into_optional_u32() { 56 Ok(v) => v, 57 Err(e) => return Err(e.into()), 58 }; 59 60 let version = match device_info_version { 61 Some(DeviceInfoVersion::V3) => { 62 ensure!(parsed_version.is_none(), "DeviceInfoV3 should not have version entry."); 63 DeviceInfoVersion::V3 64 } 65 None => match parsed_version { 66 Some(2) => DeviceInfoVersion::V2, 67 Some(v) => bail!("Unexpected DeviceInfo version: {}", v), 68 None => bail!("DeviceInfo requires a version entry."), 69 }, 70 _ => bail!("Unexpected DeviceInfo version: {:?}", device_info_version.unwrap()), 71 }; 72 73 let info = DeviceInfo { 74 brand: brand.into_string()?, 75 manufacturer: manufacturer.into_string()?, 76 product: product.into_string()?, 77 model: model.into_string()?, 78 device: device.into_string()?, 79 vb_state: vb_state.into_string()?.as_str().try_into()?, 80 bootloader_state: bootloader_state.into_string()?.as_str().try_into()?, 81 vbmeta_digest: vbmeta_digest.into_bytes()?, 82 os_version: os_version.into_optional_string()?, 83 system_patch_level: system_patch_level.into_u32()?, 84 boot_patch_level: boot_patch_level.into_u32()?, 85 vendor_patch_level: vendor_patch_level.into_u32()?, 86 security_level: security_level.into_string()?.as_str().try_into()?, 87 fused: fused.into_u32()?, 88 version, 89 }; 90 info.validate(is_factory)?; 91 Ok(info) 92 } 93 validate(&self, is_factory: bool) -> Result<()>94 fn validate(&self, is_factory: bool) -> Result<()> { 95 if DeviceInfoSecurityLevel::Avf == self.security_level { 96 ensure!( 97 self.bootloader_state == DeviceInfoBootloaderState::Avf 98 && self.vb_state == DeviceInfoVbState::Avf 99 && self.brand == "aosp-avf" 100 && self.device == "avf" 101 && self.model == "avf" 102 && self.manufacturer == "aosp-avf" 103 && self.product == "avf", 104 "AVF security level requires AVF fields. Got: {:?}", 105 self 106 ); 107 return Ok(()); 108 } else { 109 ensure!( 110 self.bootloader_state != DeviceInfoBootloaderState::Avf 111 && self.vb_state != DeviceInfoVbState::Avf 112 && self.brand != "aosp-avf" 113 && self.device != "avf" 114 && self.model != "avf" 115 && self.manufacturer != "aosp-avf" 116 && self.product != "avf", 117 "Non-AVF security level requires non-AVF fields. Got: {:?}", 118 self 119 ); 120 } 121 122 ensure!(!self.manufacturer.is_empty(), "manufacturer must not be empty"); 123 124 if !is_factory { 125 self.check_entries()?; 126 } 127 128 Ok(()) 129 } 130 check_patch_level(key: &str, level: String) -> Result<()>131 fn check_patch_level(key: &str, level: String) -> Result<()> { 132 let mut maybe_modified_level = level.clone(); 133 if level.len() == 6 { 134 maybe_modified_level += "01"; 135 } 136 137 let string = maybe_modified_level.as_str(); 138 match string.len() { 139 8 => match NaiveDate::parse_from_str(string, "%Y%m%d") { 140 Ok(_) => Ok(()), 141 Err(e) => bail!("Error parsing {key}:{level}: {}", e.to_string()), 142 }, 143 _ => bail!("value for {key} must be in format YYYYMMDD or YYYYMM, found: '{level}'"), 144 } 145 } 146 check_entries(&self) -> Result<()>147 fn check_entries(&self) -> Result<()> { 148 if self.version == DeviceInfoVersion::V3 { 149 Self::check_patch_level("system_patch_level", self.system_patch_level.to_string())?; 150 Self::check_patch_level("boot_patch_level", self.boot_patch_level.to_string())?; 151 Self::check_patch_level("vendor_patch_level", self.vendor_patch_level.to_string())?; 152 } 153 if self.version == DeviceInfoVersion::V3 || self.version == DeviceInfoVersion::V2 { 154 ensure!(!self.vbmeta_digest.is_empty(), "vbmeta_digest must not be empty"); 155 ensure!( 156 !self.vbmeta_digest.iter().all(|b| *b == 0u8), 157 "vbmeta_digest must not be all zeros. Got {:?}", 158 self.vbmeta_digest 159 ); 160 161 ensure!( 162 self.vb_state != DeviceInfoVbState::Factory, 163 "vb_state must be a valid production value" 164 ); 165 ensure!( 166 self.bootloader_state != DeviceInfoBootloaderState::Factory, 167 "bootloader_state must be a valid production value" 168 ); 169 ensure!( 170 self.fused == 0 || self.fused == 1, 171 "fused must be a valid production value {}", 172 self.fused 173 ); 174 ensure!( 175 self.security_level != DeviceInfoSecurityLevel::Factory, 176 "security_level must be a valid production value" 177 ); 178 ensure!( 179 self.security_level != DeviceInfoSecurityLevel::Tee || self.os_version.is_some(), 180 "OS version is not optional with TEE" 181 ); 182 ensure!(!self.brand.is_empty(), "brand must not be empty"); 183 ensure!(!self.device.is_empty(), "device must not be empty"); 184 ensure!(!self.model.is_empty(), "model must not be empty"); 185 ensure!(!self.product.is_empty(), "product must not be empty"); 186 } 187 188 Ok(()) 189 } 190 } 191 192 #[cfg(test)] 193 mod tests { 194 use super::*; 195 use crate::rkp::DeviceInfoVersion; 196 197 #[test] device_info_from_cbor_values_optional_os_version()198 fn device_info_from_cbor_values_optional_os_version() { 199 let values: Vec<(Value, Value)> = get_valid_values_filtered(|x| x != "os_version"); 200 let info = DeviceInfo::from_cbor_values(values, None, true).unwrap(); 201 assert!(info.os_version.is_none()); 202 } 203 204 #[test] device_info_from_cbor_values_optional_os_version_is_not_optional_with_tee()205 fn device_info_from_cbor_values_optional_os_version_is_not_optional_with_tee() { 206 let values: Vec<(Value, Value)> = get_valid_tee_values_filtered(|x| x != "os_version"); 207 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 208 assert!(err.to_string().contains("OS version is not optional with TEE")); 209 } 210 211 #[test] device_info_from_cbor_values_missing_required_field()212 fn device_info_from_cbor_values_missing_required_field() { 213 let values: Vec<(Value, Value)> = get_valid_values_filtered(|x| x != "brand"); 214 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 215 assert!(err.to_string().contains("brand")); 216 } 217 218 #[test] from_cbor_values_valid_v2()219 fn from_cbor_values_valid_v2() { 220 let actual = DeviceInfo::from_cbor_values(get_valid_values(), None, false).unwrap(); 221 let expected = DeviceInfo { 222 brand: "generic".to_string(), 223 manufacturer: "acme".to_string(), 224 product: "phone".to_string(), 225 model: "the best one".to_string(), 226 device: "really the best".to_string(), 227 vb_state: DeviceInfoVbState::Green, 228 bootloader_state: DeviceInfoBootloaderState::Locked, 229 vbmeta_digest: b"abcdefg".to_vec(), 230 os_version: Some("dessert".to_string()), 231 system_patch_level: 303010, 232 boot_patch_level: 30300102, 233 vendor_patch_level: 30300304, 234 security_level: DeviceInfoSecurityLevel::StrongBox, 235 fused: 1, 236 version: DeviceInfoVersion::V2, 237 }; 238 assert_eq!(actual, expected); 239 } 240 241 #[test] device_info_from_cbor_values_valid_v3()242 fn device_info_from_cbor_values_valid_v3() { 243 let values: Vec<(Value, Value)> = get_valid_values_filtered(|x| x != "version"); 244 let actual = 245 DeviceInfo::from_cbor_values(values, Some(DeviceInfoVersion::V3), false).unwrap(); 246 let expected = DeviceInfo { 247 brand: "generic".to_string(), 248 manufacturer: "acme".to_string(), 249 product: "phone".to_string(), 250 model: "the best one".to_string(), 251 device: "really the best".to_string(), 252 vb_state: DeviceInfoVbState::Green, 253 bootloader_state: DeviceInfoBootloaderState::Locked, 254 vbmeta_digest: b"abcdefg".to_vec(), 255 os_version: Some("dessert".to_string()), 256 system_patch_level: 303010, 257 boot_patch_level: 30300102, 258 vendor_patch_level: 30300304, 259 security_level: DeviceInfoSecurityLevel::StrongBox, 260 fused: 1, 261 version: DeviceInfoVersion::V3, 262 }; 263 assert_eq!(actual, expected); 264 } 265 266 #[test] device_info_from_cbor_values_mismatched_version()267 fn device_info_from_cbor_values_mismatched_version() { 268 let values: Vec<(Value, Value)> = get_valid_values(); 269 let err = 270 DeviceInfo::from_cbor_values(values, Some(DeviceInfoVersion::V3), false).unwrap_err(); 271 println!("{err:?}"); 272 assert!(err.to_string().contains("version")); 273 } 274 275 #[test] device_info_from_cbor_values_invalid_version_value()276 fn device_info_from_cbor_values_invalid_version_value() { 277 let values: Vec<(Value, Value)> = get_valid_values_filtered(|x| x != "version"); 278 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 279 println!("{err:?}"); 280 assert!(err.to_string().contains("version")); 281 } 282 283 #[test] device_info_from_cbor_values_missing_version()284 fn device_info_from_cbor_values_missing_version() { 285 let values: Vec<(Value, Value)> = get_valid_values_filtered(|x| x != "version"); 286 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 287 println!("{err:?}"); 288 assert!(err.to_string().contains("version")); 289 } 290 291 #[test] device_info_from_cbor_duplicate_values()292 fn device_info_from_cbor_duplicate_values() { 293 let mut values: Vec<(Value, Value)> = get_valid_values(); 294 values.push(("brand".into(), "generic".into())); 295 296 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 297 println!("{err:?}"); 298 assert!(err.to_string().contains("may be set only once")); 299 } 300 301 #[test] device_info_from_cbor_empty_vbmeta_digest()302 fn device_info_from_cbor_empty_vbmeta_digest() { 303 let mut values: Vec<(Value, Value)> = get_valid_values_filtered(|v| v != "vbmeta_digest"); 304 values.push(("vbmeta_digest".into(), vec![0u8; 0].into())); 305 306 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 307 println!("{err:?}"); 308 assert!(err.to_string().contains("vbmeta_digest must not be empty"), "{err:?}"); 309 } 310 311 #[test] device_info_from_cbor_all_zero_vbmeta_digest()312 fn device_info_from_cbor_all_zero_vbmeta_digest() { 313 let mut values: Vec<(Value, Value)> = get_valid_values_filtered(|v| v != "vbmeta_digest"); 314 values.push(("vbmeta_digest".into(), vec![0u8; 16].into())); 315 316 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 317 println!("{err:?}"); 318 assert!(err.to_string().contains("vbmeta_digest must not be all zeros"), "{err:?}"); 319 } 320 321 #[test] device_info_from_cbor_values_non_avf_security_level_has_avf_vb_state()322 fn device_info_from_cbor_values_non_avf_security_level_has_avf_vb_state() { 323 let mut values = get_valid_values_filtered(|x| x != "vb_state"); 324 values.push(("vb_state".into(), "avf".into())); 325 326 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 327 assert!(err.to_string().contains("Non-AVF security level"), "{err:?}"); 328 } 329 330 #[test] device_info_from_cbor_values_non_avf_security_level_has_avf_bootloader_state()331 fn device_info_from_cbor_values_non_avf_security_level_has_avf_bootloader_state() { 332 let mut values = get_valid_values_filtered(|x| x != "bootloader_state"); 333 values.push(("bootloader_state".into(), "avf".into())); 334 335 let err = DeviceInfo::from_cbor_values(values, None, false).unwrap_err(); 336 assert!(err.to_string().contains("Non-AVF security level"), "{err:?}"); 337 } 338 339 #[test] device_info_from_cbor_values_avf_security_level_has_non_avf_vb_state()340 fn device_info_from_cbor_values_avf_security_level_has_non_avf_vb_state() { 341 let values: Vec<(Value, Value)> = get_valid_avf_values() 342 .into_iter() 343 .filter(|(k, _v)| k.as_text().unwrap() != "vb_state") 344 .chain(vec![("vb_state".into(), "green".into())]) 345 .collect(); 346 let err = 347 DeviceInfo::from_cbor_values(values, Some(DeviceInfoVersion::V3), false).unwrap_err(); 348 assert!(err.to_string().contains("AVF security level requires AVF fields"), "{err:?}"); 349 } 350 351 #[test] device_info_from_cbor_values_avf_security_level_has_avf_fields()352 fn device_info_from_cbor_values_avf_security_level_has_avf_fields() { 353 let values = get_valid_avf_values(); 354 let actual = 355 DeviceInfo::from_cbor_values(values, Some(DeviceInfoVersion::V3), false).unwrap(); 356 let expected = DeviceInfo { 357 brand: "aosp-avf".to_string(), 358 manufacturer: "aosp-avf".to_string(), 359 product: "avf".to_string(), 360 model: "avf".to_string(), 361 device: "avf".to_string(), 362 vb_state: DeviceInfoVbState::Avf, 363 bootloader_state: DeviceInfoBootloaderState::Avf, 364 vbmeta_digest: b"abcdefg".to_vec(), 365 os_version: Some("dessert".to_string()), 366 system_patch_level: 303010, 367 boot_patch_level: 30300102, 368 vendor_patch_level: 30300304, 369 security_level: DeviceInfoSecurityLevel::Avf, 370 fused: 1, 371 version: DeviceInfoVersion::V3, 372 }; 373 assert_eq!(expected, actual); 374 } 375 get_valid_values() -> Vec<(Value, Value)>376 fn get_valid_values() -> Vec<(Value, Value)> { 377 vec![ 378 ("brand".into(), "generic".into()), 379 ("manufacturer".into(), "acme".into()), 380 ("product".into(), "phone".into()), 381 ("model".into(), "the best one".into()), 382 ("device".into(), "really the best".into()), 383 ("vb_state".into(), "green".into()), 384 ("bootloader_state".into(), "locked".into()), 385 ("vbmeta_digest".into(), b"abcdefg".as_ref().into()), 386 ("os_version".into(), "dessert".into()), 387 ("system_patch_level".into(), 303010.into()), 388 ("boot_patch_level".into(), 30300102.into()), 389 ("vendor_patch_level".into(), 30300304.into()), 390 ("security_level".into(), "strongbox".into()), 391 ("fused".into(), 1.into()), 392 ("version".into(), 2.into()), 393 ] 394 } 395 get_valid_tee_values() -> Vec<(Value, Value)>396 fn get_valid_tee_values() -> Vec<(Value, Value)> { 397 vec![ 398 ("brand".into(), "generic".into()), 399 ("manufacturer".into(), "acme".into()), 400 ("product".into(), "phone".into()), 401 ("model".into(), "the best one".into()), 402 ("device".into(), "really the best".into()), 403 ("vb_state".into(), "green".into()), 404 ("bootloader_state".into(), "locked".into()), 405 ("vbmeta_digest".into(), b"abcdefg".as_ref().into()), 406 ("os_version".into(), "dessert".into()), 407 ("system_patch_level".into(), 303010.into()), 408 ("boot_patch_level".into(), 30300102.into()), 409 ("vendor_patch_level".into(), 30300304.into()), 410 ("security_level".into(), "tee".into()), 411 ("fused".into(), 1.into()), 412 ("version".into(), 2.into()), 413 ] 414 } 415 get_valid_avf_values() -> Vec<(Value, Value)>416 fn get_valid_avf_values() -> Vec<(Value, Value)> { 417 vec![ 418 ("brand".into(), "aosp-avf".into()), 419 ("manufacturer".into(), "aosp-avf".into()), 420 ("product".into(), "avf".into()), 421 ("model".into(), "avf".into()), 422 ("device".into(), "avf".into()), 423 ("vb_state".into(), "avf".into()), 424 ("bootloader_state".into(), "avf".into()), 425 ("vbmeta_digest".into(), b"abcdefg".as_ref().into()), 426 ("os_version".into(), "dessert".into()), 427 ("system_patch_level".into(), 303010.into()), 428 ("boot_patch_level".into(), 30300102.into()), 429 ("vendor_patch_level".into(), 30300304.into()), 430 ("security_level".into(), "avf".into()), 431 ("fused".into(), 1.into()), 432 ] 433 } 434 get_valid_values_filtered<F: Fn(&str) -> bool>(filter: F) -> Vec<(Value, Value)>435 fn get_valid_values_filtered<F: Fn(&str) -> bool>(filter: F) -> Vec<(Value, Value)> { 436 get_valid_values().into_iter().filter(|x| filter(x.0.as_text().unwrap())).collect() 437 } 438 get_valid_tee_values_filtered<F: Fn(&str) -> bool>(filter: F) -> Vec<(Value, Value)>439 fn get_valid_tee_values_filtered<F: Fn(&str) -> bool>(filter: F) -> Vec<(Value, Value)> { 440 get_valid_tee_values().into_iter().filter(|x| filter(x.0.as_text().unwrap())).collect() 441 } 442 } 443