blob: c555760dae262d6ab71ca1d93eeb53c9a797cac9 [file] [log] [blame]
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +00001// 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//! This module implements test utils to generate various types of keys.
16
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +000017use anyhow::Result;
18
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +000019use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Rajesh Nyamagoud11912ea2021-12-20 20:37:20 +000020 Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
21 ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +000022};
23use android_system_keystore2::aidl::android::system::keystore2::{
24 Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +000025 KeyMetadata::KeyMetadata, ResponseCode::ResponseCode,
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +000026};
27
28use crate::authorizations::AuthSetBuilder;
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +000029use android_system_keystore2::binder::{ExceptionCode, Result as BinderResult};
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +000030
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +000031/// Shell namespace.
32pub const SELINUX_SHELL_NAMESPACE: i64 = 1;
Rajesh Nyamagouddc6fb232021-12-08 21:27:15 +000033/// Vold namespace.
34pub const SELINUX_VOLD_NAMESPACE: i64 = 100;
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +000035
Rajesh Nyamagoudfa7c0f12021-12-02 17:15:48 +000036/// SU context.
37pub const TARGET_SU_CTX: &str = "u:r:su:s0";
38
39/// Vold context
40pub const TARGET_VOLD_CTX: &str = "u:r:vold:s0";
41
Rajesh Nyamagoud11912ea2021-12-20 20:37:20 +000042/// Key parameters to generate a key.
43pub struct KeyParams {
44 /// Key Size.
45 pub key_size: i32,
46 /// Key Purposes.
47 pub purpose: Vec<KeyPurpose>,
48 /// Padding Mode.
49 pub padding: Option<PaddingMode>,
50 /// Digest.
51 pub digest: Option<Digest>,
52 /// MFG Digest.
53 pub mgf_digest: Option<Digest>,
54 /// Block Mode.
55 pub block_mode: Option<BlockMode>,
56 /// Attestation challenge.
57 pub att_challenge: Option<Vec<u8>>,
58 /// Attestation app id.
59 pub att_app_id: Option<Vec<u8>>,
60}
61
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +000062/// To map Keystore errors.
63#[derive(thiserror::Error, Debug, Eq, PartialEq)]
64pub enum Error {
65 /// Keystore2 error code
66 #[error("ResponseCode {0:?}")]
67 Rc(ResponseCode),
68 /// Keymint error code
69 #[error("ErrorCode {0:?}")]
70 Km(ErrorCode),
71 /// Exception
72 #[error("Binder exception {0:?}")]
73 Binder(ExceptionCode),
74}
75
76/// Keystore2 error mapping.
77pub fn map_ks_error<T>(r: BinderResult<T>) -> Result<T, Error> {
78 r.map_err(|s| {
79 match s.exception_code() {
80 ExceptionCode::SERVICE_SPECIFIC => {
81 match s.service_specific_error() {
82 se if se < 0 => {
83 // Negative service specific errors are KM error codes.
84 Error::Km(ErrorCode(se))
85 }
86 se => {
87 // Positive service specific errors are KS response codes.
88 Error::Rc(ResponseCode(se))
89 }
90 }
91 }
92 // We create `Error::Binder` to preserve the exception code
93 // for logging.
94 e_code => Error::Binder(e_code),
95 }
96 })
97}
98
99/// Generate EC Key using given security level and domain with below key parameters and
100/// optionally allow the generated key to be attested with factory provisioned attest key using
101/// given challenge and application id -
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000102/// Purposes: SIGN and VERIFY
103/// Digest: SHA_2_256
104/// Curve: P_256
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +0000105pub fn generate_ec_p256_signing_key(
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000106 sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +0000107 domain: Domain,
108 nspace: i64,
109 alias: Option<String>,
110 att_challenge: Option<&[u8]>,
111 att_app_id: Option<&[u8]>,
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000112) -> binder::Result<KeyMetadata> {
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +0000113 let mut key_attest = false;
114 let mut gen_params = AuthSetBuilder::new()
Rajesh Nyamagoudc7d064d2022-08-20 01:45:17 +0000115 .no_auth_required()
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000116 .algorithm(Algorithm::EC)
117 .purpose(KeyPurpose::SIGN)
118 .purpose(KeyPurpose::VERIFY)
119 .digest(Digest::SHA_2_256)
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +0000120 .ec_curve(EcCurve::P_256);
121
122 if let Some(challenge) = att_challenge {
123 key_attest = true;
124 gen_params = gen_params.clone().attestation_challenge(challenge.to_vec());
125 }
126
127 if let Some(app_id) = att_app_id {
128 key_attest = true;
129 gen_params = gen_params.clone().attestation_app_id(app_id.to_vec());
130 }
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000131
132 match sec_level.generateKey(
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +0000133 &KeyDescriptor { domain, nspace, alias, blob: None },
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000134 None,
135 &gen_params,
136 0,
137 b"entropy",
138 ) {
139 Ok(key_metadata) => {
140 assert!(key_metadata.certificate.is_some());
Rajesh Nyamagoudb881d512021-12-10 00:33:15 +0000141 if key_attest {
142 assert!(key_metadata.certificateChain.is_some());
143 }
144 if domain == Domain::BLOB {
145 assert!(key_metadata.key.blob.is_some());
146 }
Rajesh Nyamagoud901386c2022-03-21 20:35:18 +0000147
148 Ok(key_metadata)
149 }
150 Err(e) => Err(e),
151 }
152}
Rajesh Nyamagouda7766452021-12-13 21:44:19 +0000153
154/// Generate EC signing key.
Rajesh Nyamagoudc7d064d2022-08-20 01:45:17 +0000155pub fn generate_ec_key(
156 sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
Rajesh Nyamagouda7766452021-12-13 21:44:19 +0000157 domain: Domain,
158 nspace: i64,
159 alias: Option<String>,
160 ec_curve: EcCurve,
161 digest: Digest,
162) -> binder::Result<KeyMetadata> {
163 let gen_params = AuthSetBuilder::new()
164 .no_auth_required()
165 .algorithm(Algorithm::EC)
166 .purpose(KeyPurpose::SIGN)
167 .purpose(KeyPurpose::VERIFY)
168 .digest(digest)
169 .ec_curve(ec_curve);
170
171 let key_metadata = sec_level.generateKey(
172 &KeyDescriptor { domain, nspace, alias, blob: None },
173 None,
174 &gen_params,
175 0,
176 b"entropy",
177 )?;
178
179 // Must have a public key.
180 assert!(key_metadata.certificate.is_some());
181
182 // Should not have an attestation record.
183 assert!(key_metadata.certificateChain.is_none());
184
185 if domain == Domain::BLOB {
186 assert!(key_metadata.key.blob.is_some());
187 } else {
188 assert!(key_metadata.key.blob.is_none());
189 }
190 Ok(key_metadata)
191}
Rajesh Nyamagoud11912ea2021-12-20 20:37:20 +0000192
193/// Generate a RSA key with the given key parameters, alias, domain and namespace.
194pub fn generate_rsa_key(
195 sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
196 domain: Domain,
197 nspace: i64,
198 alias: Option<String>,
199 key_params: &KeyParams,
200 attest_key: Option<&KeyDescriptor>,
201) -> binder::Result<KeyMetadata> {
202 let mut gen_params = AuthSetBuilder::new()
203 .no_auth_required()
204 .algorithm(Algorithm::RSA)
205 .rsa_public_exponent(65537)
206 .key_size(key_params.key_size);
207
208 for purpose in &key_params.purpose {
209 gen_params = gen_params.purpose(*purpose);
210 }
211 if let Some(value) = key_params.digest {
212 gen_params = gen_params.digest(value)
213 }
214 if let Some(value) = key_params.padding {
215 gen_params = gen_params.padding_mode(value);
216 }
217 if let Some(value) = key_params.mgf_digest {
218 gen_params = gen_params.mgf_digest(value);
219 }
220 if let Some(value) = key_params.block_mode {
221 gen_params = gen_params.block_mode(value)
222 }
223 if let Some(value) = &key_params.att_challenge {
224 gen_params = gen_params.attestation_challenge(value.to_vec())
225 }
226 if let Some(value) = &key_params.att_app_id {
227 gen_params = gen_params.attestation_app_id(value.to_vec())
228 }
229
230 let key_metadata = sec_level.generateKey(
231 &KeyDescriptor { domain, nspace, alias, blob: None },
232 attest_key,
233 &gen_params,
234 0,
235 b"entropy",
236 )?;
237
238 // Must have a public key.
239 assert!(key_metadata.certificate.is_some());
240
241 if attest_key.is_none() && key_params.att_challenge.is_some() && key_params.att_app_id.is_some()
242 {
243 // Should have an attestation record.
244 assert!(key_metadata.certificateChain.is_some());
245 } else {
246 // Should not have an attestation record.
247 assert!(key_metadata.certificateChain.is_none());
248 }
249
250 assert!(
251 (domain == Domain::BLOB && key_metadata.key.blob.is_some())
252 || key_metadata.key.blob.is_none()
253 );
254
255 Ok(key_metadata)
256}
Rajesh Nyamagoud47409932022-01-08 00:37:13 +0000257
Rajesh Nyamagoudc3523ba2022-08-05 17:38:25 +0000258/// Generate AES/3DES key.
259pub fn generate_sym_key(
Rajesh Nyamagoud47409932022-01-08 00:37:13 +0000260 sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
Rajesh Nyamagoudc3523ba2022-08-05 17:38:25 +0000261 algorithm: Algorithm,
Rajesh Nyamagoud47409932022-01-08 00:37:13 +0000262 size: i32,
263 alias: &str,
264 padding_mode: &PaddingMode,
265 block_mode: &BlockMode,
266 min_mac_len: Option<i32>,
267) -> binder::Result<KeyMetadata> {
268 let mut gen_params = AuthSetBuilder::new()
269 .no_auth_required()
Rajesh Nyamagoudc3523ba2022-08-05 17:38:25 +0000270 .algorithm(algorithm)
Rajesh Nyamagoud47409932022-01-08 00:37:13 +0000271 .purpose(KeyPurpose::ENCRYPT)
272 .purpose(KeyPurpose::DECRYPT)
273 .key_size(size)
274 .padding_mode(*padding_mode)
275 .block_mode(*block_mode);
276
277 if let Some(val) = min_mac_len {
278 gen_params = gen_params.min_mac_length(val);
279 }
280
281 let key_metadata = sec_level.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
294 // Should not have public certificate.
295 assert!(key_metadata.certificate.is_none());
296
297 // Should not have an attestation record.
298 assert!(key_metadata.certificateChain.is_none());
299 Ok(key_metadata)
300}
Rajesh Nyamagoud4c6193c2022-02-03 01:15:34 +0000301
302/// Generate HMAC key.
303pub fn generate_hmac_key(
304 sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
305 alias: &str,
306 key_size: i32,
307 min_mac_len: i32,
308 digest: Digest,
309) -> binder::Result<KeyMetadata> {
310 let gen_params = AuthSetBuilder::new()
311 .no_auth_required()
312 .algorithm(Algorithm::HMAC)
313 .purpose(KeyPurpose::SIGN)
314 .purpose(KeyPurpose::VERIFY)
315 .key_size(key_size)
316 .min_mac_length(min_mac_len)
317 .digest(digest);
318
319 let key_metadata = sec_level.generateKey(
320 &KeyDescriptor {
321 domain: Domain::APP,
322 nspace: -1,
323 alias: Some(alias.to_string()),
324 blob: None,
325 },
326 None,
327 &gen_params,
328 0,
329 b"entropy",
330 )?;
331
332 // Should not have public certificate.
333 assert!(key_metadata.certificate.is_none());
334
335 // Should not have an attestation record.
336 assert!(key_metadata.certificateChain.is_none());
337
338 Ok(key_metadata)
339}