blob: fd0468f758b19dbf973882ecff7edec6fc7e23a3 [file] [log] [blame]
David Drysdale2566fb32024-07-09 14:46:37 +01001// 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
17use super::*;
18use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
19use std::sync::atomic::{AtomicU32, Ordering};
20use std::sync::{Arc, Mutex};
21
22const DEFAULT_RPC_SERVICE_NAME: &str =
23 "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
24
25struct MockRegistrationValues {
26 key: RemotelyProvisionedKey,
27 latency: Option<Duration>,
28 thread_join_handles: Vec<Option<std::thread::JoinHandle<()>>>,
29}
30
31struct MockRegistration(Arc<Mutex<MockRegistrationValues>>);
32
33impl MockRegistration {
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
50impl Drop for MockRegistration {
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
60impl Interface for MockRegistration {}
61
62impl IRegistration for MockRegistration {
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
83 fn cancelGetKey(&self, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
84 Ok(())
85 }
86
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
109fn 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.
123fn get_next_key_id() -> u32 {
124 static ID: AtomicU32 = AtomicU32::new(0);
125 ID.fetch_add(1, Ordering::Relaxed)
126}
127
128#[test]
129fn 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]
136fn 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]
146fn 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]
156fn 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]
168fn 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]
178fn 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]
193fn 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]
202fn 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]
212fn 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]
224fn 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]
236fn 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]
246fn 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]
261fn 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]
270fn 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]
283fn 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.
302fn 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]
318fn 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}