xref: /aosp_15_r20/system/security/keystore2/rkpd_client/src/tests.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1 // Copyright 2022, 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 //! RKPD tests.
16 
17 use super::*;
18 use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
19 use std::sync::atomic::{AtomicU32, Ordering};
20 use std::sync::{Arc, Mutex};
21 
22 const DEFAULT_RPC_SERVICE_NAME: &str =
23     "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
24 
25 struct MockRegistrationValues {
26     key: RemotelyProvisionedKey,
27     latency: Option<Duration>,
28     thread_join_handles: Vec<Option<std::thread::JoinHandle<()>>>,
29 }
30 
31 struct MockRegistration(Arc<Mutex<MockRegistrationValues>>);
32 
33 impl MockRegistration {
new_native_binder( key: &RemotelyProvisionedKey, latency: Option<Duration>, ) -> Strong<dyn IRegistration>34     pub fn new_native_binder(
35         key: &RemotelyProvisionedKey,
36         latency: Option<Duration>,
37     ) -> Strong<dyn IRegistration> {
38         let result = Self(Arc::new(Mutex::new(MockRegistrationValues {
39             key: RemotelyProvisionedKey {
40                 keyBlob: key.keyBlob.clone(),
41                 encodedCertChain: key.encodedCertChain.clone(),
42             },
43             latency,
44             thread_join_handles: Vec::new(),
45         })));
46         BnRegistration::new_binder(result, BinderFeatures::default())
47     }
48 }
49 
50 impl Drop for MockRegistration {
drop(&mut self)51     fn drop(&mut self) {
52         let mut values = self.0.lock().unwrap();
53         for handle in values.thread_join_handles.iter_mut() {
54             // These are test threads. So, no need to worry too much about error handling.
55             handle.take().unwrap().join().unwrap();
56         }
57     }
58 }
59 
60 impl Interface for MockRegistration {}
61 
62 impl IRegistration for MockRegistration {
getKey(&self, _: i32, cb: &Strong<dyn IGetKeyCallback>) -> binder::Result<()>63     fn getKey(&self, _: i32, cb: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
64         let mut values = self.0.lock().unwrap();
65         let key = RemotelyProvisionedKey {
66             keyBlob: values.key.keyBlob.clone(),
67             encodedCertChain: values.key.encodedCertChain.clone(),
68         };
69         let latency = values.latency;
70         let get_key_cb = cb.clone();
71 
72         // Need a separate thread to trigger timeout in the caller.
73         let join_handle = std::thread::spawn(move || {
74             if let Some(duration) = latency {
75                 std::thread::sleep(duration);
76             }
77             get_key_cb.onSuccess(&key).unwrap();
78         });
79         values.thread_join_handles.push(Some(join_handle));
80         Ok(())
81     }
82 
cancelGetKey(&self, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()>83     fn cancelGetKey(&self, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
84         Ok(())
85     }
86 
storeUpgradedKeyAsync( &self, _: &[u8], _: &[u8], cb: &Strong<dyn IStoreUpgradedKeyCallback>, ) -> binder::Result<()>87     fn storeUpgradedKeyAsync(
88         &self,
89         _: &[u8],
90         _: &[u8],
91         cb: &Strong<dyn IStoreUpgradedKeyCallback>,
92     ) -> binder::Result<()> {
93         // We are primarily concerned with timing out correctly. Storing the key in this mock
94         // registration isn't particularly interesting, so skip that part.
95         let values = self.0.lock().unwrap();
96         let store_cb = cb.clone();
97         let latency = values.latency;
98 
99         std::thread::spawn(move || {
100             if let Some(duration) = latency {
101                 std::thread::sleep(duration);
102             }
103             store_cb.onSuccess().unwrap();
104         });
105         Ok(())
106     }
107 }
108 
get_mock_registration( key: &RemotelyProvisionedKey, latency: Option<Duration>, ) -> Result<binder::Strong<dyn IRegistration>>109 fn get_mock_registration(
110     key: &RemotelyProvisionedKey,
111     latency: Option<Duration>,
112 ) -> Result<binder::Strong<dyn IRegistration>> {
113     let (tx, rx) = oneshot::channel();
114     let cb = GetRegistrationCallback::new_native_binder(tx);
115     let mock_registration = MockRegistration::new_native_binder(key, latency);
116 
117     assert!(cb.onSuccess(&mock_registration).is_ok());
118     tokio_rt().block_on(rx).unwrap()
119 }
120 
121 // Using the same key ID makes test cases race with each other. So, we use separate key IDs for
122 // different test cases.
get_next_key_id() -> u32123 fn get_next_key_id() -> u32 {
124     static ID: AtomicU32 = AtomicU32::new(0);
125     ID.fetch_add(1, Ordering::Relaxed)
126 }
127 
128 #[test]
test_get_registration_cb_success()129 fn test_get_registration_cb_success() {
130     let key: RemotelyProvisionedKey = Default::default();
131     let registration = get_mock_registration(&key, /*latency=*/ None);
132     assert!(registration.is_ok());
133 }
134 
135 #[test]
test_get_registration_cb_cancel()136 fn test_get_registration_cb_cancel() {
137     let (tx, rx) = oneshot::channel();
138     let cb = GetRegistrationCallback::new_native_binder(tx);
139     assert!(cb.onCancel().is_ok());
140 
141     let result = tokio_rt().block_on(rx).unwrap();
142     assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::RequestCancelled);
143 }
144 
145 #[test]
test_get_registration_cb_error()146 fn test_get_registration_cb_error() {
147     let (tx, rx) = oneshot::channel();
148     let cb = GetRegistrationCallback::new_native_binder(tx);
149     assert!(cb.onError("error").is_ok());
150 
151     let result = tokio_rt().block_on(rx).unwrap();
152     assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::GetRegistrationFailed);
153 }
154 
155 #[test]
test_get_key_cb_success()156 fn test_get_key_cb_success() {
157     let mock_key =
158         RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
159     let (tx, rx) = oneshot::channel();
160     let cb = GetKeyCallback::new_native_binder(tx);
161     assert!(cb.onSuccess(&mock_key).is_ok());
162 
163     let key = tokio_rt().block_on(rx).unwrap().unwrap();
164     assert_eq!(key, mock_key);
165 }
166 
167 #[test]
test_get_key_cb_cancel()168 fn test_get_key_cb_cancel() {
169     let (tx, rx) = oneshot::channel();
170     let cb = GetKeyCallback::new_native_binder(tx);
171     assert!(cb.onCancel().is_ok());
172 
173     let result = tokio_rt().block_on(rx).unwrap();
174     assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::RequestCancelled);
175 }
176 
177 #[test]
test_get_key_cb_error()178 fn test_get_key_cb_error() {
179     for get_key_error in GetKeyErrorCode::enum_values() {
180         let (tx, rx) = oneshot::channel();
181         let cb = GetKeyCallback::new_native_binder(tx);
182         assert!(cb.onError(get_key_error, "error").is_ok());
183 
184         let result = tokio_rt().block_on(rx).unwrap();
185         assert_eq!(
186             result.unwrap_err().downcast::<Error>().unwrap(),
187             Error::GetKeyFailed(get_key_error),
188         );
189     }
190 }
191 
192 #[test]
test_store_upgraded_cb_success()193 fn test_store_upgraded_cb_success() {
194     let (tx, rx) = oneshot::channel();
195     let cb = StoreUpgradedKeyCallback::new_native_binder(tx);
196     assert!(cb.onSuccess().is_ok());
197 
198     tokio_rt().block_on(rx).unwrap().unwrap();
199 }
200 
201 #[test]
test_store_upgraded_key_cb_error()202 fn test_store_upgraded_key_cb_error() {
203     let (tx, rx) = oneshot::channel();
204     let cb = StoreUpgradedKeyCallback::new_native_binder(tx);
205     assert!(cb.onError("oh no! it failed").is_ok());
206 
207     let result = tokio_rt().block_on(rx).unwrap();
208     assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::StoreUpgradedKeyFailed);
209 }
210 
211 #[test]
test_get_mock_key_success()212 fn test_get_mock_key_success() {
213     let mock_key =
214         RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
215     let registration = get_mock_registration(&mock_key, /*latency=*/ None).unwrap();
216 
217     let key = tokio_rt()
218         .block_on(get_rkpd_attestation_key_from_registration_async(&registration, 0))
219         .unwrap();
220     assert_eq!(key, mock_key);
221 }
222 
223 #[test]
test_get_mock_key_timeout()224 fn test_get_mock_key_timeout() {
225     let mock_key =
226         RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
227     let latency = RKPD_TIMEOUT + Duration::from_secs(1);
228     let registration = get_mock_registration(&mock_key, Some(latency)).unwrap();
229 
230     let result =
231         tokio_rt().block_on(get_rkpd_attestation_key_from_registration_async(&registration, 0));
232     assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::RetryableTimeout);
233 }
234 
235 #[test]
test_store_mock_key_success()236 fn test_store_mock_key_success() {
237     let mock_key =
238         RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
239     let registration = get_mock_registration(&mock_key, /*latency=*/ None).unwrap();
240     tokio_rt()
241         .block_on(store_rkpd_attestation_key_with_registration_async(&registration, &[], &[]))
242         .unwrap();
243 }
244 
245 #[test]
test_store_mock_key_timeout()246 fn test_store_mock_key_timeout() {
247     let mock_key =
248         RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
249     let latency = RKPD_TIMEOUT + Duration::from_secs(1);
250     let registration = get_mock_registration(&mock_key, Some(latency)).unwrap();
251 
252     let result = tokio_rt().block_on(store_rkpd_attestation_key_with_registration_async(
253         &registration,
254         &[],
255         &[],
256     ));
257     assert_eq!(result.unwrap_err().downcast::<Error>().unwrap(), Error::Timeout);
258 }
259 
260 #[test]
test_get_rkpd_attestation_key()261 fn test_get_rkpd_attestation_key() {
262     binder::ProcessState::start_thread_pool();
263     let key_id = get_next_key_id();
264     let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
265     assert!(!key.keyBlob.is_empty());
266     assert!(!key.encodedCertChain.is_empty());
267 }
268 
269 #[test]
test_get_rkpd_attestation_key_same_caller()270 fn test_get_rkpd_attestation_key_same_caller() {
271     binder::ProcessState::start_thread_pool();
272     let key_id = get_next_key_id();
273 
274     // Multiple calls should return the same key.
275     let first_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
276     let second_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
277 
278     assert_eq!(first_key.keyBlob, second_key.keyBlob);
279     assert_eq!(first_key.encodedCertChain, second_key.encodedCertChain);
280 }
281 
282 #[test]
test_get_rkpd_attestation_key_different_caller()283 fn test_get_rkpd_attestation_key_different_caller() {
284     binder::ProcessState::start_thread_pool();
285     let first_key_id = get_next_key_id();
286     let second_key_id = get_next_key_id();
287 
288     // Different callers should be getting different keys.
289     let first_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, first_key_id).unwrap();
290     let second_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, second_key_id).unwrap();
291 
292     assert_ne!(first_key.keyBlob, second_key.keyBlob);
293     assert_ne!(first_key.encodedCertChain, second_key.encodedCertChain);
294 }
295 
296 #[test]
297 // Couple of things to note:
298 // 1. This test must never run with UID of keystore. Otherwise, it can mess up keys stored by
299 //    keystore.
300 // 2. Storing and reading the stored key is prone to race condition. So, we only do this in one
301 //    test case.
test_store_rkpd_attestation_key()302 fn test_store_rkpd_attestation_key() {
303     binder::ProcessState::start_thread_pool();
304     let key_id = get_next_key_id();
305     let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
306     let new_blob: [u8; 8] = rand::random();
307 
308     assert!(store_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, &key.keyBlob, &new_blob).is_ok());
309 
310     let new_key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
311 
312     // Restore original key so that we don't leave RKPD with invalid blobs.
313     assert!(store_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, &new_blob, &key.keyBlob).is_ok());
314     assert_eq!(new_key.keyBlob, new_blob);
315 }
316 
317 #[test]
test_stress_get_rkpd_attestation_key()318 fn test_stress_get_rkpd_attestation_key() {
319     binder::ProcessState::start_thread_pool();
320     let key_id = get_next_key_id();
321     let mut threads = vec![];
322     const NTHREADS: u32 = 10;
323     const NCALLS: u32 = 1000;
324 
325     for _ in 0..NTHREADS {
326         threads.push(std::thread::spawn(move || {
327             for _ in 0..NCALLS {
328                 let key = get_rkpd_attestation_key(DEFAULT_RPC_SERVICE_NAME, key_id).unwrap();
329                 assert!(!key.keyBlob.is_empty());
330                 assert!(!key.encodedCertChain.is_empty());
331             }
332         }));
333     }
334 
335     for t in threads {
336         assert!(t.join().is_ok());
337     }
338 }
339