• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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