xref: /aosp_15_r20/system/security/keystore2/tests/user_auth.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1 // Copyright 2024, 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 //! Tests for user authentication interactions (via `IKeystoreAuthorization`).
16 
17 use crate::keystore2_client_test_utils::{BarrierReached, BarrierReachedWithData};
18 use android_security_authorization::aidl::android::security::authorization::{
19     IKeystoreAuthorization::IKeystoreAuthorization
20 };
21 use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::{
22      IKeystoreMaintenance,
23 };
24 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
25     Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
26     HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
27     KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
28 };
29 use android_hardware_gatekeeper::aidl::android::hardware::gatekeeper::{
30     IGatekeeper::IGatekeeper, IGatekeeper::ERROR_RETRY_TIMEOUT,
31 };
32 use android_system_keystore2::aidl::android::system::keystore2::{
33     CreateOperationResponse::CreateOperationResponse, Domain::Domain, KeyDescriptor::KeyDescriptor,
34     KeyMetadata::KeyMetadata,
35 };
36 use android_system_keystore2::binder::{ExceptionCode, Result as BinderResult};
37 use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::{
38     Timestamp::Timestamp,
39 };
40 use anyhow::Context;
41 use keystore2_test_utils::{
42     authorizations::AuthSetBuilder, expect, get_keystore_service, run_as,
43     run_as::{ChannelReader, ChannelWriter}, expect_km_error,
44 };
45 use log::{warn, info};
46 use rustutils::users::AID_USER_OFFSET;
47 use std::{time::Duration, thread::sleep};
48 
49 /// Test user ID.
50 const TEST_USER_ID: i32 = 100;
51 /// Corresponding uid value.
52 const UID: u32 = TEST_USER_ID as u32 * AID_USER_OFFSET + 1001;
53 /// Fake synthetic password blob.
54 static SYNTHETIC_PASSWORD: &[u8] = &[
55     0x42, 0x39, 0x30, 0x37, 0x44, 0x37, 0x32, 0x37, 0x39, 0x39, 0x43, 0x42, 0x39, 0x41, 0x42, 0x30,
56     0x34, 0x31, 0x30, 0x38, 0x46, 0x44, 0x33, 0x45, 0x39, 0x42, 0x32, 0x38, 0x36, 0x35, 0x41, 0x36,
57     0x33, 0x44, 0x42, 0x42, 0x43, 0x36, 0x33, 0x42, 0x34, 0x39, 0x37, 0x33, 0x35, 0x45, 0x41, 0x41,
58     0x32, 0x45, 0x31, 0x35, 0x43, 0x43, 0x46, 0x32, 0x39, 0x36, 0x33, 0x34, 0x31, 0x32, 0x41, 0x39,
59 ];
60 /// Gatekeeper password.
61 static GK_PASSWORD: &[u8] = b"correcthorsebatterystaple";
62 /// Fake SID value corresponding to Gatekeeper.
63 static GK_FAKE_SID: i64 = 123456;
64 /// Fake SID value corresponding to a biometric authenticator.
65 static BIO_FAKE_SID1: i64 = 345678;
66 /// Fake SID value corresponding to a biometric authenticator.
67 static BIO_FAKE_SID2: i64 = 456789;
68 
69 const WEAK_UNLOCK_ENABLED: bool = true;
70 const WEAK_UNLOCK_DISABLED: bool = false;
71 const UNFORCED: bool = false;
72 
get_authorization() -> binder::Strong<dyn IKeystoreAuthorization>73 fn get_authorization() -> binder::Strong<dyn IKeystoreAuthorization> {
74     binder::get_interface("android.security.authorization").unwrap()
75 }
76 
get_maintenance() -> binder::Strong<dyn IKeystoreMaintenance>77 fn get_maintenance() -> binder::Strong<dyn IKeystoreMaintenance> {
78     binder::get_interface("android.security.maintenance").unwrap()
79 }
80 
81 /// Get the default Gatekeeper instance. This may fail on older devices where Gatekeeper is still a
82 /// HIDL interface rather than AIDL.
get_gatekeeper() -> Option<binder::Strong<dyn IGatekeeper>>83 fn get_gatekeeper() -> Option<binder::Strong<dyn IGatekeeper>> {
84     binder::get_interface("android.hardware.gatekeeper.IGatekeeper/default").ok()
85 }
86 
87 /// Indicate whether a Gatekeeper result indicates a delayed-retry is needed.
is_gk_retry<T: std::fmt::Debug>(result: &BinderResult<T>) -> bool88 fn is_gk_retry<T: std::fmt::Debug>(result: &BinderResult<T>) -> bool {
89     matches!(result, Err(s) if s.exception_code() == ExceptionCode::SERVICE_SPECIFIC
90                  && s.service_specific_error() == ERROR_RETRY_TIMEOUT)
91 }
92 
abort_op(result: binder::Result<CreateOperationResponse>)93 fn abort_op(result: binder::Result<CreateOperationResponse>) {
94     if let Ok(rsp) = result {
95         if let Some(op) = rsp.iOperation {
96             if let Err(e) = op.abort() {
97                 warn!("abort op failed: {e:?}");
98             }
99         } else {
100             warn!("can't abort op with missing iOperation");
101         }
102     } else {
103         warn!("can't abort failed op: {result:?}");
104     }
105 }
106 
107 /// RAII structure to ensure that test users are removed at the end of a test.
108 struct TestUser {
109     id: i32,
110     maint: binder::Strong<dyn IKeystoreMaintenance>,
111     gk: Option<binder::Strong<dyn IGatekeeper>>,
112     gk_sid: Option<i64>,
113     gk_handle: Vec<u8>,
114 }
115 
116 impl TestUser {
new() -> Self117     fn new() -> Self {
118         Self::new_user(TEST_USER_ID, SYNTHETIC_PASSWORD)
119     }
new_user(user_id: i32, sp: &[u8]) -> Self120     fn new_user(user_id: i32, sp: &[u8]) -> Self {
121         let maint = get_maintenance();
122         maint.onUserAdded(user_id).expect("failed to add test user");
123         maint
124             .initUserSuperKeys(user_id, sp, /* allowExisting= */ false)
125             .expect("failed to init test user");
126         let gk = get_gatekeeper();
127         let (gk_sid, gk_handle) = if let Some(gk) = &gk {
128             // AIDL Gatekeeper is available, so enroll a password.
129             loop {
130                 let result = gk.enroll(user_id, &[], &[], GK_PASSWORD);
131                 if is_gk_retry(&result) {
132                     sleep(Duration::from_secs(1));
133                     continue;
134                 }
135                 let rsp = result.expect("gk.enroll() failed");
136                 info!("registered test user {user_id} as sid {} with GK", rsp.secureUserId);
137                 break (Some(rsp.secureUserId), rsp.data);
138             }
139         } else {
140             (None, vec![])
141         };
142         Self { id: user_id, maint, gk, gk_sid, gk_handle }
143     }
144 
145     /// Perform Gatekeeper verification, which will return a HAT on success.
gk_verify(&self, challenge: i64) -> Option<HardwareAuthToken>146     fn gk_verify(&self, challenge: i64) -> Option<HardwareAuthToken> {
147         let Some(gk) = &self.gk else { return None };
148         loop {
149             let result = gk.verify(self.id, challenge, &self.gk_handle, GK_PASSWORD);
150             if is_gk_retry(&result) {
151                 sleep(Duration::from_secs(1));
152                 continue;
153             }
154             let rsp = result.expect("gk.verify failed");
155             break Some(rsp.hardwareAuthToken);
156         }
157     }
158 }
159 
160 impl Drop for TestUser {
drop(&mut self)161     fn drop(&mut self) {
162         let _ = self.maint.onUserRemoved(self.id);
163         if let Some(gk) = &self.gk {
164             info!("deregister test user {} with GK", self.id);
165             if let Err(e) = gk.deleteUser(self.id) {
166                 warn!("failed to deregister test user {}: {e:?}", self.id);
167             }
168         }
169     }
170 }
171 
172 #[test]
test_auth_bound_timeout_with_gk()173 fn test_auth_bound_timeout_with_gk() {
174     type Barrier = BarrierReachedWithData<Option<i64>>;
175     android_logger::init_once(
176         android_logger::Config::default()
177             .with_tag("keystore2_client_tests")
178             .with_max_level(log::LevelFilter::Debug),
179     );
180 
181     let child_fn = move |reader: &mut ChannelReader<Barrier>,
182                          writer: &mut ChannelWriter<Barrier>|
183           -> Result<(), run_as::Error> {
184         // Now we're in a new process, wait to be notified before starting.
185         let gk_sid: i64 = match reader.recv().0 {
186             Some(sid) => sid,
187             None => {
188                 // There is no AIDL Gatekeeper available, so abandon the test.  It would be nice to
189                 // know this before starting the child process, but finding it out requires Binder,
190                 // which can't be used until after the child has forked.
191                 return Ok(());
192             }
193         };
194 
195         // Action A: create a new auth-bound key which requires auth in the last 3 seconds,
196         // and fail to start an operation using it.
197         let ks2 = get_keystore_service();
198         let sec_level =
199             ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
200         let params = AuthSetBuilder::new()
201             .user_secure_id(gk_sid)
202             .user_secure_id(BIO_FAKE_SID1)
203             .user_secure_id(BIO_FAKE_SID2)
204             .user_auth_type(HardwareAuthenticatorType::ANY)
205             .auth_timeout(3)
206             .algorithm(Algorithm::EC)
207             .purpose(KeyPurpose::SIGN)
208             .purpose(KeyPurpose::VERIFY)
209             .digest(Digest::SHA_2_256)
210             .ec_curve(EcCurve::P_256);
211 
212         let KeyMetadata { key, .. } = sec_level
213             .generateKey(
214                 &KeyDescriptor {
215                     domain: Domain::APP,
216                     nspace: -1,
217                     alias: Some("auth-bound-timeout".to_string()),
218                     blob: None,
219                 },
220                 None,
221                 &params,
222                 0,
223                 b"entropy",
224             )
225             .context("key generation failed")?;
226         info!("A: created auth-timeout key {key:?}");
227 
228         // No HATs so cannot create an operation using the key.
229         let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
230         let result = sec_level.createOperation(&key, &params, UNFORCED);
231         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
232         info!("A: failed auth-bound operation (no HAT) as expected {result:?}");
233 
234         writer.send(&Barrier::new(None)); // A done.
235 
236         // Action B: succeed when a valid HAT is available.
237         reader.recv();
238 
239         let result = sec_level.createOperation(&key, &params, UNFORCED);
240         expect!(result.is_ok());
241         let op = result.unwrap().iOperation.context("no operation in result")?;
242         let result = op.finish(Some(b"data"), None);
243         expect!(result.is_ok());
244         info!("B: performed auth-bound operation (with valid GK HAT) as expected");
245 
246         writer.send(&Barrier::new(None)); // B done.
247 
248         // Action C: fail again when the HAT is old enough to not even be checked.
249         reader.recv();
250         info!("C: wait so that any HAT times out");
251         sleep(Duration::from_secs(4));
252         let result = sec_level.createOperation(&key, &params, UNFORCED);
253         info!("C: failed auth-bound operation (HAT is too old) as expected {result:?}");
254         writer.send(&Barrier::new(None)); // C done.
255 
256         Ok(())
257     };
258 
259     // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
260     // `--test-threads=1`), and nothing yet done with binder.
261     let mut child_handle = unsafe {
262         // Perform keystore actions while running as the test user.
263         run_as::run_as_child_app(UID, UID, child_fn)
264     }
265     .unwrap();
266 
267     // Now that the separate process has been forked off, it's safe to use binder to setup a test
268     // user.
269     let _ks2 = get_keystore_service();
270     let user = TestUser::new();
271     if user.gk.is_none() {
272         // Can't run this test if there's no AIDL Gatekeeper.
273         child_handle.send(&Barrier::new(None));
274         assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
275         return;
276     }
277     let user_id = user.id;
278     let auth_service = get_authorization();
279 
280     // Lock and unlock to ensure super keys are already created.
281     auth_service
282         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
283         .unwrap();
284     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
285 
286     info!("trigger child process action A and wait for completion");
287     child_handle.send(&Barrier::new(Some(user.gk_sid.unwrap())));
288     child_handle.recv_or_die();
289 
290     // Unlock with GK password to get a genuine auth token.
291     let real_hat = user.gk_verify(0).expect("failed to perform GK verify");
292     auth_service.addAuthToken(&real_hat).unwrap();
293 
294     info!("trigger child process action B and wait for completion");
295     child_handle.send(&Barrier::new(None));
296     child_handle.recv_or_die();
297 
298     info!("trigger child process action C and wait for completion");
299     child_handle.send(&Barrier::new(None));
300     child_handle.recv_or_die();
301 
302     assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
303 }
304 
305 #[test]
test_auth_bound_timeout_failure()306 fn test_auth_bound_timeout_failure() {
307     android_logger::init_once(
308         android_logger::Config::default()
309             .with_tag("keystore2_client_tests")
310             .with_max_level(log::LevelFilter::Debug),
311     );
312 
313     let child_fn = move |reader: &mut ChannelReader<BarrierReached>,
314                          writer: &mut ChannelWriter<BarrierReached>|
315           -> Result<(), run_as::Error> {
316         // Now we're in a new process, wait to be notified before starting.
317         reader.recv();
318 
319         // Action A: create a new auth-bound key which requires auth in the last 3 seconds,
320         // and fail to start an operation using it.
321         let ks2 = get_keystore_service();
322 
323         let sec_level =
324             ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
325         let params = AuthSetBuilder::new()
326             .user_secure_id(BIO_FAKE_SID1)
327             .user_secure_id(BIO_FAKE_SID2)
328             .user_auth_type(HardwareAuthenticatorType::ANY)
329             .auth_timeout(3)
330             .algorithm(Algorithm::EC)
331             .purpose(KeyPurpose::SIGN)
332             .purpose(KeyPurpose::VERIFY)
333             .digest(Digest::SHA_2_256)
334             .ec_curve(EcCurve::P_256);
335 
336         let KeyMetadata { key, .. } = sec_level
337             .generateKey(
338                 &KeyDescriptor {
339                     domain: Domain::APP,
340                     nspace: -1,
341                     alias: Some("auth-bound-timeout".to_string()),
342                     blob: None,
343                 },
344                 None,
345                 &params,
346                 0,
347                 b"entropy",
348             )
349             .context("key generation failed")?;
350         info!("A: created auth-timeout key {key:?}");
351 
352         // No HATs so cannot create an operation using the key.
353         let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
354         let result = sec_level.createOperation(&key, &params, UNFORCED);
355         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
356         info!("A: failed auth-bound operation (no HAT) as expected {result:?}");
357 
358         writer.send(&BarrierReached {}); // A done.
359 
360         // Action B: fail again when an invalid HAT is available.
361         reader.recv();
362 
363         let result = sec_level.createOperation(&key, &params, UNFORCED);
364         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
365         info!("B: failed auth-bound operation (HAT is invalid) as expected {result:?}");
366 
367         writer.send(&BarrierReached {}); // B done.
368 
369         // Action C: fail again when the HAT is old enough to not even be checked.
370         reader.recv();
371         info!("C: wait so that any HAT times out");
372         sleep(Duration::from_secs(4));
373         let result = sec_level.createOperation(&key, &params, UNFORCED);
374         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
375         info!("C: failed auth-bound operation (HAT is too old) as expected {result:?}");
376         writer.send(&BarrierReached {}); // C done.
377 
378         Ok(())
379     };
380 
381     // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
382     // `--test-threads=1`), and nothing yet done with binder.
383     let mut child_handle = unsafe {
384         // Perform keystore actions while running as the test user.
385         run_as::run_as_child_app(UID, UID, child_fn)
386     }
387     .unwrap();
388 
389     // Now that the separate process has been forked off, it's safe to use binder to setup a test
390     // user.
391     let _ks2 = get_keystore_service();
392     let user = TestUser::new();
393     let user_id = user.id;
394     let auth_service = get_authorization();
395 
396     // Lock and unlock to ensure super keys are already created.
397     auth_service
398         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
399         .unwrap();
400     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
401     auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
402 
403     info!("trigger child process action A and wait for completion");
404     child_handle.send(&BarrierReached {});
405     child_handle.recv_or_die();
406 
407     // Unlock with password and a fake auth token that matches the key
408     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
409     auth_service.addAuthToken(&fake_bio_lskf_token(GK_FAKE_SID, BIO_FAKE_SID1)).unwrap();
410 
411     info!("trigger child process action B and wait for completion");
412     child_handle.send(&BarrierReached {});
413     child_handle.recv_or_die();
414 
415     info!("trigger child process action C and wait for completion");
416     child_handle.send(&BarrierReached {});
417     child_handle.recv_or_die();
418 
419     assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
420 }
421 
422 #[test]
test_auth_bound_per_op_with_gk()423 fn test_auth_bound_per_op_with_gk() {
424     type Barrier = BarrierReachedWithData<Option<i64>>;
425     android_logger::init_once(
426         android_logger::Config::default()
427             .with_tag("keystore2_client_tests")
428             .with_max_level(log::LevelFilter::Debug),
429     );
430 
431     let child_fn = move |reader: &mut ChannelReader<Barrier>,
432                          writer: &mut ChannelWriter<Barrier>|
433           -> Result<(), run_as::Error> {
434         // Now we're in a new process, wait to be notified before starting.
435         let gk_sid: i64 = match reader.recv().0 {
436             Some(sid) => sid,
437             None => {
438                 // There is no AIDL Gatekeeper available, so abandon the test.  It would be nice to
439                 // know this before starting the child process, but finding it out requires Binder,
440                 // which can't be used until after the child has forked.
441                 return Ok(());
442             }
443         };
444 
445         // Action A: create a new auth-bound key which requires auth-per-operation (because
446         // AUTH_TIMEOUT is not specified), and fail to finish an operation using it.
447         let ks2 = get_keystore_service();
448         let sec_level =
449             ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
450         let params = AuthSetBuilder::new()
451             .user_secure_id(gk_sid)
452             .user_secure_id(BIO_FAKE_SID1)
453             .user_auth_type(HardwareAuthenticatorType::ANY)
454             .algorithm(Algorithm::EC)
455             .purpose(KeyPurpose::SIGN)
456             .purpose(KeyPurpose::VERIFY)
457             .digest(Digest::SHA_2_256)
458             .ec_curve(EcCurve::P_256);
459 
460         let KeyMetadata { key, .. } = sec_level
461             .generateKey(
462                 &KeyDescriptor {
463                     domain: Domain::APP,
464                     nspace: -1,
465                     alias: Some("auth-per-op".to_string()),
466                     blob: None,
467                 },
468                 None,
469                 &params,
470                 0,
471                 b"entropy",
472             )
473             .context("key generation failed")?;
474         info!("A: created auth-per-op key {key:?}");
475 
476         // We can create an operation using the key...
477         let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
478         let result = sec_level
479             .createOperation(&key, &params, UNFORCED)
480             .expect("failed to create auth-per-op operation");
481         let op = result.iOperation.context("no operation in result")?;
482         info!("A: created auth-per-op operation, got challenge {:?}", result.operationChallenge);
483 
484         // .. but attempting to finish the operation fails because Keystore can't find a HAT.
485         let result = op.finish(Some(b"data"), None);
486         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
487         info!("A: failed auth-per-op op (no HAT) as expected {result:?}");
488 
489         writer.send(&Barrier::new(None)); // A done.
490 
491         // Action B: start an operation and pass out the challenge
492         reader.recv();
493         let result = sec_level
494             .createOperation(&key, &params, UNFORCED)
495             .expect("failed to create auth-per-op operation");
496         let op = result.iOperation.context("no operation in result")?;
497         info!("B: created auth-per-op operation, got challenge {:?}", result.operationChallenge);
498         writer.send(&Barrier::new(Some(result.operationChallenge.unwrap().challenge))); // B done.
499 
500         // Action C: finishing the operation succeeds now there's a per-op HAT.
501         reader.recv();
502         let result = op.finish(Some(b"data"), None);
503         expect!(result.is_ok());
504         info!("C: performed auth-per-op op expected");
505         writer.send(&Barrier::new(None)); // D done.
506 
507         Ok(())
508     };
509 
510     // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
511     // `--test-threads=1`), and nothing yet done with binder.
512     let mut child_handle = unsafe {
513         // Perform keystore actions while running as the test user.
514         run_as::run_as_child_app(UID, UID, child_fn)
515     }
516     .unwrap();
517 
518     // Now that the separate process has been forked off, it's safe to use binder to setup a test
519     // user.
520     let _ks2 = get_keystore_service();
521     let user = TestUser::new();
522     if user.gk.is_none() {
523         // Can't run this test if there's no AIDL Gatekeeper.
524         child_handle.send(&Barrier::new(None));
525         assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
526         return;
527     }
528     let user_id = user.id;
529     let auth_service = get_authorization();
530 
531     // Lock and unlock to ensure super keys are already created.
532     auth_service
533         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
534         .unwrap();
535     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
536 
537     info!("trigger child process action A and wait for completion");
538     child_handle.send(&Barrier::new(Some(user.gk_sid.unwrap())));
539     child_handle.recv_or_die();
540 
541     info!("trigger child process action B and wait for completion");
542     child_handle.send(&Barrier::new(None));
543     let challenge = child_handle.recv_or_die().0.expect("no challenge");
544 
545     // Unlock with GK and the challenge to get a genuine per-op auth token
546     let real_hat = user.gk_verify(challenge).expect("failed to perform GK verify");
547     auth_service.addAuthToken(&real_hat).unwrap();
548 
549     info!("trigger child process action C and wait for completion");
550     child_handle.send(&Barrier::new(None));
551     child_handle.recv_or_die();
552 
553     assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
554 }
555 
556 #[test]
test_auth_bound_per_op_failure()557 fn test_auth_bound_per_op_failure() {
558     type Barrier = BarrierReachedWithData<i64>;
559     android_logger::init_once(
560         android_logger::Config::default()
561             .with_tag("keystore2_client_tests")
562             .with_max_level(log::LevelFilter::Debug),
563     );
564 
565     let child_fn = move |reader: &mut ChannelReader<Barrier>,
566                          writer: &mut ChannelWriter<Barrier>|
567           -> Result<(), run_as::Error> {
568         // Now we're in a new process, wait to be notified before starting.
569         reader.recv();
570 
571         // Action A: create a new auth-bound key which requires auth-per-operation (because
572         // AUTH_TIMEOUT is not specified), and fail to finish an operation using it.
573         let ks2 = get_keystore_service();
574 
575         let sec_level =
576             ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
577         let params = AuthSetBuilder::new()
578             .user_secure_id(GK_FAKE_SID)
579             .user_secure_id(BIO_FAKE_SID1)
580             .user_auth_type(HardwareAuthenticatorType::ANY)
581             .algorithm(Algorithm::EC)
582             .purpose(KeyPurpose::SIGN)
583             .purpose(KeyPurpose::VERIFY)
584             .digest(Digest::SHA_2_256)
585             .ec_curve(EcCurve::P_256);
586 
587         let KeyMetadata { key, .. } = sec_level
588             .generateKey(
589                 &KeyDescriptor {
590                     domain: Domain::APP,
591                     nspace: -1,
592                     alias: Some("auth-per-op".to_string()),
593                     blob: None,
594                 },
595                 None,
596                 &params,
597                 0,
598                 b"entropy",
599             )
600             .context("key generation failed")?;
601         info!("A: created auth-per-op key {key:?}");
602 
603         // We can create an operation using the key...
604         let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
605         let result = sec_level
606             .createOperation(&key, &params, UNFORCED)
607             .expect("failed to create auth-per-op operation");
608         let op = result.iOperation.context("no operation in result")?;
609         info!("A: created auth-per-op operation, got challenge {:?}", result.operationChallenge);
610 
611         // .. but attempting to finish the operation fails because Keystore can't find a HAT.
612         let result = op.finish(Some(b"data"), None);
613         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
614         info!("A: failed auth-per-op op (no HAT) as expected {result:?}");
615 
616         writer.send(&Barrier::new(0)); // A done.
617 
618         // Action B: fail again when an irrelevant HAT is available.
619         reader.recv();
620 
621         let result = sec_level
622             .createOperation(&key, &params, UNFORCED)
623             .expect("failed to create auth-per-op operation");
624         let op = result.iOperation.context("no operation in result")?;
625         info!("B: created auth-per-op operation, got challenge {:?}", result.operationChallenge);
626         // The operation fails because the HAT that Keystore received is not related to the
627         // challenge.
628         let result = op.finish(Some(b"data"), None);
629         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
630         info!("B: failed auth-per-op op (HAT is not per-op) as expected {result:?}");
631 
632         writer.send(&Barrier::new(0)); // B done.
633 
634         // Action C: start an operation and pass out the challenge
635         reader.recv();
636         let result = sec_level
637             .createOperation(&key, &params, UNFORCED)
638             .expect("failed to create auth-per-op operation");
639         let op = result.iOperation.context("no operation in result")?;
640         info!("C: created auth-per-op operation, got challenge {:?}", result.operationChallenge);
641         writer.send(&Barrier::new(result.operationChallenge.unwrap().challenge)); // C done.
642 
643         // Action D: finishing the operation still fails because the per-op HAT
644         // is invalid (the HMAC signature is faked and so the secure world
645         // rejects the HAT).
646         reader.recv();
647         let result = op.finish(Some(b"data"), None);
648         expect_km_error!(&result, ErrorCode::KEY_USER_NOT_AUTHENTICATED);
649         info!("D: failed auth-per-op op (HAT is per-op but invalid) as expected {result:?}");
650         writer.send(&Barrier::new(0)); // D done.
651 
652         Ok(())
653     };
654 
655     // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
656     // `--test-threads=1`), and nothing yet done with binder.
657     let mut child_handle = unsafe {
658         // Perform keystore actions while running as the test user.
659         run_as::run_as_child_app(UID, UID, child_fn)
660     }
661     .unwrap();
662 
663     // Now that the separate process has been forked off, it's safe to use binder to setup a test
664     // user.
665     let _ks2 = get_keystore_service();
666     let user = TestUser::new();
667     let user_id = user.id;
668     let auth_service = get_authorization();
669 
670     // Lock and unlock to ensure super keys are already created.
671     auth_service
672         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
673         .unwrap();
674     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
675     auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
676 
677     info!("trigger child process action A and wait for completion");
678     child_handle.send(&Barrier::new(0));
679     child_handle.recv_or_die();
680 
681     // Unlock with password and a fake auth token.
682     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
683     auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
684 
685     info!("trigger child process action B and wait for completion");
686     child_handle.send(&Barrier::new(0));
687     child_handle.recv_or_die();
688 
689     info!("trigger child process action C and wait for completion");
690     child_handle.send(&Barrier::new(0));
691     let challenge = child_handle.recv_or_die().0;
692 
693     // Add a fake auth token with the challenge value.
694     auth_service.addAuthToken(&fake_lskf_token_with_challenge(GK_FAKE_SID, challenge)).unwrap();
695 
696     info!("trigger child process action D and wait for completion");
697     child_handle.send(&Barrier::new(0));
698     child_handle.recv_or_die();
699 
700     assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
701 }
702 
703 #[test]
test_unlocked_device_required()704 fn test_unlocked_device_required() {
705     android_logger::init_once(
706         android_logger::Config::default()
707             .with_tag("keystore2_client_tests")
708             .with_max_level(log::LevelFilter::Debug),
709     );
710 
711     let child_fn = move |reader: &mut ChannelReader<BarrierReached>,
712                          writer: &mut ChannelWriter<BarrierReached>|
713           -> Result<(), run_as::Error> {
714         let ks2 = get_keystore_service();
715         if ks2.getInterfaceVersion().unwrap() < 4 {
716             // Assuming `IKeystoreAuthorization::onDeviceLocked` and
717             // `IKeystoreAuthorization::onDeviceUnlocked` APIs will be supported on devices
718             // with `IKeystoreService` >= 4.
719             return Ok(());
720         }
721 
722         // Now we're in a new process, wait to be notified before starting.
723         reader.recv();
724 
725         // Action A: create a new unlocked-device-required key (which thus requires
726         // super-encryption), while the device is unlocked.
727         let sec_level =
728             ks2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).context("no TEE")?;
729         let params = AuthSetBuilder::new()
730             .no_auth_required()
731             .unlocked_device_required()
732             .algorithm(Algorithm::EC)
733             .purpose(KeyPurpose::SIGN)
734             .purpose(KeyPurpose::VERIFY)
735             .digest(Digest::SHA_2_256)
736             .ec_curve(EcCurve::P_256);
737 
738         let KeyMetadata { key, .. } = sec_level
739             .generateKey(
740                 &KeyDescriptor {
741                     domain: Domain::APP,
742                     nspace: -1,
743                     alias: Some("unlocked-device-required".to_string()),
744                     blob: None,
745                 },
746                 None,
747                 &params,
748                 0,
749                 b"entropy",
750             )
751             .context("key generation failed")?;
752         info!("A: created unlocked-device-required key while unlocked {key:?}");
753         writer.send(&BarrierReached {}); // A done.
754 
755         // Action B: fail to use the unlocked-device-required key while locked.
756         reader.recv();
757         let params = AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256);
758         let result = sec_level.createOperation(&key, &params, UNFORCED);
759         info!("B: use unlocked-device-required key while locked => {result:?}");
760         expect_km_error!(&result, ErrorCode::DEVICE_LOCKED);
761         writer.send(&BarrierReached {}); // B done.
762 
763         // Action C: try to use the unlocked-device-required key while unlocked with a
764         // password.
765         reader.recv();
766         let result = sec_level.createOperation(&key, &params, UNFORCED);
767         info!("C: use unlocked-device-required key while lskf-unlocked => {result:?}");
768         expect!(result.is_ok(), "failed with {result:?}");
769         abort_op(result);
770         writer.send(&BarrierReached {}); // C done.
771 
772         // Action D: try to use the unlocked-device-required key while unlocked with a weak
773         // biometric.
774         reader.recv();
775         let result = sec_level.createOperation(&key, &params, UNFORCED);
776         info!("D: use unlocked-device-required key while weak-locked => {result:?}");
777         expect!(result.is_ok(), "createOperation failed: {result:?}");
778         abort_op(result);
779         writer.send(&BarrierReached {}); // D done.
780 
781         Ok(())
782     };
783 
784     // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
785     // `--test-threads=1`), and nothing yet done with binder.
786     let mut child_handle = unsafe {
787         // Perform keystore actions while running as the test user.
788         run_as::run_as_child_app(UID, UID, child_fn)
789     }
790     .unwrap();
791 
792     let ks2 = get_keystore_service();
793     if ks2.getInterfaceVersion().unwrap() < 4 {
794         // Assuming `IKeystoreAuthorization::onDeviceLocked` and
795         // `IKeystoreAuthorization::onDeviceUnlocked` APIs will be supported on devices
796         // with `IKeystoreService` >= 4.
797         assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
798         return;
799     }
800     // Now that the separate process has been forked off, it's safe to use binder.
801     let user = TestUser::new();
802     let user_id = user.id;
803     let auth_service = get_authorization();
804 
805     // Lock and unlock to ensure super keys are already created.
806     auth_service
807         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
808         .unwrap();
809     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
810     auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
811 
812     info!("trigger child process action A while unlocked and wait for completion");
813     child_handle.send(&BarrierReached {});
814     child_handle.recv_or_die();
815 
816     // Move to locked and don't allow weak unlock, so super keys are wiped.
817     auth_service
818         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_DISABLED)
819         .unwrap();
820 
821     info!("trigger child process action B while locked and wait for completion");
822     child_handle.send(&BarrierReached {});
823     child_handle.recv_or_die();
824 
825     // Unlock with password => loads super key from database.
826     auth_service.onDeviceUnlocked(user_id, Some(SYNTHETIC_PASSWORD)).unwrap();
827     auth_service.addAuthToken(&fake_lskf_token(GK_FAKE_SID)).unwrap();
828 
829     info!("trigger child process action C while lskf-unlocked and wait for completion");
830     child_handle.send(&BarrierReached {});
831     child_handle.recv_or_die();
832 
833     // Move to locked and allow weak unlock, then do a weak unlock.
834     auth_service
835         .onDeviceLocked(user_id, &[BIO_FAKE_SID1, BIO_FAKE_SID2], WEAK_UNLOCK_ENABLED)
836         .unwrap();
837     auth_service.onDeviceUnlocked(user_id, None).unwrap();
838 
839     info!("trigger child process action D while weak-unlocked and wait for completion");
840     child_handle.send(&BarrierReached {});
841     child_handle.recv_or_die();
842 
843     assert_eq!(child_handle.get_result(), Ok(()), "child process failed");
844 }
845 
846 /// Generate a fake [`HardwareAuthToken`] for the given sid.
fake_lskf_token(gk_sid: i64) -> HardwareAuthToken847 fn fake_lskf_token(gk_sid: i64) -> HardwareAuthToken {
848     fake_lskf_token_with_challenge(gk_sid, 0)
849 }
850 
851 /// Generate a fake [`HardwareAuthToken`] for the given sid and challenge.
fake_lskf_token_with_challenge(gk_sid: i64, challenge: i64) -> HardwareAuthToken852 fn fake_lskf_token_with_challenge(gk_sid: i64, challenge: i64) -> HardwareAuthToken {
853     HardwareAuthToken {
854         challenge,
855         userId: gk_sid,
856         authenticatorId: 0,
857         authenticatorType: HardwareAuthenticatorType::PASSWORD,
858         timestamp: Timestamp { milliSeconds: 123 },
859         mac: vec![1, 2, 3],
860     }
861 }
862 
863 /// Generate a fake [`HardwareAuthToken`] for the given sids
fake_bio_lskf_token(gk_sid: i64, bio_sid: i64) -> HardwareAuthToken864 fn fake_bio_lskf_token(gk_sid: i64, bio_sid: i64) -> HardwareAuthToken {
865     HardwareAuthToken {
866         challenge: 0,
867         userId: gk_sid,
868         authenticatorId: bio_sid,
869         authenticatorType: HardwareAuthenticatorType::PASSWORD,
870         timestamp: Timestamp { milliSeconds: 123 },
871         mac: vec![1, 2, 3],
872     }
873 }
874