blob: ff0ddf8ab6de0c526d3ed61ad56d0b8f6155a454 [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::{
Shaquille Johnsondf83fb72023-03-24 12:26:52 +000022 ISharedSecret::BpSharedSecret, ISharedSecret::ISharedSecret,
23 SharedSecretParameters::SharedSecretParameters,
Janis Danisevskis84a83e42021-03-21 21:46:54 -070024};
25use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
Joel Galensonec7872a2021-07-02 14:37:10 -070026use anyhow::Result;
Shaquille Johnsond4443c62023-02-23 17:39:24 +000027use binder::get_declared_instances;
Shaquille Johnsonbbbe5d52023-03-09 17:37:08 +000028use keystore2_hal_names::get_hidl_instances;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070029use std::fmt::{self, Display, Formatter};
Janis Danisevskisd7308c72021-06-10 14:42:36 -070030use std::time::Duration;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070031
32/// This function initiates the shared secret negotiation. It starts a thread and then returns
Shaquille Johnsonbbbe5d52023-03-09 17:37:08 +000033/// 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.
Janis Danisevskis84a83e42021-03-21 21:46:54 -070037///
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.
42pub 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.");
David Drysdaleecd403d2022-03-18 10:13:41 +000049
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();
Janis Danisevskis84a83e42021-03-21 21:46:54 -070053 });
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
57enum 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
64impl Display for SharedSecretParticipant {
65 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
66 match self {
Shaquille Johnsondf83fb72023-03-24 12:26:52 +000067 Self::Aidl(instance) => {
68 write!(f, "{}/{}", <BpSharedSecret as ISharedSecret>::get_descriptor(), instance)
69 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -070070 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)]
84enum 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
93fn 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
110static KEYMASTER_PACKAGE_NAME: &str = "android.hardware.keymaster";
111static KEYMASTER_INTERFACE_NAME: &str = "IKeymasterDevice";
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700112static COMPAT_PACKAGE_NAME: &str = "android.security.compat";
113
114/// Lists participants.
115fn list_participants() -> Result<Vec<SharedSecretParticipant>> {
Janis Danisevskisd0e08882021-06-08 15:03:07 -0700116 // 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)]
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700121 .iter()
Chariseec3f67ea2023-03-03 02:12:50 +0000122 .flat_map(|(ma, mi)| {
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700123 get_hidl_instances(KEYMASTER_PACKAGE_NAME, *ma, *mi, KEYMASTER_INTERFACE_NAME)
Chariseec3f67ea2023-03-03 02:12:50 +0000124 .iter()
Joel Galensonec7872a2021-07-02 14:37:10 -0700125 .filter_map(|name| {
Chariseec3f67ea2023-03-03 02:12:50 +0000126 filter_map_legacy_km_instances(name.to_string(), (*ma, *mi)).and_then(|sp| {
Joel Galensonec7872a2021-07-02 14:37:10 -0700127 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 })
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700138 })
Joel Galensonec7872a2021-07-02 14:37:10 -0700139 .collect::<Vec<SharedSecretParticipant>>()
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700140 })
Joel Galensonec7872a2021-07-02 14:37:10 -0700141 .chain({
Shaquille Johnsondf83fb72023-03-24 12:26:52 +0000142 get_declared_instances(<BpSharedSecret as ISharedSecret>::get_descriptor())
Shaquille Johnsond4443c62023-02-23 17:39:24 +0000143 .unwrap()
Joel Galensonec7872a2021-07-02 14:37:10 -0700144 .into_iter()
145 .map(SharedSecretParticipant::Aidl)
146 .collect::<Vec<_>>()
147 .into_iter()
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700148 })
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700149 .collect())
150}
151
152fn 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) => {
Janis Danisevskisd544d5a2021-03-24 12:30:14 -0700163 let service_name = format!(
Shaquille Johnsondf83fb72023-03-24 12:26:52 +0000164 "{}/{}",
165 <BpSharedSecret as ISharedSecret>::get_descriptor(),
166 instance_name
Janis Danisevskisd544d5a2021-03-24 12:30:14 -0700167 );
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700168 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 }
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700228 std::thread::sleep(Duration::from_millis(1000));
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700229 }
230 connected_participants
231}
232
233fn 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.");
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700250 std::thread::sleep(Duration::from_millis(1000));
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700251 }
252 Ok(params) => break params,
253 }
254 };
255
256 params.sort_unstable();
257
258 // Phase 2: Send the sorted sharing parameters to all participants.
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700259 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))
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700267 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700268 }
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700269 (_, 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 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700283}
David Drysdaleecd403d2022-03-18 10:13:41 +0000284
285/// Perform RootOfTrust transfer from TEE to StrongBox (if available).
286pub 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}