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 android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
16     Algorithm::Algorithm, BlockMode::BlockMode, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
17     PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
18 };
19 
20 use android_system_keystore2::aidl::android::system::keystore2::{
21     Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
22 };
23 
24 use keystore2_test_utils::{
25     authorizations, get_keystore_service, key_generations, key_generations::Error,
26 };
27 
28 use crate::keystore2_client_test_utils::{
29     perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
30 };
31 
32 /// Generate a AES key. Create encrypt and decrypt operations using the generated key.
create_aes_key_and_operation( sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>, key_size: i32, padding_mode: PaddingMode, block_mode: BlockMode, mac_len: Option<i32>, min_mac_len: Option<i32>, nonce: &mut Option<Vec<u8>>, ) -> Result<(), binder::Status>33 fn create_aes_key_and_operation(
34     sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
35     key_size: i32,
36     padding_mode: PaddingMode,
37     block_mode: BlockMode,
38     mac_len: Option<i32>,
39     min_mac_len: Option<i32>,
40     nonce: &mut Option<Vec<u8>>,
41 ) -> Result<(), binder::Status> {
42     let alias = format!("ks_aes_test_key_{}{}{}", key_size, block_mode.0, padding_mode.0);
43 
44     let key_metadata = key_generations::generate_sym_key(
45         sec_level,
46         Algorithm::AES,
47         key_size,
48         &alias,
49         &padding_mode,
50         &block_mode,
51         min_mac_len,
52     )?;
53 
54     let cipher_text = perform_sample_sym_key_encrypt_op(
55         sec_level,
56         padding_mode,
57         block_mode,
58         nonce,
59         mac_len,
60         &key_metadata.key,
61     )?;
62 
63     assert!(cipher_text.is_some());
64 
65     let plain_text = perform_sample_sym_key_decrypt_op(
66         sec_level,
67         &cipher_text.unwrap(),
68         padding_mode,
69         block_mode,
70         nonce,
71         mac_len,
72         &key_metadata.key,
73     )
74     .unwrap();
75     assert!(plain_text.is_some());
76     assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
77     Ok(())
78 }
79 
80 /// Generate AES keys with various block modes and paddings.
81 ///  - Block Modes: ECB, CBC
82 ///  - Padding Modes: NONE, PKCS7
83 /// Test should generate keys and perform operation successfully.
84 #[test]
keystore2_aes_ecb_cbc_generate_key()85 fn keystore2_aes_ecb_cbc_generate_key() {
86     let keystore2 = get_keystore_service();
87     let key_sizes = [128, 256];
88     let block_modes = [BlockMode::ECB, BlockMode::CBC];
89     let padding_modes = [PaddingMode::PKCS7, PaddingMode::NONE];
90 
91     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
92     for key_size in key_sizes {
93         for block_mode in block_modes {
94             for padding_mode in padding_modes {
95                 assert_eq!(
96                     Ok(()),
97                     create_aes_key_and_operation(
98                         &sec_level,
99                         key_size,
100                         padding_mode,
101                         block_mode,
102                         None,
103                         None,
104                         &mut None,
105                     )
106                 );
107             }
108         }
109     }
110 }
111 
112 /// Generate AES keys with -
113 ///  - Block Modes: `CTR, GCM`
114 ///  - Padding Modes: `NONE`
115 /// Test should generate keys and perform operation successfully.
116 #[test]
keystore2_aes_ctr_gcm_generate_key_success()117 fn keystore2_aes_ctr_gcm_generate_key_success() {
118     let keystore2 = get_keystore_service();
119     let key_sizes = [128, 256];
120     let key_params = [(BlockMode::CTR, None, None), (BlockMode::GCM, Some(128), Some(128))];
121 
122     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
123 
124     for key_size in key_sizes {
125         for (block_mode, mac_len, min_mac_len) in key_params {
126             let result = key_generations::map_ks_error(create_aes_key_and_operation(
127                 &sec_level,
128                 key_size,
129                 PaddingMode::NONE,
130                 block_mode,
131                 mac_len,
132                 min_mac_len,
133                 &mut None,
134             ));
135 
136             assert_eq!(Ok(()), result);
137         } // End of block mode.
138     } // End of key size.
139 }
140 
141 /// Generate AES keys with -
142 ///  - Block Modes: `CTR, GCM`
143 ///  - Padding Modes: `PKCS7`
144 /// Try to create an operation using generated keys, test should fail to create an operation
145 /// with an error code `INCOMPATIBLE_PADDING_MODE`.
146 #[test]
keystore2_aes_ctr_gcm_generate_key_fails_incompatible()147 fn keystore2_aes_ctr_gcm_generate_key_fails_incompatible() {
148     let keystore2 = get_keystore_service();
149     let key_sizes = [128, 256];
150     let key_params = [(BlockMode::CTR, None, None), (BlockMode::GCM, Some(128), Some(128))];
151 
152     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
153 
154     for key_size in key_sizes {
155         for (block_mode, mac_len, min_mac_len) in key_params {
156             let result = key_generations::map_ks_error(create_aes_key_and_operation(
157                 &sec_level,
158                 key_size,
159                 PaddingMode::PKCS7,
160                 block_mode,
161                 mac_len,
162                 min_mac_len,
163                 &mut None,
164             ));
165 
166             assert!(result.is_err());
167             assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PADDING_MODE), result.unwrap_err());
168         } // End of block mode.
169     } // End of key size.
170 }
171 
172 /// Try to generate AES key with invalid key size. Test should fail to generate a key with
173 /// an error code `UNSUPPORTED_KEY_SIZE`.
174 #[test]
keystore2_aes_key_fails_unsupported_key_size()175 fn keystore2_aes_key_fails_unsupported_key_size() {
176     let keystore2 = get_keystore_service();
177     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
178     let alias = "aes_key_test_invalid_1";
179 
180     let result = key_generations::map_ks_error(key_generations::generate_sym_key(
181         &sec_level,
182         Algorithm::AES,
183         1024,
184         alias,
185         &PaddingMode::NONE,
186         &BlockMode::ECB,
187         None,
188     ));
189     assert!(result.is_err());
190     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE), result.unwrap_err());
191 }
192 
193 /// Try to generate AES key with GCM block mode without providing `MIN_MAC_LENGTH`.
194 /// Test should fail to generate a key with an error code `MISSING_MIN_MAC_LENGTH`.
195 #[test]
keystore2_aes_gcm_key_fails_missing_min_mac_len()196 fn keystore2_aes_gcm_key_fails_missing_min_mac_len() {
197     let keystore2 = get_keystore_service();
198     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
199     let alias = "aes_key_test_invalid_1";
200 
201     let result = key_generations::map_ks_error(key_generations::generate_sym_key(
202         &sec_level,
203         Algorithm::AES,
204         128,
205         alias,
206         &PaddingMode::NONE,
207         &BlockMode::GCM,
208         None,
209     ));
210     assert!(result.is_err());
211     assert_eq!(Error::Km(ErrorCode::MISSING_MIN_MAC_LENGTH), result.unwrap_err());
212 }
213 
214 /// Try to create an operation using AES key with multiple block modes. Test should fail to create
215 /// an operation with `UNSUPPORTED_BLOCK_MODE` error code.
216 #[test]
keystore2_aes_key_op_fails_multi_block_modes()217 fn keystore2_aes_key_op_fails_multi_block_modes() {
218     let keystore2 = get_keystore_service();
219     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
220     let alias = "aes_key_test_invalid_1";
221 
222     let gen_params = authorizations::AuthSetBuilder::new()
223         .no_auth_required()
224         .algorithm(Algorithm::AES)
225         .purpose(KeyPurpose::ENCRYPT)
226         .purpose(KeyPurpose::DECRYPT)
227         .key_size(128)
228         .block_mode(BlockMode::ECB)
229         .block_mode(BlockMode::CBC)
230         .padding_mode(PaddingMode::NONE);
231 
232     let key_metadata = sec_level
233         .generateKey(
234             &KeyDescriptor {
235                 domain: Domain::APP,
236                 nspace: -1,
237                 alias: Some(alias.to_string()),
238                 blob: None,
239             },
240             None,
241             &gen_params,
242             0,
243             b"entropy",
244         )
245         .unwrap();
246 
247     let op_params = authorizations::AuthSetBuilder::new()
248         .purpose(KeyPurpose::ENCRYPT)
249         .block_mode(BlockMode::ECB)
250         .block_mode(BlockMode::CBC)
251         .padding_mode(PaddingMode::NONE);
252 
253     let result = key_generations::map_ks_error(sec_level.createOperation(
254         &key_metadata.key,
255         &op_params,
256         false,
257     ));
258     assert!(result.is_err());
259     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_BLOCK_MODE), result.unwrap_err());
260 }
261 
262 /// Try to create an operation using AES key with multiple padding modes. Test should fail to create
263 /// an operation with `UNSUPPORTED_PADDING_MODE` error code.
264 #[test]
keystore2_aes_key_op_fails_multi_padding_modes()265 fn keystore2_aes_key_op_fails_multi_padding_modes() {
266     let keystore2 = get_keystore_service();
267     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
268     let alias = "aes_key_test_invalid_1";
269 
270     let gen_params = authorizations::AuthSetBuilder::new()
271         .no_auth_required()
272         .algorithm(Algorithm::AES)
273         .purpose(KeyPurpose::ENCRYPT)
274         .purpose(KeyPurpose::DECRYPT)
275         .key_size(128)
276         .block_mode(BlockMode::ECB)
277         .padding_mode(PaddingMode::PKCS7)
278         .padding_mode(PaddingMode::NONE);
279 
280     let key_metadata = sec_level
281         .generateKey(
282             &KeyDescriptor {
283                 domain: Domain::APP,
284                 nspace: -1,
285                 alias: Some(alias.to_string()),
286                 blob: None,
287             },
288             None,
289             &gen_params,
290             0,
291             b"entropy",
292         )
293         .unwrap();
294 
295     let op_params = authorizations::AuthSetBuilder::new()
296         .purpose(KeyPurpose::ENCRYPT)
297         .block_mode(BlockMode::ECB)
298         .padding_mode(PaddingMode::PKCS7)
299         .padding_mode(PaddingMode::NONE);
300 
301     let result = key_generations::map_ks_error(sec_level.createOperation(
302         &key_metadata.key,
303         &op_params,
304         false,
305     ));
306     assert!(result.is_err());
307     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
308 }
309 
310 /// Generate a AES-ECB key with unpadded mode. Try to create an operation using generated key
311 /// with PKCS7 padding mode. Test should fail to create an Operation with
312 /// `INCOMPATIBLE_PADDING_MODE` error code.
313 #[test]
keystore2_aes_key_op_fails_incompatible_padding()314 fn keystore2_aes_key_op_fails_incompatible_padding() {
315     let keystore2 = get_keystore_service();
316     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
317     let alias = "aes_key_test_invalid_1";
318 
319     let key_metadata = key_generations::generate_sym_key(
320         &sec_level,
321         Algorithm::AES,
322         128,
323         alias,
324         &PaddingMode::NONE,
325         &BlockMode::ECB,
326         None,
327     )
328     .unwrap();
329 
330     let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
331         &sec_level,
332         PaddingMode::PKCS7,
333         BlockMode::ECB,
334         &mut None,
335         None,
336         &key_metadata.key,
337     ));
338     assert!(result.is_err());
339     assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PADDING_MODE), result.unwrap_err());
340 }
341 
342 /// Generate a AES-ECB key with unpadded mode. Try to create an operation using generated key
343 /// with CBC block mode. Test should fail to create an Operation with
344 /// `INCOMPATIBLE_BLOCK_MODE` error code.
345 #[test]
keystore2_aes_key_op_fails_incompatible_blockmode()346 fn keystore2_aes_key_op_fails_incompatible_blockmode() {
347     let keystore2 = get_keystore_service();
348     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
349     let alias = "aes_key_test_invalid_1";
350 
351     let key_metadata = key_generations::generate_sym_key(
352         &sec_level,
353         Algorithm::AES,
354         128,
355         alias,
356         &PaddingMode::NONE,
357         &BlockMode::ECB,
358         None,
359     )
360     .unwrap();
361 
362     let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
363         &sec_level,
364         PaddingMode::NONE,
365         BlockMode::CBC,
366         &mut None,
367         None,
368         &key_metadata.key,
369     ));
370     assert!(result.is_err());
371     assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_BLOCK_MODE), result.unwrap_err());
372 }
373 
374 /// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
375 /// generated key without providing `MAC_LENGTH`. Test should fail to create an operation with
376 /// `MISSING_MAC_LENGTH` error code.
377 #[test]
keystore2_aes_gcm_op_fails_missing_mac_len()378 fn keystore2_aes_gcm_op_fails_missing_mac_len() {
379     let keystore2 = get_keystore_service();
380     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
381     let mac_len = None;
382     let min_mac_len = Some(128);
383 
384     let result = key_generations::map_ks_error(create_aes_key_and_operation(
385         &sec_level,
386         128,
387         PaddingMode::NONE,
388         BlockMode::GCM,
389         mac_len,
390         min_mac_len,
391         &mut None,
392     ));
393     assert!(result.is_err());
394 
395     let e = result.unwrap_err();
396     assert!(
397         e == Error::Km(ErrorCode::MISSING_MAC_LENGTH)
398             || e == Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH)
399     );
400 }
401 
402 /// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
403 /// generated key and  provide `MAC_LENGTH` < key's `MIN_MAC_LENGTH`. Test should fail to create
404 /// an operation with `INVALID_MAC_LENGTH` error code.
405 #[test]
keystore2_aes_gcm_op_fails_invalid_mac_len()406 fn keystore2_aes_gcm_op_fails_invalid_mac_len() {
407     let keystore2 = get_keystore_service();
408     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
409     let mac_len = Some(96);
410     let min_mac_len = Some(104);
411 
412     let result = key_generations::map_ks_error(create_aes_key_and_operation(
413         &sec_level,
414         128,
415         PaddingMode::NONE,
416         BlockMode::GCM,
417         mac_len,
418         min_mac_len,
419         &mut None,
420     ));
421     assert!(result.is_err());
422     assert_eq!(Error::Km(ErrorCode::INVALID_MAC_LENGTH), result.unwrap_err());
423 }
424 
425 /// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
426 /// generated key and  provide `MAC_LENGTH` > 128. Test should fail to create an operation with
427 /// `UNSUPPORTED_MAC_LENGTH` error code.
428 #[test]
keystore2_aes_gcm_op_fails_unsupported_mac_len()429 fn keystore2_aes_gcm_op_fails_unsupported_mac_len() {
430     let keystore2 = get_keystore_service();
431     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
432 
433     let result = key_generations::map_ks_error(create_aes_key_and_operation(
434         &sec_level,
435         128,
436         PaddingMode::NONE,
437         BlockMode::GCM,
438         Some(256),
439         Some(128),
440         &mut None,
441     ));
442     assert!(result.is_err());
443     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH), result.unwrap_err());
444 }
445 
446 /// Generate a AES-CBC-PKCS7 key without `CALLER_NONCE` authorization. Try to set nonce while
447 /// creating an operation using this generated key. Test should fail to create an operation with
448 /// `CALLER_NONCE_PROHIBITED` error code.
449 #[test]
keystore2_aes_key_op_fails_nonce_prohibited()450 fn keystore2_aes_key_op_fails_nonce_prohibited() {
451     let keystore2 = get_keystore_service();
452     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
453     let alias = "aes_key_test_nonce_1";
454     let mut nonce = Some(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
455 
456     let key_metadata = key_generations::generate_sym_key(
457         &sec_level,
458         Algorithm::AES,
459         128,
460         alias,
461         &PaddingMode::PKCS7,
462         &BlockMode::CBC,
463         None,
464     )
465     .unwrap();
466 
467     let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
468         &sec_level,
469         PaddingMode::NONE,
470         BlockMode::CBC,
471         &mut nonce,
472         None,
473         &key_metadata.key,
474     ));
475     assert!(result.is_err());
476     assert_eq!(Error::Km(ErrorCode::CALLER_NONCE_PROHIBITED), result.unwrap_err());
477 }
478