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