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 use crate::keystore2_client_test_utils::{
16 delete_app_key, execute_op_run_as_child, get_vsr_api_level, perform_sample_sign_operation,
17 BarrierReached, ForcedOp, TestOutcome,
18 };
19 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
20 Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
21 KeyPurpose::KeyPurpose,
22 };
23 use android_system_keystore2::aidl::android::system::keystore2::{
24 CreateOperationResponse::CreateOperationResponse, Domain::Domain, KeyDescriptor::KeyDescriptor,
25 ResponseCode::ResponseCode,
26 };
27 use keystore2_test_utils::{
28 authorizations, get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
29 };
30 use nix::unistd::{getuid, Gid, Uid};
31 use rustutils::users::AID_USER_OFFSET;
32
33 macro_rules! test_ec_sign_key_op_success {
34 ( $test_name:ident, $digest:expr, $ec_curve:expr ) => {
35 #[test]
36 fn $test_name() {
37 perform_ec_sign_key_op_success(stringify!($test_name), $digest, $ec_curve);
38 }
39 };
40 }
41
42 macro_rules! test_ec_sign_key_op_with_none_or_md5_digest {
43 ( $test_name:ident, $digest:expr, $ec_curve:expr ) => {
44 #[test]
45 fn $test_name() {
46 perform_ec_sign_key_op_with_none_or_md5_digest(
47 stringify!($test_name),
48 $digest,
49 $ec_curve,
50 );
51 }
52 };
53 }
54
create_ec_key_and_operation( sl: &SecLevel, domain: Domain, nspace: i64, alias: Option<String>, digest: Digest, ec_curve: EcCurve, ) -> binder::Result<CreateOperationResponse>55 fn create_ec_key_and_operation(
56 sl: &SecLevel,
57 domain: Domain,
58 nspace: i64,
59 alias: Option<String>,
60 digest: Digest,
61 ec_curve: EcCurve,
62 ) -> binder::Result<CreateOperationResponse> {
63 let key_metadata =
64 key_generations::generate_ec_key(sl, domain, nspace, alias, ec_curve, digest)?;
65
66 sl.binder.createOperation(
67 &key_metadata.key,
68 &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
69 false,
70 )
71 }
72
perform_ec_sign_key_op_success(alias: &str, digest: Digest, ec_curve: EcCurve)73 fn perform_ec_sign_key_op_success(alias: &str, digest: Digest, ec_curve: EcCurve) {
74 let sl = SecLevel::tee();
75
76 let op_response = create_ec_key_and_operation(
77 &sl,
78 Domain::APP,
79 -1,
80 Some(alias.to_string()),
81 digest,
82 ec_curve,
83 )
84 .unwrap();
85
86 assert!(op_response.iOperation.is_some());
87 assert_eq!(
88 Ok(()),
89 key_generations::map_ks_error(perform_sample_sign_operation(
90 &op_response.iOperation.unwrap()
91 ))
92 );
93
94 delete_app_key(&sl.keystore2, alias).unwrap();
95 }
96
perform_ec_sign_key_op_with_none_or_md5_digest(alias: &str, digest: Digest, ec_curve: EcCurve)97 fn perform_ec_sign_key_op_with_none_or_md5_digest(alias: &str, digest: Digest, ec_curve: EcCurve) {
98 let sl = SecLevel::tee();
99
100 match key_generations::map_ks_error(create_ec_key_and_operation(
101 &sl,
102 Domain::APP,
103 -1,
104 Some(alias.to_string()),
105 digest,
106 ec_curve,
107 )) {
108 Ok(op_response) => {
109 assert!(op_response.iOperation.is_some());
110 assert_eq!(
111 Ok(()),
112 key_generations::map_ks_error(perform_sample_sign_operation(
113 &op_response.iOperation.unwrap()
114 ))
115 );
116 }
117 Err(e) => {
118 assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_DIGEST));
119 assert!(digest == Digest::NONE || digest == Digest::MD5);
120 }
121 }
122
123 delete_app_key(&sl.keystore2, alias).unwrap();
124 }
125
126 // Below macros generate tests for generating EC keys with curves EcCurve::P_224, EcCurve::P_256,
127 // EcCurve::P_384, EcCurve::P_521 and various digest modes. Tests tries to create operations using
128 // the generated keys. Operations with digest modes `SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and
129 // SHA-2 512` should be created successfully. Creation of operations with digest modes NONE and
130 // MD5 should fail with an error code `UNSUPPORTED_DIGEST`.
131 test_ec_sign_key_op_with_none_or_md5_digest!(
132 sign_ec_key_op_none_ec_p224,
133 Digest::NONE,
134 EcCurve::P_224
135 );
136 test_ec_sign_key_op_with_none_or_md5_digest!(
137 sign_ec_key_op_md5_ec_p224,
138 Digest::MD5,
139 EcCurve::P_224
140 );
141 test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p224, Digest::SHA1, EcCurve::P_224);
142 test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p224, Digest::SHA_2_224, EcCurve::P_224);
143 test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p224, Digest::SHA_2_256, EcCurve::P_224);
144 test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p224, Digest::SHA_2_384, EcCurve::P_224);
145 test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p224, Digest::SHA_2_512, EcCurve::P_224);
146 test_ec_sign_key_op_with_none_or_md5_digest!(
147 sign_ec_key_op_none_ec_p256,
148 Digest::NONE,
149 EcCurve::P_256
150 );
151 test_ec_sign_key_op_with_none_or_md5_digest!(
152 sign_ec_key_op_md5_ec_p256,
153 Digest::MD5,
154 EcCurve::P_256
155 );
156 test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p256, Digest::SHA1, EcCurve::P_256);
157 test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p256, Digest::SHA_2_224, EcCurve::P_256);
158 test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p256, Digest::SHA_2_256, EcCurve::P_256);
159 test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p256, Digest::SHA_2_384, EcCurve::P_256);
160 test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p256, Digest::SHA_2_512, EcCurve::P_256);
161 test_ec_sign_key_op_with_none_or_md5_digest!(
162 sign_ec_key_op_none_ec_p384,
163 Digest::NONE,
164 EcCurve::P_384
165 );
166 test_ec_sign_key_op_with_none_or_md5_digest!(
167 sign_ec_key_op_md5_ec_p384,
168 Digest::MD5,
169 EcCurve::P_384
170 );
171 test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p384, Digest::SHA1, EcCurve::P_384);
172 test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p384, Digest::SHA_2_224, EcCurve::P_384);
173 test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p384, Digest::SHA_2_256, EcCurve::P_384);
174 test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p384, Digest::SHA_2_384, EcCurve::P_384);
175 test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p384, Digest::SHA_2_512, EcCurve::P_384);
176 test_ec_sign_key_op_with_none_or_md5_digest!(
177 sign_ec_key_op_none_ec_p521,
178 Digest::NONE,
179 EcCurve::P_521
180 );
181 test_ec_sign_key_op_with_none_or_md5_digest!(
182 sign_ec_key_op_md5_ec_p521,
183 Digest::MD5,
184 EcCurve::P_521
185 );
186 test_ec_sign_key_op_success!(sign_ec_key_op_sha1_ec_p521, Digest::SHA1, EcCurve::P_521);
187 test_ec_sign_key_op_success!(sign_ec_key_op_sha224_ec_p521, Digest::SHA_2_224, EcCurve::P_521);
188 test_ec_sign_key_op_success!(sign_ec_key_op_sha256_ec_p521, Digest::SHA_2_256, EcCurve::P_521);
189 test_ec_sign_key_op_success!(sign_ec_key_op_sha384_ec_p521, Digest::SHA_2_384, EcCurve::P_521);
190 test_ec_sign_key_op_success!(sign_ec_key_op_sha512_ec_p521, Digest::SHA_2_512, EcCurve::P_521);
191
192 /// This test will try to load the key with Domain::BLOB.
193 /// INVALID_ARGUMENT error is expected.
194 #[test]
keystore2_get_key_entry_blob_fail()195 fn keystore2_get_key_entry_blob_fail() {
196 let sl = SecLevel::tee();
197
198 // Generate a key with domain as BLOB.
199 let key_metadata = key_generations::generate_ec_p256_signing_key(
200 &sl,
201 Domain::BLOB,
202 key_generations::SELINUX_SHELL_NAMESPACE,
203 None,
204 None,
205 )
206 .unwrap();
207
208 // Try to load the key using above generated KeyDescriptor.
209 let result = key_generations::map_ks_error(sl.keystore2.getKeyEntry(&key_metadata.key));
210 assert!(result.is_err());
211 assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
212
213 // Delete the generated key blob.
214 sl.delete_key(&key_metadata.key).unwrap();
215 }
216
217 /// Try to generate a key with invalid Domain. `INVALID_ARGUMENT` error response is expected.
218 #[test]
keystore2_generate_key_invalid_domain()219 fn keystore2_generate_key_invalid_domain() {
220 let sl = SecLevel::tee();
221 let alias = format!("ks_invalid_test_key_{}", getuid());
222
223 let result = key_generations::map_ks_error(key_generations::generate_ec_key(
224 &sl,
225 Domain(99), // Invalid domain.
226 key_generations::SELINUX_SHELL_NAMESPACE,
227 Some(alias),
228 EcCurve::P_256,
229 Digest::SHA_2_256,
230 ));
231 assert!(result.is_err());
232 assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
233 }
234
235 /// Try to generate a EC key without providing the curve.
236 /// `UNSUPPORTED_EC_CURVE or UNSUPPORTED_KEY_SIZE` error response is expected.
237 #[test]
keystore2_generate_ec_key_missing_curve()238 fn keystore2_generate_ec_key_missing_curve() {
239 let sl = SecLevel::tee();
240 let alias = format!("ks_ec_no_curve_test_key_{}", getuid());
241
242 // Don't provide EC curve.
243 let gen_params = authorizations::AuthSetBuilder::new()
244 .no_auth_required()
245 .algorithm(Algorithm::EC)
246 .purpose(KeyPurpose::SIGN)
247 .purpose(KeyPurpose::VERIFY)
248 .digest(Digest::SHA_2_256);
249
250 let result = key_generations::map_ks_error(sl.binder.generateKey(
251 &KeyDescriptor {
252 domain: Domain::SELINUX,
253 nspace: key_generations::SELINUX_SHELL_NAMESPACE,
254 alias: Some(alias),
255 blob: None,
256 },
257 None,
258 &gen_params,
259 0,
260 b"entropy",
261 ));
262 assert!(result.is_err());
263 let err = result.unwrap_err();
264 assert!(matches!(
265 err,
266 Error::Km(ErrorCode::UNSUPPORTED_EC_CURVE) | Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE)
267 ));
268 }
269
270 /// Try to generate a EC key with curve `CURVE_25519` having `SIGN and AGREE_KEY` purposes.
271 /// `INCOMPATIBLE_PURPOSE` error response is expected.
272 #[test]
keystore2_generate_ec_key_25519_multi_purpose()273 fn keystore2_generate_ec_key_25519_multi_purpose() {
274 let sl = SecLevel::tee();
275 let alias = format!("ks_ec_no_curve_test_key_{}", getuid());
276
277 // Specify `SIGN and AGREE_KEY` purposes.
278 let gen_params = authorizations::AuthSetBuilder::new()
279 .no_auth_required()
280 .algorithm(Algorithm::EC)
281 .ec_curve(EcCurve::CURVE_25519)
282 .purpose(KeyPurpose::SIGN)
283 .purpose(KeyPurpose::AGREE_KEY)
284 .digest(Digest::SHA_2_256);
285
286 let result = key_generations::map_ks_error(sl.binder.generateKey(
287 &KeyDescriptor {
288 domain: Domain::SELINUX,
289 nspace: key_generations::SELINUX_SHELL_NAMESPACE,
290 alias: Some(alias),
291 blob: None,
292 },
293 None,
294 &gen_params,
295 0,
296 b"entropy",
297 ));
298 assert!(result.is_err());
299 assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
300 }
301
302 /// Generate EC key with curve `CURVE_25519` and digest mode NONE. Try to create an operation using
303 /// generated key. `CURVE_25519` key should support `Digest::NONE` digest mode and test should be
304 /// able to create an operation successfully.
305 #[test]
keystore2_ec_25519_generate_key_success()306 fn keystore2_ec_25519_generate_key_success() {
307 let sl = SecLevel::tee();
308
309 let alias = format!("ks_ec_25519_none_test_key_gen_{}", getuid());
310 let key_metadata = key_generations::generate_ec_key(
311 &sl,
312 Domain::APP,
313 -1,
314 Some(alias),
315 EcCurve::CURVE_25519,
316 Digest::NONE,
317 )
318 .unwrap();
319
320 let op_response = sl
321 .binder
322 .createOperation(
323 &key_metadata.key,
324 &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::NONE),
325 false,
326 )
327 .unwrap();
328 assert!(op_response.iOperation.is_some());
329 assert_eq!(
330 Ok(()),
331 key_generations::map_ks_error(perform_sample_sign_operation(
332 &op_response.iOperation.unwrap()
333 ))
334 );
335 }
336
337 /// Generate EC keys with curve `CURVE_25519` and digest modes `MD5, SHA1, SHA-2 224, SHA-2 256,
338 /// SHA-2 384 and SHA-2 512`. Try to create operations using generated keys. `CURVE_25519` keys
339 /// shouldn't support these digest modes. Test should fail to create operations with an error
340 /// `UNSUPPORTED_DIGEST`.
341 #[test]
keystore2_ec_25519_generate_key_fail()342 fn keystore2_ec_25519_generate_key_fail() {
343 let sl = SecLevel::tee();
344
345 let digests = [
346 Digest::MD5,
347 Digest::SHA1,
348 Digest::SHA_2_224,
349 Digest::SHA_2_256,
350 Digest::SHA_2_384,
351 Digest::SHA_2_512,
352 ];
353
354 for digest in digests {
355 let alias = format!("ks_ec_25519_test_key_gen_{}{}", getuid(), digest.0);
356 let key_metadata = key_generations::generate_ec_key(
357 &sl,
358 Domain::APP,
359 -1,
360 Some(alias.to_string()),
361 EcCurve::CURVE_25519,
362 digest,
363 )
364 .unwrap();
365
366 // The KeyMint v2 API added `CURVE_25519` and specified that "Ed25519 keys only support
367 // Digest::NONE". However, this was not checked at the time so we can only be strict about
368 // checking this for more recent implementations.
369 if get_vsr_api_level() >= 35 {
370 let result = key_generations::map_ks_error(sl.binder.createOperation(
371 &key_metadata.key,
372 &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
373 false,
374 ));
375 assert!(result.is_err(), "unexpected success for digest {digest:?}");
376 assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
377 }
378 }
379 }
380
381 /// Generate a EC key with `SHA_2_256` digest mode. Try to create an operation with digest mode
382 /// other than `SHA_2_256`. Creation of an operation with generated key should fail with
383 /// `INCOMPATIBLE_DIGEST` error as there is a mismatch of digest mode in key authorizations.
384 #[test]
keystore2_create_op_with_incompatible_key_digest()385 fn keystore2_create_op_with_incompatible_key_digest() {
386 let sl = SecLevel::tee();
387
388 let alias = "ks_ec_test_incomp_key_digest";
389 let key_metadata = key_generations::generate_ec_key(
390 &sl,
391 Domain::APP,
392 -1,
393 Some(alias.to_string()),
394 EcCurve::P_256,
395 Digest::SHA_2_256,
396 )
397 .unwrap();
398
399 let digests =
400 [Digest::NONE, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_384, Digest::SHA_2_512];
401
402 for digest in digests {
403 let result = key_generations::map_ks_error(sl.binder.createOperation(
404 &key_metadata.key,
405 &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
406 false,
407 ));
408 assert!(result.is_err());
409 assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
410 }
411 }
412
413 /// Generate a key in client#1 and try to use it in other client#2.
414 /// Client#2 should fail to load the key as the it doesn't own the client#1 generated key.
415 #[test]
keystore2_key_owner_validation()416 fn keystore2_key_owner_validation() {
417 static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
418 const USER_ID: u32 = 99;
419 const APPLICATION_ID_1: u32 = 10601;
420
421 let uid1 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_1;
422 let gid1 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_1;
423 let alias = "ks_owner_check_test_key";
424
425 // Client#1: Generate a key and create an operation using generated key.
426 // Wait until the parent notifies to continue. Once the parent notifies, this operation
427 // is expected to be completed successfully.
428
429 // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
430 // `--test-threads=1`), and nothing yet done with binder.
431 let mut child_handle = unsafe {
432 execute_op_run_as_child(
433 TARGET_CTX,
434 Domain::APP,
435 -1,
436 Some(alias.to_string()),
437 Uid::from_raw(uid1),
438 Gid::from_raw(gid1),
439 ForcedOp(false),
440 )
441 };
442
443 // Wait until (client#1) child process notifies us to continue, so that there will be a key
444 // generated by client#1.
445 child_handle.recv();
446
447 // Client#2: This child will try to load the key generated by client#1.
448 const APPLICATION_ID_2: u32 = 10602;
449 let uid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
450 let gid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
451
452 let get_key_fn = move || {
453 let keystore2_inst = get_keystore_service();
454 let result = key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
455 domain: Domain::APP,
456 nspace: -1,
457 alias: Some(alias.to_string()),
458 blob: None,
459 }));
460 assert!(result.is_err());
461 assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
462 };
463
464 // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
465 // `--test-threads=1`), and nothing yet done with binder.
466 unsafe {
467 run_as::run_as_app(uid2, gid2, get_key_fn);
468 };
469
470 // Notify the child process (client#1) to resume and finish.
471 child_handle.send(&BarrierReached {});
472 assert!(
473 (child_handle.get_result() == TestOutcome::Ok),
474 "Client#1 failed to complete the operation."
475 );
476 }
477
478 /// Generate EC key with BLOB as domain. Generated key should be returned to caller as key blob.
479 /// Verify that `blob` field in the `KeyDescriptor` is not empty and should have the key blob.
480 /// Try to use this key for performing a sample operation and the operation should complete
481 /// successfully.
482 #[test]
keystore2_generate_key_with_blob_domain()483 fn keystore2_generate_key_with_blob_domain() {
484 let sl = SecLevel::tee();
485
486 let key_metadata = key_generations::generate_ec_key(
487 &sl,
488 Domain::BLOB,
489 key_generations::SELINUX_SHELL_NAMESPACE,
490 None,
491 EcCurve::P_256,
492 Digest::SHA_2_256,
493 )
494 .unwrap();
495
496 assert!(key_metadata.certificate.is_some());
497 assert!(key_metadata.certificateChain.is_none());
498
499 // Must have the key blob.
500 assert!(key_metadata.key.blob.is_some());
501
502 let op_response = key_generations::map_ks_error(sl.binder.createOperation(
503 &key_metadata.key,
504 &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
505 false,
506 ))
507 .unwrap();
508 assert!(op_response.iOperation.is_some());
509 assert_eq!(
510 Ok(()),
511 key_generations::map_ks_error(perform_sample_sign_operation(
512 &op_response.iOperation.unwrap()
513 ))
514 );
515
516 // Delete the generated key blob.
517 sl.delete_key(&key_metadata.key).unwrap();
518 }
519