blob: 42d38d29f4c66df243325bb747e97408dffc9026 [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;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070026use keystore2_vintf::{get_aidl_instances, get_hidl_instances};
27use std::fmt::{self, Display, Formatter};
Janis Danisevskisd7308c72021-06-10 14:42:36 -070028use std::time::Duration;
Janis Danisevskis84a83e42021-03-21 21:46:54 -070029
30/// This function initiates the shared secret negotiation. It starts a thread and then returns
31/// immediately. The thread consults the vintf manifest to enumerate expected negotiation
32/// participants. It then attempts to connect to all of these participants. If any connection
33/// fails the thread will retry once per second to connect to the failed instance(s) until all of
34/// the instances are connected. It then performs the negotiation.
35///
36/// During the first phase of the negotiation it will again try every second until
37/// all instances have responded successfully to account for instances that register early but
38/// are not fully functioning at this time due to hardware delays or boot order dependency issues.
39/// An error during the second phase or a checksum mismatch leads to a panic.
40pub fn perform_shared_secret_negotiation() {
41 std::thread::spawn(|| {
42 let participants = list_participants()
43 .expect("In perform_shared_secret_negotiation: Trying to list participants.");
44 let connected = connect_participants(participants);
45 negotiate_shared_secret(connected);
46 log::info!("Shared secret negotiation concluded successfully.");
David Drysdaleecd403d2022-03-18 10:13:41 +000047
48 // Once shared secret negotiation is done, the StrongBox and TEE have a common key that
49 // can be used to authenticate a possible RootOfTrust transfer.
50 transfer_root_of_trust();
Janis Danisevskis84a83e42021-03-21 21:46:54 -070051 });
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55enum SharedSecretParticipant {
56 /// Represents an instance of android.hardware.security.sharedsecret.ISharedSecret.
57 Aidl(String),
58 /// In the legacy case there can be at most one TEE and one Strongbox hal.
59 Hidl { is_strongbox: bool, version: (usize, usize) },
60}
61
62impl Display for SharedSecretParticipant {
63 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
64 match self {
65 Self::Aidl(instance) => write!(
66 f,
67 "{}.{}/{}",
68 SHARED_SECRET_PACKAGE_NAME, SHARED_SECRET_INTERFACE_NAME, 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)]
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";
112static SHARED_SECRET_PACKAGE_NAME: &str = "android.hardware.security.sharedsecret";
113static SHARED_SECRET_INTERFACE_NAME: &str = "ISharedSecret";
114static COMPAT_PACKAGE_NAME: &str = "android.security.compat";
115
116/// Lists participants.
117fn list_participants() -> Result<Vec<SharedSecretParticipant>> {
Janis Danisevskisd0e08882021-06-08 15:03:07 -0700118 // 4.1 implementation always also register as 4.0. So only the highest version of each
119 // "default" and "strongbox" makes the cut.
120 let mut legacy_default_found: bool = false;
121 let mut legacy_strongbox_found: bool = false;
122 Ok([(4, 1), (4, 0)]
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700123 .iter()
124 .map(|(ma, mi)| {
125 get_hidl_instances(KEYMASTER_PACKAGE_NAME, *ma, *mi, KEYMASTER_INTERFACE_NAME)
Joel Galensonec7872a2021-07-02 14:37:10 -0700126 .into_iter()
127 .filter_map(|name| {
128 filter_map_legacy_km_instances(name, (*ma, *mi)).and_then(|sp| {
129 if let SharedSecretParticipant::Hidl { is_strongbox: true, .. } = &sp {
130 if !legacy_strongbox_found {
131 legacy_strongbox_found = true;
132 return Some(sp);
133 }
134 } else if !legacy_default_found {
135 legacy_default_found = true;
136 return Some(sp);
137 }
138 None
139 })
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700140 })
Joel Galensonec7872a2021-07-02 14:37:10 -0700141 .collect::<Vec<SharedSecretParticipant>>()
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700142 })
Joel Galensonec7872a2021-07-02 14:37:10 -0700143 .into_iter()
144 .flatten()
145 .chain({
146 get_aidl_instances(SHARED_SECRET_PACKAGE_NAME, 1, SHARED_SECRET_INTERFACE_NAME)
147 .into_iter()
148 .map(SharedSecretParticipant::Aidl)
149 .collect::<Vec<_>>()
150 .into_iter()
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700151 })
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700152 .collect())
153}
154
155fn connect_participants(
156 mut participants: Vec<SharedSecretParticipant>,
157) -> Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)> {
158 let mut connected_participants: Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)> =
159 vec![];
160 loop {
161 let (connected, not_connected) = participants.into_iter().fold(
162 (connected_participants, vec![]),
163 |(mut connected, mut failed), e| {
164 match e {
165 SharedSecretParticipant::Aidl(instance_name) => {
Janis Danisevskisd544d5a2021-03-24 12:30:14 -0700166 let service_name = format!(
167 "{}.{}/{}",
168 SHARED_SECRET_PACKAGE_NAME, SHARED_SECRET_INTERFACE_NAME, instance_name
169 );
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700170 match map_binder_status_code(binder::get_interface(&service_name)) {
171 Err(e) => {
172 log::warn!(
173 "Unable to connect \"{}\" with error:\n{:?}\nRetrying later.",
174 service_name,
175 e
176 );
177 failed.push(SharedSecretParticipant::Aidl(instance_name));
178 }
179 Ok(service) => connected
180 .push((service, SharedSecretParticipant::Aidl(instance_name))),
181 }
182 }
183 SharedSecretParticipant::Hidl { is_strongbox, version } => {
184 // This is a no-op if it was called before.
185 keystore2_km_compat::add_keymint_device_service();
186
187 // If we cannot connect to the compatibility service there is no way to
188 // recover.
189 // PANIC! - Unless you brought your towel.
190 let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
191 map_binder_status_code(binder::get_interface(COMPAT_PACKAGE_NAME))
192 .expect(
193 "In connect_participants: Trying to connect to compat service.",
194 );
195
196 match map_binder_status(keystore_compat_service.getSharedSecret(
197 if is_strongbox {
198 SecurityLevel::STRONGBOX
199 } else {
200 SecurityLevel::TRUSTED_ENVIRONMENT
201 },
202 )) {
203 Err(e) => {
204 log::warn!(
205 concat!(
206 "Unable to connect keymaster device \"{}\" ",
207 "with error:\n{:?}\nRetrying later."
208 ),
209 if is_strongbox { "strongbox" } else { "TEE" },
210 e
211 );
212 failed
213 .push(SharedSecretParticipant::Hidl { is_strongbox, version });
214 }
215 Ok(service) => connected.push((
216 service,
217 SharedSecretParticipant::Hidl { is_strongbox, version },
218 )),
219 }
220 }
221 }
222 (connected, failed)
223 },
224 );
225 participants = not_connected;
226 connected_participants = connected;
227 if participants.is_empty() {
228 break;
229 }
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700230 std::thread::sleep(Duration::from_millis(1000));
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700231 }
232 connected_participants
233}
234
235fn negotiate_shared_secret(
236 participants: Vec<(Strong<dyn ISharedSecret>, SharedSecretParticipant)>,
237) {
238 // Phase 1: Get the sharing parameters from all participants.
239 let mut params = loop {
240 let result: Result<Vec<SharedSecretParameters>, SharedSecretError> = participants
241 .iter()
242 .map(|(s, p)| {
243 map_binder_status(s.getSharedSecretParameters())
244 .map_err(|e| SharedSecretError::ParameterRetrieval { e, p: (*p).clone() })
245 })
246 .collect();
247
248 match result {
249 Err(e) => {
250 log::warn!("{:?}", e);
251 log::warn!("Retrying in one second.");
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700252 std::thread::sleep(Duration::from_millis(1000));
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700253 }
254 Ok(params) => break params,
255 }
256 };
257
258 params.sort_unstable();
259
260 // Phase 2: Send the sorted sharing parameters to all participants.
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700261 let negotiation_result = participants.into_iter().try_fold(None, |acc, (s, p)| {
262 match (acc, map_binder_status(s.computeSharedSecret(&params))) {
263 (None, Ok(new_sum)) => Ok(Some(new_sum)),
264 (Some(old_sum), Ok(new_sum)) => {
265 if old_sum == new_sum {
266 Ok(Some(old_sum))
267 } else {
268 Err(SharedSecretError::Checksum(p))
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700269 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700270 }
Janis Danisevskisd7308c72021-06-10 14:42:36 -0700271 (_, Err(e)) => Err(SharedSecretError::Computation { e, p }),
272 }
273 });
274
275 if let Err(e) = negotiation_result {
276 log::error!("In negotiate_shared_secret: {:?}.", e);
277 if let SharedSecretError::Checksum(_) = e {
278 log::error!(concat!(
279 "This means that this device is NOT PROVISIONED CORRECTLY.\n",
280 "User authorization and other security functions will not work\n",
281 "as expected. Please contact your OEM for instructions.",
282 ));
283 }
284 }
Janis Danisevskis84a83e42021-03-21 21:46:54 -0700285}
David Drysdaleecd403d2022-03-18 10:13:41 +0000286
287/// Perform RootOfTrust transfer from TEE to StrongBox (if available).
288pub fn transfer_root_of_trust() {
289 let strongbox = match get_keymint_device(&SecurityLevel::STRONGBOX) {
290 Ok((s, _, _)) => s,
291 Err(_e) => {
292 log::info!("No StrongBox Keymint available, so no RoT transfer");
293 return;
294 }
295 };
296 // Ask the StrongBox KeyMint for a challenge.
297 let challenge = match strongbox.getRootOfTrustChallenge() {
298 Ok(data) => data,
299 Err(e) => {
300 // If StrongBox doesn't provide a challenge, it might be because:
301 // - it already has RootOfTrust information
302 // - it's a KeyMint v1 implementation that doesn't understand the method.
303 // In either case, we're done.
304 log::info!("StrongBox does not provide a challenge, so no RoT transfer: {:?}", e);
305 return;
306 }
307 };
308 // Get the RoT info from the TEE
309 let tee = match get_keymint_device(&SecurityLevel::TRUSTED_ENVIRONMENT) {
310 Ok((s, _, _)) => s,
311 Err(e) => {
312 log::error!("No TEE KeyMint implementation found! {:?}", e);
313 return;
314 }
315 };
316 let root_of_trust = match tee.getRootOfTrust(&challenge) {
317 Ok(rot) => rot,
318 Err(e) => {
319 log::error!("TEE KeyMint failed to return RootOfTrust info: {:?}", e);
320 return;
321 }
322 };
323 // The RootOfTrust information is CBOR-serialized data, but we don't need to parse it.
324 // Just pass it on to the StrongBox KeyMint instance.
325 let result = strongbox.sendRootOfTrust(&root_of_trust);
326 if let Err(e) = result {
327 log::error!("Failed to send RootOfTrust to StrongBox: {:?}", e);
328 }
329 log::info!("RootOfTrust transfer process complete");
330}