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