• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! KeyMint helper functions that are only suitable for non-secure environments
18 //! such as Cuttlefish.
19 
20 use kmr_hal::env::get_property;
21 use log::error;
22 
23 /// Retrieve the most significant attestation property for `name`.
attestation_property(name: &str) -> Vec<u8>24 fn attestation_property(name: &str) -> Vec<u8> {
25     let prop_val = get_property(&format!("ro.product.vendor.{}", name)).unwrap_or_default();
26     if !prop_val.is_empty() {
27         prop_val
28     } else {
29         get_property(&format!("ro.product.{}", name))
30             .unwrap_or_else(|prop_name| format!("{} unavailable", prop_name))
31     }
32     .as_bytes()
33     .to_vec()
34 }
35 
36 /// Populate attestation ID information based on properties (where available).
37 /// Retrieving the serial number requires SELinux permission.
attestation_id_info() -> kmr_wire::AttestationIdInfo38 pub fn attestation_id_info() -> kmr_wire::AttestationIdInfo {
39     let prop = |name| {
40         get_property(name)
41             .unwrap_or_else(|_| format!("{} unavailable", name))
42             .as_bytes()
43             .to_vec()
44     };
45     kmr_wire::AttestationIdInfo {
46         brand: attestation_property("brand"),
47         device: attestation_property("device"),
48         product: attestation_property("name"),
49         serial: prop("ro.serialno"),
50         manufacturer: attestation_property("manufacturer"),
51         model: attestation_property("model"),
52         // Currently modem_simulator always returns one fixed value. See `handleGetIMEI` in
53         // device/google/cuttlefish/host/commands/modem_simulator/misc_service.cpp for more details.
54         // TODO(b/263188546): Use device-specific IMEI values when available.
55         imei: b"867400022047199".to_vec(),
56         imei2: b"867400022047199".to_vec(),
57         meid: vec![],
58     }
59 }
60 
61 /// Get boot information based on system properties.
get_boot_info() -> kmr_wire::SetBootInfoRequest62 pub fn get_boot_info() -> kmr_wire::SetBootInfoRequest {
63     let vbmeta_digest = get_property("ro.boot.vbmeta.digest").unwrap_or_else(|_| "00".repeat(32));
64     let verified_boot_hash = hex::decode(&vbmeta_digest).unwrap_or_else(|_e| {
65         error!("failed to parse VBMeta digest hex data in '{vbmeta_digest}': {_e:?}");
66         vec![0; 32]
67     });
68     let device_boot_locked = match get_property("ro.boot.vbmeta.device_state")
69         .unwrap_or_else(|_| "no-prop".to_string())
70         .as_str()
71     {
72         "locked" => true,
73         "unlocked" => false,
74         v => {
75             error!("Unknown device_state '{}', treating as unlocked", v);
76             false
77         }
78     };
79     let verified_boot_key_digest =
80         get_property("ro.boot.vbmeta.public_key_digest").unwrap_or_else(|_| "00".repeat(32));
81     let verified_boot_key = match device_boot_locked {
82         true => hex::decode(&verified_boot_key_digest).unwrap_or_else(|_e| {
83             error!("Failed to parse Verified Boot key hex data in '{verified_boot_key_digest}': {_e:?}");
84             vec![0; 32]
85         }),
86         // VTS-16+ requires the attested Verified Boot key to be 32 bytes of zeroes when the
87         // bootloader is unlocked, so we ignore the property's value in that case. Behaviour
88         // prior to VTS-16 is unspecified, so it's fine to return the same.
89         false => vec![0; 32],
90     };
91     let verified_boot_state = match get_property("ro.boot.verifiedbootstate")
92         .unwrap_or_else(|_| "no-prop".to_string())
93         .as_str()
94     {
95         "green" => 0,  // Verified
96         "yellow" => 1, // SelfSigned
97         "orange" => 2, // Unverified,
98         "red" => 3,    // Failed,
99         v => {
100             error!("Unknown boot state '{}', treating as Unverified", v);
101             2
102         }
103     };
104 
105     // Attempt to get the boot patchlevel from a system property.  This requires an SELinux
106     // permission, so fall back to re-using the OS patchlevel if this can't be done.
107     let boot_patchlevel_prop = get_property("ro.vendor.boot_security_patch").unwrap_or_else(|e| {
108         error!("Failed to retrieve boot patchlevel: {:?}", e);
109         get_property(kmr_hal::env::OS_PATCHLEVEL_PROPERTY)
110             .unwrap_or_else(|_| "1970-09-19".to_string())
111     });
112     let boot_patchlevel =
113         kmr_hal::env::extract_patchlevel(&boot_patchlevel_prop).unwrap_or(19700919);
114 
115     kmr_wire::SetBootInfoRequest {
116         verified_boot_key,
117         device_boot_locked,
118         verified_boot_state,
119         verified_boot_hash,
120         boot_patchlevel,
121     }
122 }
123