blob: 739f4babc71d7e7a562e2a90f39676493acc995d [file] [log] [blame]
Janis Danisevskis84a83e42021-03-21 21:46:54 -07001// 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
17use crate::error::{map_binder_status, map_binder_status_code, Error};
David Drysdaleecd403d2022-03-18 10:13:41 +000018use crate::globals::get_keymint_device;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070019use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
20use android_hardware_security_keymint::binder::Strong;
21use android_hardware_security_sharedsecret::aidl::android::hardware::security::sharedsecret::{
22 ISharedSecret::ISharedSecret, SharedSecretParameters::SharedSecretParameters,
23};
24use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
Joel Galensonec7872a2021-07-02 14:37:10 -070025use anyhow::Result;
Shaquille Johnsond4443c62023-02-23 17:39:24 +000026use binder::get_declared_instances;
27use keystore2_vintf::get_hidl_instances;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070028use std::fmt::{self, Display, Formatter};
Janis Danisevskisd7308c72021-06-10 14:42:36 -070029use std::time::Duration;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070030
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.
41pub 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.");
David Drysdaleecd403d2022-03-18 10:13:41 +000048
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();
Janis Danisevskis84a83e42021-03-21 21:46:54 -070052 });
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
56enum 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
63impl Display for SharedSecretParticipant {
64 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)]
85enum 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
94fn 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
111static KEYMASTER_PACKAGE_NAME: &str = "android.hardware.keymaster";
112static KEYMASTER_INTERFACE_NAME: &str = "IKeymasterDevice";
113static SHARED_SECRET_PACKAGE_NAME: &str = "android.hardware.security.sharedsecret";
114static SHARED_SECRET_INTERFACE_NAME: &str = "ISharedSecret";
Shaquille Johnsond4443c62023-02-23 17:39:24 +0000115static SHARED_SECRET_PACKAGE_AND_INTERFACE_NAME: &str =
116 "android.hardware.security.sharedsecret.ISharedSecret";
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700117static COMPAT_PACKAGE_NAME: &str = "android.security.compat";
118
119/// Lists participants.
120fn list_participants() -> Result<Vec<SharedSecretParticipant>> {
Janis Danisevskisd0e08882021-06-08 15:03:07 -0700121 // 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)]
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700126 .iter()
Chariseec3f67ea2023-03-03 02:12:50 +0000127 .flat_map(|(ma, mi)| {
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700128 get_hidl_instances(KEYMASTER_PACKAGE_NAME, *ma, *mi, KEYMASTER_INTERFACE_NAME)
Chariseec3f67ea2023-03-03 02:12:50 +0000129 .iter()
Joel Galensonec7872a2021-07-02 14:37:10 -0700130 .filter_map(|name| {
Chariseec3f67ea2023-03-03 02:12:50 +0000131 filter_map_legacy_km_instances(name.to_string(), (*ma, *mi)).and_then(|sp| {
Joel Galensonec7872a2021-07-02 14:37:10 -0700132 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 })
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700143 })
Joel Galensonec7872a2021-07-02 14:37:10 -0700144 .collect::<Vec<SharedSecretParticipant>>()
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700145 })
Joel Galensonec7872a2021-07-02 14:37:10 -0700146 .chain({
Shaquille Johnsond4443c62023-02-23 17:39:24 +0000147 get_declared_instances(SHARED_SECRET_PACKAGE_AND_INTERFACE_NAME)
148 .unwrap()
Joel Galensonec7872a2021-07-02 14:37:10 -0700149 .into_iter()
150 .map(SharedSecretParticipant::Aidl)
151 .collect::<Vec<_>>()
152 .into_iter()
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700153 })
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700154 .collect())
155}
156
157fn 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) => {
Janis Danisevskisd544d5a2021-03-24 12:30:14 -0700168 let service_name = format!(
169 "{}.{}/{}",
170 SHARED_SECRET_PACKAGE_NAME, SHARED_SECRET_INTERFACE_NAME, instance_name
171 );
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700172 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 }
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700232 std::thread::sleep(Duration::from_millis(1000));
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700233 }
234 connected_participants
235}
236
237fn 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.");
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700254 std::thread::sleep(Duration::from_millis(1000));
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700255 }
256 Ok(params) => break params,
257 }
258 };
259
260 params.sort_unstable();
261
262 // Phase 2: Send the sorted sharing parameters to all participants.
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700263 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))
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700271 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700272 }
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700273 (_, 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 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700287}
David Drysdaleecd403d2022-03-18 10:13:41 +0000288
289/// Perform RootOfTrust transfer from TEE to StrongBox (if available).
290pub 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}