1 // Copyright 2021, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! This module implements the shared secret negotiation.
16
17 use crate::error::{map_binder_status, map_binder_status_code, Error};
18 use crate::globals::get_keymint_device;
19 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
20 use android_hardware_security_keymint::binder::Strong;
21 use android_hardware_security_sharedsecret::aidl::android::hardware::security::sharedsecret::{
22 ISharedSecret::ISharedSecret, SharedSecretParameters::SharedSecretParameters,
23 };
24 use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
25 use anyhow::Result;
26 use binder::get_declared_instances;
27 use keystore2_vintf::get_hidl_instances;
28 use std::fmt::{self, Display, Formatter};
29 use std::time::Duration;
30
31 /// This function initiates the shared secret negotiation. It starts a thread and then returns
32 /// immediately. The thread consults the vintf manifest to enumerate expected negotiation
33 /// participants. It then attempts to connect to all of these participants. If any connection
34 /// fails the thread will retry once per second to connect to the failed instance(s) until all of
35 /// the instances are connected. It then performs the negotiation.
36 ///
37 /// During the first phase of the negotiation it will again try every second until
38 /// all instances have responded successfully to account for instances that register early but
39 /// are not fully functioning at this time due to hardware delays or boot order dependency issues.
40 /// An error during the second phase or a checksum mismatch leads to a panic.
perform_shared_secret_negotiation()41 pub fn perform_shared_secret_negotiation() {
42 std::thread::spawn(|| {
43 let participants = list_participants()
44 .expect("In perform_shared_secret_negotiation: Trying to list participants.");
45 let connected = connect_participants(participants);
46 negotiate_shared_secret(connected);
47 log::info!("Shared secret negotiation concluded successfully.");
48
49 // Once shared secret negotiation is done, the StrongBox and TEE have a common key that
50 // can be used to authenticate a possible RootOfTrust transfer.
51 transfer_root_of_trust();
52 });
53 }
54
55 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
56 enum SharedSecretParticipant {
57 /// Represents an instance of android.hardware.security.sharedsecret.ISharedSecret.
58 Aidl(String),
59 /// In the legacy case there can be at most one TEE and one Strongbox hal.
60 Hidl { is_strongbox: bool, version: (usize, usize) },
61 }
62
63 impl Display for SharedSecretParticipant {
fmt(&self, f: &mut Formatter) -> fmt::Result64 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
65 match self {
66 Self::Aidl(instance) => write!(
67 f,
68 "{}.{}/{}",
69 SHARED_SECRET_PACKAGE_NAME, SHARED_SECRET_INTERFACE_NAME, instance
70 ),
71 Self::Hidl { is_strongbox, version: (ma, mi) } => write!(
72 f,
73 "{}@V{}.{}::{}/{}",
74 KEYMASTER_PACKAGE_NAME,
75 ma,
76 mi,
77 KEYMASTER_INTERFACE_NAME,
78 if *is_strongbox { "strongbox" } else { "default" }
79 ),
80 }
81 }
82 }
83
84 #[derive(thiserror::Error, Debug)]
85 enum SharedSecretError {
86 #[error("Shared parameter retrieval failed on instance {p} with error {e:?}.")]
87 ParameterRetrieval { e: Error, p: SharedSecretParticipant },
88 #[error("Shared secret computation failed on instance {p} with error {e:?}.")]
89 Computation { e: Error, p: SharedSecretParticipant },
90 #[error("Checksum comparison failed on instance {0}.")]
91 Checksum(SharedSecretParticipant),
92 }
93
filter_map_legacy_km_instances( name: String, version: (usize, usize), ) -> Option<SharedSecretParticipant>94 fn filter_map_legacy_km_instances(
95 name: String,
96 version: (usize, usize),
97 ) -> Option<SharedSecretParticipant> {
98 match name.as_str() {
99 "default" => Some(SharedSecretParticipant::Hidl { is_strongbox: false, version }),
100 "strongbox" => Some(SharedSecretParticipant::Hidl { is_strongbox: true, version }),
101 _ => {
102 log::warn!("Found unexpected keymaster instance: \"{}\"", name);
103 log::warn!("Device is misconfigured. Allowed instances are:");
104 log::warn!(" * default");
105 log::warn!(" * strongbox");
106 None
107 }
108 }
109 }
110
111 static KEYMASTER_PACKAGE_NAME: &str = "android.hardware.keymaster";
112 static KEYMASTER_INTERFACE_NAME: &str = "IKeymasterDevice";
113 static SHARED_SECRET_PACKAGE_NAME: &str = "android.hardware.security.sharedsecret";
114 static SHARED_SECRET_INTERFACE_NAME: &str = "ISharedSecret";
115 static SHARED_SECRET_PACKAGE_AND_INTERFACE_NAME: &str =
116 "android.hardware.security.sharedsecret.ISharedSecret";
117 static COMPAT_PACKAGE_NAME: &str = "android.security.compat";
118
119 /// Lists participants.
list_participants() -> Result<Vec<SharedSecretParticipant>>120 fn list_participants() -> Result<Vec<SharedSecretParticipant>> {
121 // 4.1 implementation always also register as 4.0. So only the highest version of each
122 // "default" and "strongbox" makes the cut.
123 let mut legacy_default_found: bool = false;
124 let mut legacy_strongbox_found: bool = false;
125 Ok([(4, 1), (4, 0)]
126 .iter()
127 .flat_map(|(ma, mi)| {
128 get_hidl_instances(KEYMASTER_PACKAGE_NAME, *ma, *mi, KEYMASTER_INTERFACE_NAME)
129 .iter()
130 .filter_map(|name| {
131 filter_map_legacy_km_instances(name.to_string(), (*ma, *mi)).and_then(|sp| {
132 if let SharedSecretParticipant::Hidl { is_strongbox: true, .. } = &sp {
133 if !legacy_strongbox_found {
134 legacy_strongbox_found = true;
135 return Some(sp);
136 }
137 } else if !legacy_default_found {
138 legacy_default_found = true;
139 return Some(sp);
140 }
141 None
142 })
143 })
144 .collect::<Vec<SharedSecretParticipant>>()
145 })
146 .chain({
147 get_declared_instances(SHARED_SECRET_PACKAGE_AND_INTERFACE_NAME)
148 .unwrap()
149 .into_iter()
150 .map(SharedSecretParticipant::Aidl)
151 .collect::<Vec<_>>()
152 .into_iter()
153 })
154 .collect())
155 }
156
connect_participants( mut participants: Vec<SharedSecretParticipant>, ) -> Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)>157 fn connect_participants(
158 mut participants: Vec<SharedSecretParticipant>,
159 ) -> Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)> {
160 let mut connected_participants: Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)> =
161 vec![];
162 loop {
163 let (connected, not_connected) = participants.into_iter().fold(
164 (connected_participants, vec![]),
165 |(mut connected, mut failed), e| {
166 match e {
167 SharedSecretParticipant::Aidl(instance_name) => {
168 let service_name = format!(
169 "{}.{}/{}",
170 SHARED_SECRET_PACKAGE_NAME, SHARED_SECRET_INTERFACE_NAME, instance_name
171 );
172 match map_binder_status_code(binder::get_interface(&service_name)) {
173 Err(e) => {
174 log::warn!(
175 "Unable to connect \"{}\" with error:\n{:?}\nRetrying later.",
176 service_name,
177 e
178 );
179 failed.push(SharedSecretParticipant::Aidl(instance_name));
180 }
181 Ok(service) => connected
182 .push((service, SharedSecretParticipant::Aidl(instance_name))),
183 }
184 }
185 SharedSecretParticipant::Hidl { is_strongbox, version } => {
186 // This is a no-op if it was called before.
187 keystore2_km_compat::add_keymint_device_service();
188
189 // If we cannot connect to the compatibility service there is no way to
190 // recover.
191 // PANIC! - Unless you brought your towel.
192 let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
193 map_binder_status_code(binder::get_interface(COMPAT_PACKAGE_NAME))
194 .expect(
195 "In connect_participants: Trying to connect to compat service.",
196 );
197
198 match map_binder_status(keystore_compat_service.getSharedSecret(
199 if is_strongbox {
200 SecurityLevel::STRONGBOX
201 } else {
202 SecurityLevel::TRUSTED_ENVIRONMENT
203 },
204 )) {
205 Err(e) => {
206 log::warn!(
207 concat!(
208 "Unable to connect keymaster device \"{}\" ",
209 "with error:\n{:?}\nRetrying later."
210 ),
211 if is_strongbox { "strongbox" } else { "TEE" },
212 e
213 );
214 failed
215 .push(SharedSecretParticipant::Hidl { is_strongbox, version });
216 }
217 Ok(service) => connected.push((
218 service,
219 SharedSecretParticipant::Hidl { is_strongbox, version },
220 )),
221 }
222 }
223 }
224 (connected, failed)
225 },
226 );
227 participants = not_connected;
228 connected_participants = connected;
229 if participants.is_empty() {
230 break;
231 }
232 std::thread::sleep(Duration::from_millis(1000));
233 }
234 connected_participants
235 }
236
negotiate_shared_secret( participants: Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)>, )237 fn negotiate_shared_secret(
238 participants: Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)>,
239 ) {
240 // Phase 1: Get the sharing parameters from all participants.
241 let mut params = loop {
242 let result: Result<Vec<SharedSecretParameters>, SharedSecretError> = participants
243 .iter()
244 .map(|(s, p)| {
245 map_binder_status(s.getSharedSecretParameters())
246 .map_err(|e| SharedSecretError::ParameterRetrieval { e, p: (*p).clone() })
247 })
248 .collect();
249
250 match result {
251 Err(e) => {
252 log::warn!("{:?}", e);
253 log::warn!("Retrying in one second.");
254 std::thread::sleep(Duration::from_millis(1000));
255 }
256 Ok(params) => break params,
257 }
258 };
259
260 params.sort_unstable();
261
262 // Phase 2: Send the sorted sharing parameters to all participants.
263 let negotiation_result = participants.into_iter().try_fold(None, |acc, (s, p)| {
264 match (acc, map_binder_status(s.computeSharedSecret(¶ms))) {
265 (None, Ok(new_sum)) => Ok(Some(new_sum)),
266 (Some(old_sum), Ok(new_sum)) => {
267 if old_sum == new_sum {
268 Ok(Some(old_sum))
269 } else {
270 Err(SharedSecretError::Checksum(p))
271 }
272 }
273 (_, Err(e)) => Err(SharedSecretError::Computation { e, p }),
274 }
275 });
276
277 if let Err(e) = negotiation_result {
278 log::error!("In negotiate_shared_secret: {:?}.", e);
279 if let SharedSecretError::Checksum(_) = e {
280 log::error!(concat!(
281 "This means that this device is NOT PROVISIONED CORRECTLY.\n",
282 "User authorization and other security functions will not work\n",
283 "as expected. Please contact your OEM for instructions.",
284 ));
285 }
286 }
287 }
288
289 /// Perform RootOfTrust transfer from TEE to StrongBox (if available).
transfer_root_of_trust()290 pub fn transfer_root_of_trust() {
291 let strongbox = match get_keymint_device(&SecurityLevel::STRONGBOX) {
292 Ok((s, _, _)) => s,
293 Err(_e) => {
294 log::info!("No StrongBox Keymint available, so no RoT transfer");
295 return;
296 }
297 };
298 // Ask the StrongBox KeyMint for a challenge.
299 let challenge = match strongbox.getRootOfTrustChallenge() {
300 Ok(data) => data,
301 Err(e) => {
302 // If StrongBox doesn't provide a challenge, it might be because:
303 // - it already has RootOfTrust information
304 // - it's a KeyMint v1 implementation that doesn't understand the method.
305 // In either case, we're done.
306 log::info!("StrongBox does not provide a challenge, so no RoT transfer: {:?}", e);
307 return;
308 }
309 };
310 // Get the RoT info from the TEE
311 let tee = match get_keymint_device(&SecurityLevel::TRUSTED_ENVIRONMENT) {
312 Ok((s, _, _)) => s,
313 Err(e) => {
314 log::error!("No TEE KeyMint implementation found! {:?}", e);
315 return;
316 }
317 };
318 let root_of_trust = match tee.getRootOfTrust(&challenge) {
319 Ok(rot) => rot,
320 Err(e) => {
321 log::error!("TEE KeyMint failed to return RootOfTrust info: {:?}", e);
322 return;
323 }
324 };
325 // The RootOfTrust information is CBOR-serialized data, but we don't need to parse it.
326 // Just pass it on to the StrongBox KeyMint instance.
327 let result = strongbox.sendRootOfTrust(&root_of_trust);
328 if let Err(e) = result {
329 log::error!("Failed to send RootOfTrust to StrongBox: {:?}", e);
330 }
331 log::info!("RootOfTrust transfer process complete");
332 }
333