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, Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
17     SecurityLevel::SecurityLevel,
18 };
19 use android_system_keystore2::aidl::android::system::keystore2::{
20     Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
21 };
22 
23 use keystore2_test_utils::{
24     authorizations, get_keystore_service, key_generations, key_generations::Error,
25 };
26 
27 use crate::keystore2_client_test_utils::perform_sample_sign_operation;
28 
29 /// Generate HMAC key with given parameters and perform a sample operation using generated key.
create_hmac_key_and_operation( sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>, alias: &str, key_size: i32, mac_len: i32, min_mac_len: i32, digest: Digest, ) -> Result<(), binder::Status>30 fn create_hmac_key_and_operation(
31     sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
32     alias: &str,
33     key_size: i32,
34     mac_len: i32,
35     min_mac_len: i32,
36     digest: Digest,
37 ) -> Result<(), binder::Status> {
38     let key_metadata =
39         key_generations::generate_hmac_key(sec_level, alias, key_size, min_mac_len, digest)?;
40 
41     let op_response = sec_level.createOperation(
42         &key_metadata.key,
43         &authorizations::AuthSetBuilder::new()
44             .purpose(KeyPurpose::SIGN)
45             .digest(digest)
46             .mac_length(mac_len),
47         false,
48     )?;
49 
50     assert!(op_response.iOperation.is_some());
51     assert_eq!(
52         Ok(()),
53         key_generations::map_ks_error(perform_sample_sign_operation(
54             &op_response.iOperation.unwrap()
55         ))
56     );
57 
58     Ok(())
59 }
60 
61 /// Generate HMAC keys with various digest modes [SHA1, SHA_2_224, SHA_2_256, SHA_2_384,
62 /// SHA_2_512]. Create an operation using generated keys. Test should create operations
63 /// successfully.
64 #[test]
keystore2_hmac_key_op_success()65 fn keystore2_hmac_key_op_success() {
66     let digests =
67         [Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512];
68     let min_mac_len = 128;
69     let mac_len = 128;
70     let key_size = 128;
71 
72     let keystore2 = get_keystore_service();
73     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
74 
75     for digest in digests {
76         let alias = format!("ks_hmac_test_key_{}", digest.0);
77 
78         assert_eq!(
79             Ok(()),
80             create_hmac_key_and_operation(
81                 &sec_level,
82                 &alias,
83                 key_size,
84                 mac_len,
85                 min_mac_len,
86                 digest,
87             )
88         );
89     }
90 }
91 
92 /// Generate HMAC keys with various key lengths. For invalid key sizes, key generation
93 /// should fail with an error code `UNSUPPORTED_KEY_SIZE`.
94 #[test]
keystore2_hmac_gen_keys_fails_expect_unsupported_key_size()95 fn keystore2_hmac_gen_keys_fails_expect_unsupported_key_size() {
96     let min_mac_len = 256;
97     let digest = Digest::SHA_2_256;
98 
99     let keystore2 = get_keystore_service();
100     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
101 
102     for key_size in 0..513 {
103         let alias = format!("ks_hmac_test_key_{}", key_size);
104         let result = key_generations::map_ks_error(key_generations::generate_hmac_key(
105             &sec_level,
106             &alias,
107             key_size,
108             min_mac_len,
109             digest,
110         ));
111 
112         match result {
113             Ok(_) => {
114                 assert!((key_size >= 64 && key_size % 8 == 0));
115             }
116             Err(e) => {
117                 assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE));
118                 assert!((key_size < 64 || key_size % 8 != 0), "Unsupported KeySize: {}", key_size);
119             }
120         }
121     }
122 }
123 
124 /// Generate HMAC keys with various min-mac-lengths. For invalid min-mac-length, key generation
125 /// should fail with an error code `UNSUPPORTED_MIN_MAC_LENGTH`.
126 #[test]
keystore2_hmac_gen_keys_fails_expect_unsupported_min_mac_length()127 fn keystore2_hmac_gen_keys_fails_expect_unsupported_min_mac_length() {
128     let digest = Digest::SHA_2_256;
129     let key_size = 128;
130 
131     let keystore2 = get_keystore_service();
132     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
133 
134     for min_mac_len in 0..257 {
135         let alias = format!("ks_hmac_test_key_mml_{}", min_mac_len);
136         match key_generations::map_ks_error(key_generations::generate_hmac_key(
137             &sec_level,
138             &alias,
139             key_size,
140             min_mac_len,
141             digest,
142         )) {
143             Ok(_) => {
144                 assert!((min_mac_len >= 64 && min_mac_len % 8 == 0));
145             }
146             Err(e) => {
147                 assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH));
148                 assert!(
149                     (min_mac_len < 64 || min_mac_len % 8 != 0),
150                     "Unsupported MinMacLength: {}",
151                     min_mac_len
152                 );
153             }
154         }
155     }
156 }
157 
158 /// Try to generate HMAC key with multiple digests in key authorizations list.
159 /// Test fails to generate a key with multiple digests with an error code `UNSUPPORTED_DIGEST`.
160 #[test]
keystore2_hmac_gen_key_multi_digests_fails_expect_unsupported_digest()161 fn keystore2_hmac_gen_key_multi_digests_fails_expect_unsupported_digest() {
162     let keystore2 = get_keystore_service();
163     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
164 
165     let alias = "ks_hmac_test_key_multi_dig";
166     let gen_params = authorizations::AuthSetBuilder::new()
167         .no_auth_required()
168         .algorithm(Algorithm::HMAC)
169         .purpose(KeyPurpose::SIGN)
170         .purpose(KeyPurpose::VERIFY)
171         .key_size(128)
172         .min_mac_length(128)
173         .digest(Digest::SHA1)
174         .digest(Digest::SHA_2_256);
175 
176     let result = key_generations::map_ks_error(sec_level.generateKey(
177         &KeyDescriptor {
178             domain: Domain::APP,
179             nspace: -1,
180             alias: Some(alias.to_string()),
181             blob: None,
182         },
183         None,
184         &gen_params,
185         0,
186         b"entropy",
187     ));
188     assert!(result.is_err());
189     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
190 }
191 
192 /// Try to generate HMAC key without providing digest mode. HMAC key generation with
193 /// no digest should fail with an error code `UNSUPPORTED_DIGEST`.
194 #[test]
keystore2_hmac_gen_key_no_digests_fails_expect_unsupported_digest()195 fn keystore2_hmac_gen_key_no_digests_fails_expect_unsupported_digest() {
196     let keystore2 = get_keystore_service();
197     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
198 
199     let alias = "ks_hmac_test_key_no_dig";
200     let gen_params = authorizations::AuthSetBuilder::new()
201         .no_auth_required()
202         .algorithm(Algorithm::HMAC)
203         .purpose(KeyPurpose::SIGN)
204         .purpose(KeyPurpose::VERIFY)
205         .key_size(128)
206         .min_mac_length(128);
207 
208     let result = key_generations::map_ks_error(sec_level.generateKey(
209         &KeyDescriptor {
210             domain: Domain::APP,
211             nspace: -1,
212             alias: Some(alias.to_string()),
213             blob: None,
214         },
215         None,
216         &gen_params,
217         0,
218         b"entropy",
219     ));
220     assert!(result.is_err());
221     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
222 }
223 
224 /// Try to generate a HMAC key with NONE digest mode, it should fail with `UNSUPPORTED_DIGEST`
225 /// error code.
226 #[test]
keystore2_hmac_gen_key_with_none_digest_fails_expect_unsupported_digest()227 fn keystore2_hmac_gen_key_with_none_digest_fails_expect_unsupported_digest() {
228     let min_mac_len = 128;
229     let key_size = 128;
230     let keystore2 = get_keystore_service();
231     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
232 
233     let alias = "ks_hmac_test_key_fail";
234     let result = key_generations::map_ks_error(key_generations::generate_hmac_key(
235         &sec_level,
236         alias,
237         key_size,
238         min_mac_len,
239         Digest::NONE,
240     ));
241     assert!(result.is_err());
242     assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
243 }
244 
245 /// Generate HMAC key with min-mac-len of 128 bits for the digest modes Digest::SHA1 and
246 /// Digest::SHA_2_224. Try to create an operation with generated key and mac-length greater than
247 /// digest length. Test should fail to create an operation with an error code
248 /// `UNSUPPORTED_MAC_LENGTH`.
249 #[test]
keystore2_hmac_key_op_with_mac_len_greater_than_digest_len_fail()250 fn keystore2_hmac_key_op_with_mac_len_greater_than_digest_len_fail() {
251     let digests = [Digest::SHA1, Digest::SHA_2_224];
252     let min_mac_len = 128;
253     let mac_len = 256;
254     let key_size = 128;
255 
256     let keystore2 = get_keystore_service();
257     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
258 
259     for digest in digests {
260         let alias = format!("ks_hmac_test_key_{}", digest.0);
261 
262         let result = key_generations::map_ks_error(create_hmac_key_and_operation(
263             &sec_level,
264             &alias,
265             key_size,
266             mac_len,
267             min_mac_len,
268             digest,
269         ));
270 
271         assert!(result.is_err());
272         assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH), result.unwrap_err());
273     }
274 }
275 
276 /// Generate HMAC key with min-mac-len of 128 bits for the digest modes Digest::SHA1 and
277 /// Digest::SHA_2_224. Try to create an operation with generated key and mac-length less than
278 /// min-mac-length. Test should fail to create an operation with an error code
279 /// `INVALID_MAC_LENGTH`.
280 #[test]
keystore2_hmac_key_op_with_mac_len_less_than_min_mac_len_fail()281 fn keystore2_hmac_key_op_with_mac_len_less_than_min_mac_len_fail() {
282     let digests = [Digest::SHA1, Digest::SHA_2_224];
283     let min_mac_len = 128;
284     let mac_len = 64;
285     let key_size = 128;
286 
287     let keystore2 = get_keystore_service();
288     let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
289 
290     for digest in digests {
291         let alias = format!("ks_hmac_test_key_{}", digest.0);
292 
293         let result = key_generations::map_ks_error(create_hmac_key_and_operation(
294             &sec_level,
295             &alias,
296             key_size,
297             mac_len,
298             min_mac_len,
299             digest,
300         ));
301 
302         assert!(result.is_err());
303         assert_eq!(Error::Km(ErrorCode::INVALID_MAC_LENGTH), result.unwrap_err());
304     }
305 }
306