• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params))) {
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