blob: a19ba25b407acf084fb9e26a23bb1d5bdc5a5781 [file] [log] [blame]
Hasini Gunasinghe12486362020-07-24 18:40:20 +00001// Copyright 2020, 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
Janis Danisevskise6efb242020-12-19 13:58:01 -080015//! Key parameters are declared by KeyMint to describe properties of keys and operations.
16//! During key generation and import, key parameters are used to characterize a key, its usage
17//! restrictions, and additional parameters for attestation. During the lifetime of the key,
18//! the key characteristics are expressed as set of key parameters. During cryptographic
19//! operations, clients may specify additional operation specific parameters.
20//! This module provides a Keystore 2.0 internal representation for key parameters and
21//! implements traits to convert it from and into KeyMint KeyParameters and store it in
22//! the SQLite database.
23//!
24//! ## Synopsis
25//!
26//! enum KeyParameterValue {
27//! Invalid,
28//! Algorithm(Algorithm),
29//! ...
30//! }
31//!
32//! impl KeyParameterValue {
33//! pub fn get_tag(&self) -> Tag;
34//! pub fn new_from_sql(tag: Tag, data: &SqlField) -> Result<Self>;
35//! fn to_sql(&self) -> SqlResult<ToSqlOutput>
36//! }
37//!
38//! use ...::keymint::KeyParameter as KmKeyParameter;
39//! impl Into<KmKeyParameter> for KeyParameterValue {}
40//! impl From<KmKeyParameter> for KeyParameterValue {}
41//!
42//! ## Implementation
43//! Each of the five functions is implemented as match statement over each key parameter variant.
44//! We bootstrap these function as well as the KeyParameterValue enum itself from a single list
45//! of key parameters, that needs to be kept in sync with the KeyMint AIDL specification.
46//!
47//! The list resembles an enum declaration with a few extra fields.
48//! enum KeyParameterValue {
49//! Invalid with tag INVALID and field Invalid,
50//! Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
51//! ...
52//! }
53//! The tag corresponds to the variant of the keymint::Tag, and the field corresponds to the
54//! variant of the keymint::KeyParameterValue union. There is no one to one mapping between
55//! tags and union fields, e.g., the values of both tags BOOT_PATCHLEVEL and VENDOR_PATCHLEVEL
56//! are stored in the Integer field.
57//!
58//! The macros interpreting them all follow a similar pattern and follow the following fragment
59//! naming scheme:
60//!
61//! Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
62//! $vname $(($vtype ))? with tag $tag_name and field $field_name,
63//!
64//! Further, KeyParameterValue appears in the macro as $enum_name.
65//! Note that $vtype is optional to accommodate variants like Invalid which don't wrap a value.
66//!
67//! In some cases $vtype is not part of the expansion, but we still have to modify the expansion
68//! depending on the presence of $vtype. In these cases we recurse through the list following the
69//! following pattern:
70//!
71//! (@<marker> <non repeating args>, [<out list>], [<in list>])
72//!
73//! These macros usually have four rules:
74//! * Two main recursive rules, of the form:
75//! (
76//! @<marker>
77//! <non repeating args>,
78//! [<out list>],
79//! [<one element pattern> <in tail>]
80//! ) => {
81//! macro!{@<marker> <non repeating args>, [<out list>
82//! <one element expansion>
83//! ], [<in tail>]}
84//! };
85//! They pop one element off the <in list> and add one expansion to the out list.
86//! The element expansion is kept on a separate line (or lines) for better readability.
87//! The two variants differ in whether or not $vtype is expected.
88//! * The termination condition which has an empty in list.
89//! * The public interface, which does not have @marker and calls itself with an empty out list.
Hasini Gunasinghe12486362020-07-24 18:40:20 +000090
Janis Danisevskis4522c2b2020-11-27 18:04:58 -080091use crate::db_utils::SqlField;
Hasini Gunasingheaf993662020-07-24 18:40:20 +000092use crate::error::Error as KeystoreError;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070093use crate::error::ResponseCode;
94
Shawn Willden708744a2020-12-11 13:05:27 +000095pub use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070096 Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
97 HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
Janis Danisevskis398e6be2020-12-17 09:29:25 -080098 KeyParameter::KeyParameter as KmKeyParameter,
99 KeyParameterValue::KeyParameterValue as KmKeyParameterValue, KeyPurpose::KeyPurpose,
100 PaddingMode::PaddingMode, SecurityLevel::SecurityLevel, Tag::Tag,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000101};
Janis Danisevskisa53c9cf2020-10-26 11:52:33 -0700102use android_system_keystore2::aidl::android::system::keystore2::Authorization::Authorization;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000103use anyhow::{Context, Result};
Janis Danisevskis4522c2b2020-11-27 18:04:58 -0800104use rusqlite::types::{Null, ToSql, ToSqlOutput};
105use rusqlite::Result as SqlResult;
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000106
Janis Danisevskise6efb242020-12-19 13:58:01 -0800107/// This trait is used to associate a primitive to any type that can be stored inside a
108/// KeyParameterValue, especially the AIDL enum types, e.g., keymint::{Algorithm, Digest, ...}.
109/// This allows for simplifying the macro rules, e.g., for reading from the SQL database.
110/// An expression like `KeyParameterValue::Algorithm(row.get(0))` would not work because
111/// a type of `Algorithm` is expected which does not implement `FromSql` and we cannot
112/// implement it because we own neither the type nor the trait.
113/// With AssociatePrimitive we can write an expression
114/// `KeyParameter::Algorithm(<Algorithm>::from_primitive(row.get(0)))` to inform `get`
115/// about the expected primitive type that it can convert into. By implementing this
116/// trait for all inner types we can write a single rule to cover all cases (except where
117/// there is no wrapped type):
118/// `KeyParameterValue::$vname(<$vtype>::from_primitive(row.get(0)))`
119trait AssociatePrimitive {
120 type Primitive;
121
122 fn from_primitive(v: Self::Primitive) -> Self;
123 fn to_primitive(&self) -> Self::Primitive;
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000124}
125
Janis Danisevskise6efb242020-12-19 13:58:01 -0800126/// Associates the given type with i32. The macro assumes that the given type is actually a
127/// tuple struct wrapping i32, such as AIDL enum types.
128macro_rules! implement_associate_primitive_for_aidl_enum {
129 ($t:ty) => {
130 impl AssociatePrimitive for $t {
131 type Primitive = i32;
132
133 fn from_primitive(v: Self::Primitive) -> Self {
134 Self(v)
135 }
136 fn to_primitive(&self) -> Self::Primitive {
137 self.0
138 }
139 }
140 };
141}
142
143/// Associates the given type with itself.
144macro_rules! implement_associate_primitive_identity {
145 ($t:ty) => {
146 impl AssociatePrimitive for $t {
147 type Primitive = $t;
148
149 fn from_primitive(v: Self::Primitive) -> Self {
150 v
151 }
152 fn to_primitive(&self) -> Self::Primitive {
153 self.clone()
154 }
155 }
156 };
157}
158
159implement_associate_primitive_for_aidl_enum! {Algorithm}
160implement_associate_primitive_for_aidl_enum! {BlockMode}
161implement_associate_primitive_for_aidl_enum! {Digest}
162implement_associate_primitive_for_aidl_enum! {EcCurve}
163implement_associate_primitive_for_aidl_enum! {HardwareAuthenticatorType}
164implement_associate_primitive_for_aidl_enum! {KeyOrigin}
165implement_associate_primitive_for_aidl_enum! {KeyPurpose}
166implement_associate_primitive_for_aidl_enum! {PaddingMode}
167implement_associate_primitive_for_aidl_enum! {SecurityLevel}
168
169implement_associate_primitive_identity! {Vec<u8>}
170implement_associate_primitive_identity! {i64}
171implement_associate_primitive_identity! {i32}
172
173/// Expands the list of KeyParameterValue variants as follows:
174///
175/// Input:
176/// pub enum KeyParameterValue {
177/// Invalid with tag INVALID and field Invalid,
178/// Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
179/// }
180///
181/// Output:
182/// ```
183/// pub enum KeyParameterValue {
184/// Invalid,
185/// Algorithm(Algorithm),
186/// }
187/// ```
188macro_rules! implement_enum {
189 (
190 $(#[$enum_meta:meta])*
191 $enum_vis:vis enum $enum_name:ident {
192 $($(#[$emeta:meta])* $vname:ident$(($vtype:ty))?),* $(,)?
193 }
194 ) => {
195 $(#[$enum_meta])*
196 $enum_vis enum $enum_name {
197 $(
198 $(#[$emeta])*
199 $vname$(($vtype))?
200 ),*
201 }
202 };
203}
204
205/// Expands the list of KeyParameterValue variants as follows:
206///
207/// Input:
208/// Invalid with tag INVALID and field Invalid,
209/// Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
210///
211/// Output:
212/// ```
213/// pub fn get_tag(&self) -> Tag {
214/// match self {
215/// KeyParameterValue::Invalid => Tag::INVALID,
216/// KeyParameterValue::Algorithm(_) => Tag::ALGORITHM,
217/// }
218/// }
219/// ```
220macro_rules! implement_get_tag {
221 (
222 @replace_type_spec
223 $enum_name:ident,
224 [$($out:tt)*],
225 [$vname:ident($vtype:ty) $tag_name:ident, $($in:tt)*]
226 ) => {
227 implement_get_tag!{@replace_type_spec $enum_name, [$($out)*
228 $enum_name::$vname(_) => Tag::$tag_name,
229 ], [$($in)*]}
230 };
231 (
232 @replace_type_spec
233 $enum_name:ident,
234 [$($out:tt)*],
235 [$vname:ident $tag_name:ident, $($in:tt)*]
236 ) => {
237 implement_get_tag!{@replace_type_spec $enum_name, [$($out)*
238 $enum_name::$vname => Tag::$tag_name,
239 ], [$($in)*]}
240 };
241 (@replace_type_spec $enum_name:ident, [$($out:tt)*], []) => {
242 /// Returns the tag of the given instance.
243 pub fn get_tag(&self) -> Tag {
244 match self {
245 $($out)*
246 }
247 }
248 };
249
250 ($enum_name:ident; $($vname:ident$(($vtype:ty))? $tag_name:ident),*) => {
251 implement_get_tag!{@replace_type_spec $enum_name, [], [$($vname$(($vtype))? $tag_name,)*]}
252 };
253}
254
255/// Expands the list of KeyParameterValue variants as follows:
256///
257/// Input:
258/// Invalid with tag INVALID and field Invalid,
259/// Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
260///
261/// Output:
262/// ```
263/// fn to_sql(&self) -> SqlResult<ToSqlOutput> {
264/// match self {
265/// KeyParameterValue::Invalid => Ok(ToSqlOutput::from(Null)),
266/// KeyParameterValue::Algorithm(v) => Ok(ToSqlOutput::from(v.to_primitive())),
267/// }
268/// }
269/// ```
270macro_rules! implement_to_sql {
271 (
272 @replace_type_spec
273 $enum_name:ident,
274 [$($out:tt)*],
275 [$vname:ident($vtype:ty), $($in:tt)*]
276 ) => {
277 implement_to_sql!{@replace_type_spec $enum_name, [ $($out)*
278 $enum_name::$vname(v) => Ok(ToSqlOutput::from(v.to_primitive())),
279 ], [$($in)*]}
280 };
281 (
282 @replace_type_spec
283 $enum_name:ident,
284 [$($out:tt)*],
285 [$vname:ident, $($in:tt)*]
286 ) => {
287 implement_to_sql!{@replace_type_spec $enum_name, [ $($out)*
288 $enum_name::$vname => Ok(ToSqlOutput::from(Null)),
289 ], [$($in)*]}
290 };
291 (@replace_type_spec $enum_name:ident, [$($out:tt)*], []) => {
292 /// Converts $enum_name to be stored in a rusqlite database.
293 fn to_sql(&self) -> SqlResult<ToSqlOutput> {
294 match self {
295 $($out)*
296 }
297 }
298 };
299
300
301 ($enum_name:ident; $($vname:ident$(($vtype:ty))?),*) => {
302 impl ToSql for $enum_name {
303 implement_to_sql!{@replace_type_spec $enum_name, [], [$($vname$(($vtype))?,)*]}
304 }
305
306 }
307}
308
309/// Expands the list of KeyParameterValue variants as follows:
310///
311/// Input:
312/// Invalid with tag INVALID and field Invalid,
313/// Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
314///
315/// Output:
316/// ```
317/// pub fn new_from_sql(
318/// tag: Tag,
319/// data: &SqlField,
320/// ) -> Result<Self> {
321/// Ok(match self {
322/// Tag::Invalid => KeyParameterValue::Invalid,
323/// Tag::ALGORITHM => {
324/// KeyParameterValue::Algorithm(<Algorithm>::from_primitive(data
325/// .get()
326/// .map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
327/// .context(concat!("Failed to read sql data for tag: ", "ALGORITHM", "."))?
328/// ))
329/// },
330/// })
331/// }
332/// ```
333macro_rules! implement_new_from_sql {
334 ($enum_name:ident; $($vname:ident$(($vtype:ty))? $tag_name:ident),*) => {
335 /// Takes a tag and an SqlField and attempts to construct a KeyParameter value.
336 /// This function may fail if the parameter value cannot be extracted from the
337 /// database cell.
338 pub fn new_from_sql(
339 tag: Tag,
340 data: &SqlField,
341 ) -> Result<Self> {
342 Ok(match tag {
343 $(
344 Tag::$tag_name => {
345 $enum_name::$vname$((<$vtype>::from_primitive(data
346 .get()
347 .map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
348 .context(concat!(
349 "Failed to read sql data for tag: ",
350 stringify!($tag_name),
351 "."
352 ))?
353 )))?
354 },
355 )*
356 _ => $enum_name::Invalid,
357 })
358 }
359 };
360}
361
362/// This key parameter default is used during the conversion from KeyParameterValue
363/// to keymint::KeyParameterValue. Keystore's version does not have wrapped types
364/// for boolean tags and the tag Invalid. The AIDL version uses bool and integer
365/// variants respectively. This default function is invoked in these cases to
366/// homogenize the rules for boolean and invalid tags.
367/// The bool variant returns true because boolean parameters are implicitly true
368/// if present.
369trait KpDefault {
370 fn default() -> Self;
371}
372
373impl KpDefault for i32 {
374 fn default() -> Self {
375 0
376 }
377}
378
379impl KpDefault for bool {
380 fn default() -> Self {
381 true
382 }
383}
384
385/// Expands the list of KeyParameterValue variants as follows:
386///
387/// Input:
388/// Invalid with tag INVALID and field Invalid,
389/// Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
390///
391/// Output:
392/// ```
393/// impl From<KmKeyParameter> for KeyParameterValue {
394/// fn from(kp: KmKeyParameter) -> Self {
395/// match kp {
396/// KmKeyParameter { tag: Tag::INVALID, value: KmKeyParameterValue::Invalid(_) }
397/// => $enum_name::$vname,
398/// KmKeyParameter { tag: Tag::Algorithm, value: KmKeyParameterValue::Algorithm(v) }
399/// => $enum_name::Algorithm(v),
400/// _ => $enum_name::Invalid,
401/// }
402/// }
403/// }
404///
405/// impl Into<KmKeyParameter> for KeyParameterValue {
406/// fn into(self) -> KmKeyParameter {
407/// match self {
408/// KeyParameterValue::Invalid => KmKeyParameter {
409/// tag: Tag::INVALID,
410/// value: KmKeyParameterValue::Invalid(KpDefault::default())
411/// },
412/// KeyParameterValue::Algorithm(v) => KmKeyParameter {
413/// tag: Tag::ALGORITHM,
414/// value: KmKeyParameterValue::Algorithm(v)
415/// },
416/// }
417/// }
418/// }
419/// ```
420macro_rules! implement_try_from_to_km_parameter {
421 // The first three rules expand From<KmKeyParameter>.
422 (
423 @from
424 $enum_name:ident,
425 [$($out:tt)*],
426 [$vname:ident($vtype:ty) $tag_name:ident $field_name:ident, $($in:tt)*]
427 ) => {
428 implement_try_from_to_km_parameter!{@from $enum_name, [$($out)*
429 KmKeyParameter {
430 tag: Tag::$tag_name,
431 value: KmKeyParameterValue::$field_name(v)
432 } => $enum_name::$vname(v),
433 ], [$($in)*]
434 }};
435 (
436 @from
437 $enum_name:ident,
438 [$($out:tt)*],
439 [$vname:ident $tag_name:ident $field_name:ident, $($in:tt)*]
440 ) => {
441 implement_try_from_to_km_parameter!{@from $enum_name, [$($out)*
442 KmKeyParameter {
443 tag: Tag::$tag_name,
444 value: KmKeyParameterValue::$field_name(_)
445 } => $enum_name::$vname,
446 ], [$($in)*]
447 }};
448 (@from $enum_name:ident, [$($out:tt)*], []) => {
449 impl From<KmKeyParameter> for $enum_name {
450 fn from(kp: KmKeyParameter) -> Self {
451 match kp {
452 $($out)*
453 _ => $enum_name::Invalid,
454 }
455 }
456 }
457 };
458
459 // The next three rules expand Into<KmKeyParameter>.
460 (
461 @into
462 $enum_name:ident,
463 [$($out:tt)*],
464 [$vname:ident($vtype:ty) $tag_name:ident $field_name:ident, $($in:tt)*]
465 ) => {
466 implement_try_from_to_km_parameter!{@into $enum_name, [$($out)*
467 $enum_name::$vname(v) => KmKeyParameter {
468 tag: Tag::$tag_name,
469 value: KmKeyParameterValue::$field_name(v)
470 },
471 ], [$($in)*]
472 }};
473 (
474 @into
475 $enum_name:ident,
476 [$($out:tt)*],
477 [$vname:ident $tag_name:ident $field_name:ident, $($in:tt)*]
478 ) => {
479 implement_try_from_to_km_parameter!{@into $enum_name, [$($out)*
480 $enum_name::$vname => KmKeyParameter {
481 tag: Tag::$tag_name,
482 value: KmKeyParameterValue::$field_name(KpDefault::default())
483 },
484 ], [$($in)*]
485 }};
486 (@into $enum_name:ident, [$($out:tt)*], []) => {
487 impl Into<KmKeyParameter> for $enum_name {
488 fn into(self) -> KmKeyParameter {
489 match self {
490 $($out)*
491 }
492 }
493 }
494 };
495
496
497 ($enum_name:ident; $($vname:ident$(($vtype:ty))? $tag_name:ident $field_name:ident),*) => {
498 implement_try_from_to_km_parameter!(
499 @from $enum_name,
500 [],
501 [$($vname$(($vtype))? $tag_name $field_name,)*]
502 );
503 implement_try_from_to_km_parameter!(
504 @into $enum_name,
505 [],
506 [$($vname$(($vtype))? $tag_name $field_name,)*]
507 );
508 };
509}
510
511/// This is the top level macro. While the other macros do most of the heavy lifting, this takes
512/// the key parameter list and passes it on to the other macros to generate all of the conversion
513/// functions. In addition, it generates an important test vector for verifying that tag type of the
514/// keymint tag matches the associated keymint KeyParameterValue field.
515macro_rules! implement_key_parameter_value {
516 (
517 $(#[$enum_meta:meta])*
518 $enum_vis:vis enum $enum_name:ident {
519 $(
520 $(#[$emeta:meta])*
521 $vname:ident$(($vtype:ty))? with tag $tag_name:ident and field $field_name:ident
522 ),* $(,)?
523 }
524 ) => {
525 implement_enum!(
526 $(#[$enum_meta])*
527 $enum_vis enum $enum_name {
528 $(
529 $(#[$emeta])*
530 $vname$(($vtype))?
531 ),*
532 });
533
534 impl $enum_name {
535 implement_new_from_sql!($enum_name; $($vname$(($vtype))? $tag_name),*);
536 implement_get_tag!($enum_name; $($vname$(($vtype))? $tag_name),*);
537
538 #[cfg(test)]
539 fn make_field_matches_tag_type_test_vector() -> Vec<KmKeyParameter> {
540 vec![$(KmKeyParameter{
541 tag: Tag::$tag_name,
542 value: KmKeyParameterValue::$field_name(Default::default())}
543 ),*]
544 }
545 }
546
547 implement_try_from_to_km_parameter!(
548 $enum_name;
549 $($vname$(($vtype))? $tag_name $field_name),*
550 );
551
552 implement_to_sql!($enum_name; $($vname$(($vtype))?),*);
553 };
554}
555
556implement_key_parameter_value! {
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000557/// KeyParameterValue holds a value corresponding to one of the Tags defined in
558/// the AIDL spec at hardware/interfaces/keymint
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700559#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000560pub enum KeyParameterValue {
561 /// Associated with Tag:INVALID
Janis Danisevskise6efb242020-12-19 13:58:01 -0800562 Invalid with tag INVALID and field Invalid,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000563 /// Set of purposes for which the key may be used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800564 KeyPurpose(KeyPurpose) with tag PURPOSE and field KeyPurpose,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000565 /// Cryptographic algorithm with which the key is used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800566 Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000567 /// Size of the key , in bits
Janis Danisevskise6efb242020-12-19 13:58:01 -0800568 KeySize(i32) with tag KEY_SIZE and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000569 /// Block cipher mode(s) with which the key may be used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800570 BlockMode(BlockMode) with tag BLOCK_MODE and field BlockMode,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000571 /// Digest algorithms that may be used with the key to perform signing and verification
Janis Danisevskise6efb242020-12-19 13:58:01 -0800572 Digest(Digest) with tag DIGEST and field Digest,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000573 /// Padding modes that may be used with the key. Relevant to RSA, AES and 3DES keys.
Janis Danisevskise6efb242020-12-19 13:58:01 -0800574 PaddingMode(PaddingMode) with tag PADDING and field PaddingMode,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000575 /// Can the caller provide a nonce for nonce-requiring operations
Janis Danisevskise6efb242020-12-19 13:58:01 -0800576 CallerNonce with tag CALLER_NONCE and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000577 /// Minimum length of MAC for HMAC keys and AES keys that support GCM mode
Janis Danisevskise6efb242020-12-19 13:58:01 -0800578 MinMacLength(i32) with tag MIN_MAC_LENGTH and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000579 /// The elliptic curve
Janis Danisevskise6efb242020-12-19 13:58:01 -0800580 EcCurve(EcCurve) with tag EC_CURVE and field EcCurve,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000581 /// Value of the public exponent for an RSA key pair
Janis Danisevskise6efb242020-12-19 13:58:01 -0800582 RSAPublicExponent(i64) with tag RSA_PUBLIC_EXPONENT and field LongInteger,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000583 /// An attestation certificate for the generated key should contain an application-scoped
584 /// and time-bounded device-unique ID
Janis Danisevskise6efb242020-12-19 13:58:01 -0800585 IncludeUniqueID with tag INCLUDE_UNIQUE_ID and field BoolValue,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000586 //TODO: find out about this
587 // /// Necessary system environment conditions for the generated key to be used
588 // KeyBlobUsageRequirements(KeyBlobUsageRequirements),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000589 /// Only the boot loader can use the key
Janis Danisevskise6efb242020-12-19 13:58:01 -0800590 BootLoaderOnly with tag BOOTLOADER_ONLY and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000591 /// When deleted, the key is guaranteed to be permanently deleted and unusable
Janis Danisevskise6efb242020-12-19 13:58:01 -0800592 RollbackResistance with tag ROLLBACK_RESISTANCE and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000593 /// The date and time at which the key becomes active
Janis Danisevskise6efb242020-12-19 13:58:01 -0800594 ActiveDateTime(i64) with tag ACTIVE_DATETIME and field DateTime,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000595 /// The date and time at which the key expires for signing and encryption
Janis Danisevskise6efb242020-12-19 13:58:01 -0800596 OriginationExpireDateTime(i64) with tag ORIGINATION_EXPIRE_DATETIME and field DateTime,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000597 /// The date and time at which the key expires for verification and decryption
Janis Danisevskise6efb242020-12-19 13:58:01 -0800598 UsageExpireDateTime(i64) with tag USAGE_EXPIRE_DATETIME and field DateTime,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000599 /// Minimum amount of time that elapses between allowed operations
Janis Danisevskise6efb242020-12-19 13:58:01 -0800600 MinSecondsBetweenOps(i32) with tag MIN_SECONDS_BETWEEN_OPS and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000601 /// Maximum number of times that a key may be used between system reboots
Janis Danisevskise6efb242020-12-19 13:58:01 -0800602 MaxUsesPerBoot(i32) with tag MAX_USES_PER_BOOT and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000603 /// ID of the Android user that is permitted to use the key
Janis Danisevskise6efb242020-12-19 13:58:01 -0800604 UserID(i32) with tag USER_ID and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000605 /// A key may only be used under a particular secure user authentication state
Janis Danisevskise6efb242020-12-19 13:58:01 -0800606 UserSecureID(i64) with tag USER_SECURE_ID and field LongInteger,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000607 /// No authentication is required to use this key
Janis Danisevskise6efb242020-12-19 13:58:01 -0800608 NoAuthRequired with tag NO_AUTH_REQUIRED and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000609 /// The types of user authenticators that may be used to authorize this key
Janis Danisevskise6efb242020-12-19 13:58:01 -0800610 HardwareAuthenticatorType(HardwareAuthenticatorType) with tag USER_AUTH_TYPE and field HardwareAuthenticatorType,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000611 /// The time in seconds for which the key is authorized for use, after user authentication
Janis Danisevskise6efb242020-12-19 13:58:01 -0800612 AuthTimeout(i32) with tag AUTH_TIMEOUT and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000613 /// The key may be used after authentication timeout if device is still on-body
Janis Danisevskise6efb242020-12-19 13:58:01 -0800614 AllowWhileOnBody with tag ALLOW_WHILE_ON_BODY and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000615 /// The key must be unusable except when the user has provided proof of physical presence
Janis Danisevskise6efb242020-12-19 13:58:01 -0800616 TrustedUserPresenceRequired with tag TRUSTED_USER_PRESENCE_REQUIRED and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000617 /// Applicable to keys with KeyPurpose SIGN, and specifies that this key must not be usable
618 /// unless the user provides confirmation of the data to be signed
Janis Danisevskise6efb242020-12-19 13:58:01 -0800619 TrustedConfirmationRequired with tag TRUSTED_CONFIRMATION_REQUIRED and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000620 /// The key may only be used when the device is unlocked
Janis Danisevskise6efb242020-12-19 13:58:01 -0800621 UnlockedDeviceRequired with tag UNLOCKED_DEVICE_REQUIRED and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000622 /// When provided to generateKey or importKey, this tag specifies data
623 /// that is necessary during all uses of the key
Janis Danisevskise6efb242020-12-19 13:58:01 -0800624 ApplicationID(Vec<u8>) with tag APPLICATION_ID and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000625 /// When provided to generateKey or importKey, this tag specifies data
626 /// that is necessary during all uses of the key
Janis Danisevskise6efb242020-12-19 13:58:01 -0800627 ApplicationData(Vec<u8>) with tag APPLICATION_DATA and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000628 /// Specifies the date and time the key was created
Janis Danisevskise6efb242020-12-19 13:58:01 -0800629 CreationDateTime(i64) with tag CREATION_DATETIME and field DateTime,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000630 /// Specifies where the key was created, if known
Janis Danisevskise6efb242020-12-19 13:58:01 -0800631 KeyOrigin(KeyOrigin) with tag ORIGIN and field Origin,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000632 /// The key used by verified boot to validate the operating system booted
Janis Danisevskise6efb242020-12-19 13:58:01 -0800633 RootOfTrust(Vec<u8>) with tag ROOT_OF_TRUST and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000634 /// System OS version with which the key may be used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800635 OSVersion(i32) with tag OS_VERSION and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000636 /// Specifies the system security patch level with which the key may be used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800637 OSPatchLevel(i32) with tag OS_PATCHLEVEL and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000638 /// Specifies a unique, time-based identifier
Janis Danisevskise6efb242020-12-19 13:58:01 -0800639 UniqueID(Vec<u8>) with tag UNIQUE_ID and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000640 /// Used to deliver a "challenge" value to the attestKey() method
Janis Danisevskise6efb242020-12-19 13:58:01 -0800641 AttestationChallenge(Vec<u8>) with tag ATTESTATION_CHALLENGE and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000642 /// The set of applications which may use a key, used only with attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800643 AttestationApplicationID(Vec<u8>) with tag ATTESTATION_APPLICATION_ID and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000644 /// Provides the device's brand name, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800645 AttestationIdBrand(Vec<u8>) with tag ATTESTATION_ID_BRAND and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000646 /// Provides the device's device name, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800647 AttestationIdDevice(Vec<u8>) with tag ATTESTATION_ID_DEVICE and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000648 /// Provides the device's product name, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800649 AttestationIdProduct(Vec<u8>) with tag ATTESTATION_ID_PRODUCT and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000650 /// Provides the device's serial number, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800651 AttestationIdSerial(Vec<u8>) with tag ATTESTATION_ID_SERIAL and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000652 /// Provides the IMEIs for all radios on the device, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800653 AttestationIdIMEI(Vec<u8>) with tag ATTESTATION_ID_IMEI and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000654 /// Provides the MEIDs for all radios on the device, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800655 AttestationIdMEID(Vec<u8>) with tag ATTESTATION_ID_MEID and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000656 /// Provides the device's manufacturer name, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800657 AttestationIdManufacturer(Vec<u8>) with tag ATTESTATION_ID_MANUFACTURER and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000658 /// Provides the device's model name, to attestKey()
Janis Danisevskise6efb242020-12-19 13:58:01 -0800659 AttestationIdModel(Vec<u8>) with tag ATTESTATION_ID_MODEL and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000660 /// Specifies the vendor image security patch level with which the key may be used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800661 VendorPatchLevel(i32) with tag VENDOR_PATCHLEVEL and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000662 /// Specifies the boot image (kernel) security patch level with which the key may be used
Janis Danisevskise6efb242020-12-19 13:58:01 -0800663 BootPatchLevel(i32) with tag BOOT_PATCHLEVEL and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000664 /// Provides "associated data" for AES-GCM encryption or decryption
Janis Danisevskise6efb242020-12-19 13:58:01 -0800665 AssociatedData(Vec<u8>) with tag ASSOCIATED_DATA and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000666 /// Provides or returns a nonce or Initialization Vector (IV) for AES-GCM,
667 /// AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption
Janis Danisevskise6efb242020-12-19 13:58:01 -0800668 Nonce(Vec<u8>) with tag NONCE and field Blob,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000669 /// Provides the requested length of a MAC or GCM authentication tag, in bits
Janis Danisevskise6efb242020-12-19 13:58:01 -0800670 MacLength(i32) with tag MAC_LENGTH and field Integer,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000671 /// Specifies whether the device has been factory reset since the
672 /// last unique ID rotation. Used for key attestation
Janis Danisevskise6efb242020-12-19 13:58:01 -0800673 ResetSinceIdRotation with tag RESET_SINCE_ID_ROTATION and field BoolValue,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000674 /// Used to deliver a cryptographic token proving that the user
675 /// confirmed a signing request
Janis Danisevskise6efb242020-12-19 13:58:01 -0800676 ConfirmationToken(Vec<u8>) with tag CONFIRMATION_TOKEN and field Blob,
677}
678}
679
680impl From<&KmKeyParameter> for KeyParameterValue {
681 fn from(kp: &KmKeyParameter) -> Self {
682 kp.clone().into()
683 }
684}
685
686/// KeyParameter wraps the KeyParameterValue and the security level at which it is enforced.
687#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
688pub struct KeyParameter {
689 value: KeyParameterValue,
690 security_level: SecurityLevel,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000691}
692
693impl KeyParameter {
694 /// Create an instance of KeyParameter, given the value and the security level.
Janis Danisevskise6efb242020-12-19 13:58:01 -0800695 pub fn new(value: KeyParameterValue, security_level: SecurityLevel) -> Self {
696 KeyParameter { value, security_level }
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000697 }
698
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000699 /// Construct a KeyParameter from the data from a rusqlite row.
700 /// Note that following variants of KeyParameterValue should not be stored:
701 /// IncludeUniqueID, ApplicationID, ApplicationData, RootOfTrust, UniqueID,
702 /// Attestation*, AssociatedData, Nonce, MacLength, ResetSinceIdRotation, ConfirmationToken.
703 /// This filtering is enforced at a higher level and here we support conversion for all the
704 /// variants.
705 pub fn new_from_sql(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700706 tag_val: Tag,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000707 data: &SqlField,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700708 security_level_val: SecurityLevel,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000709 ) -> Result<Self> {
Janis Danisevskise6efb242020-12-19 13:58:01 -0800710 Ok(Self {
711 value: KeyParameterValue::new_from_sql(tag_val, data)?,
712 security_level: security_level_val,
713 })
714 }
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000715
Janis Danisevskise6efb242020-12-19 13:58:01 -0800716 /// Get the KeyMint Tag of this this key parameter.
717 pub fn get_tag(&self) -> Tag {
718 self.value.get_tag()
719 }
720
721 /// Returns key parameter value.
722 pub fn key_parameter_value(&self) -> &KeyParameterValue {
723 &self.value
724 }
725
726 /// Returns the security level of this key parameter.
727 pub fn security_level(&self) -> &SecurityLevel {
728 &self.security_level
729 }
730
731 /// An authorization is a KeyParameter with an associated security level that is used
732 /// to convey the key characteristics to keystore clients. This function consumes
733 /// an internal KeyParameter representation to produce the Authorization wire type.
734 pub fn into_authorization(self) -> Authorization {
735 Authorization { securityLevel: self.security_level, keyParameter: self.value.into() }
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000736 }
737}
738
Janis Danisevskise6efb242020-12-19 13:58:01 -0800739#[cfg(test)]
740mod generated_key_parameter_tests {
741 use super::*;
742 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::TagType::TagType;
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +0000743
Janis Danisevskise6efb242020-12-19 13:58:01 -0800744 fn get_field_by_tag_type(tag: Tag) -> KmKeyParameterValue {
745 let tag_type = TagType((tag.0 as u32 & 0xF0000000) as i32);
746 match tag {
747 Tag::ALGORITHM => return KmKeyParameterValue::Algorithm(Default::default()),
748 Tag::BLOCK_MODE => return KmKeyParameterValue::BlockMode(Default::default()),
749 Tag::PADDING => return KmKeyParameterValue::PaddingMode(Default::default()),
750 Tag::DIGEST => return KmKeyParameterValue::Digest(Default::default()),
751 Tag::EC_CURVE => return KmKeyParameterValue::EcCurve(Default::default()),
752 Tag::ORIGIN => return KmKeyParameterValue::Origin(Default::default()),
753 Tag::PURPOSE => return KmKeyParameterValue::KeyPurpose(Default::default()),
754 Tag::USER_AUTH_TYPE => {
755 return KmKeyParameterValue::HardwareAuthenticatorType(Default::default())
756 }
757 Tag::HARDWARE_TYPE => return KmKeyParameterValue::SecurityLevel(Default::default()),
758 _ => {}
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700759 }
Janis Danisevskise6efb242020-12-19 13:58:01 -0800760 match tag_type {
761 TagType::INVALID => return KmKeyParameterValue::Invalid(Default::default()),
762 TagType::ENUM | TagType::ENUM_REP => {}
763 TagType::UINT | TagType::UINT_REP => {
764 return KmKeyParameterValue::Integer(Default::default())
765 }
766 TagType::ULONG | TagType::ULONG_REP => {
767 return KmKeyParameterValue::LongInteger(Default::default())
768 }
769 TagType::DATE => return KmKeyParameterValue::DateTime(Default::default()),
770 TagType::BOOL => return KmKeyParameterValue::BoolValue(Default::default()),
771 TagType::BIGNUM | TagType::BYTES => {
772 return KmKeyParameterValue::Blob(Default::default())
773 }
774 _ => {}
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700775 }
Janis Danisevskise6efb242020-12-19 13:58:01 -0800776 panic!("Unknown tag/tag_type: {:?} {:?}", tag, tag_type);
777 }
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +0000778
Janis Danisevskise6efb242020-12-19 13:58:01 -0800779 fn check_field_matches_tag_type(list_o_parameters: &[KmKeyParameter]) {
780 for kp in list_o_parameters.iter() {
781 match (&kp.value, get_field_by_tag_type(kp.tag)) {
782 (&KmKeyParameterValue::Algorithm(_), KmKeyParameterValue::Algorithm(_))
783 | (&KmKeyParameterValue::BlockMode(_), KmKeyParameterValue::BlockMode(_))
784 | (&KmKeyParameterValue::PaddingMode(_), KmKeyParameterValue::PaddingMode(_))
785 | (&KmKeyParameterValue::Digest(_), KmKeyParameterValue::Digest(_))
786 | (&KmKeyParameterValue::EcCurve(_), KmKeyParameterValue::EcCurve(_))
787 | (&KmKeyParameterValue::Origin(_), KmKeyParameterValue::Origin(_))
788 | (&KmKeyParameterValue::KeyPurpose(_), KmKeyParameterValue::KeyPurpose(_))
789 | (
790 &KmKeyParameterValue::HardwareAuthenticatorType(_),
791 KmKeyParameterValue::HardwareAuthenticatorType(_),
792 )
793 | (&KmKeyParameterValue::SecurityLevel(_), KmKeyParameterValue::SecurityLevel(_))
794 | (&KmKeyParameterValue::Invalid(_), KmKeyParameterValue::Invalid(_))
795 | (&KmKeyParameterValue::Integer(_), KmKeyParameterValue::Integer(_))
796 | (&KmKeyParameterValue::LongInteger(_), KmKeyParameterValue::LongInteger(_))
797 | (&KmKeyParameterValue::DateTime(_), KmKeyParameterValue::DateTime(_))
798 | (&KmKeyParameterValue::BoolValue(_), KmKeyParameterValue::BoolValue(_))
799 | (&KmKeyParameterValue::Blob(_), KmKeyParameterValue::Blob(_)) => {}
800 (actual, expected) => panic!(
801 "Tag {:?} associated with variant {:?} expected {:?}",
802 kp.tag, actual, expected
803 ),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700804 }
805 }
Janis Danisevskise6efb242020-12-19 13:58:01 -0800806 }
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +0000807
Janis Danisevskise6efb242020-12-19 13:58:01 -0800808 #[test]
809 fn key_parameter_value_field_matches_tag_type() {
810 check_field_matches_tag_type(&KeyParameterValue::make_field_matches_tag_type_test_vector());
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +0000811 }
812}
813
814#[cfg(test)]
815mod basic_tests {
816 use crate::key_parameter::*;
817
818 // Test basic functionality of KeyParameter.
819 #[test]
820 fn test_key_parameter() {
821 let key_parameter = KeyParameter::new(
822 KeyParameterValue::Algorithm(Algorithm::RSA),
823 SecurityLevel::STRONGBOX,
824 );
825
826 assert_eq!(key_parameter.get_tag(), Tag::ALGORITHM);
827
828 assert_eq!(
829 *key_parameter.key_parameter_value(),
830 KeyParameterValue::Algorithm(Algorithm::RSA)
831 );
832
833 assert_eq!(*key_parameter.security_level(), SecurityLevel::STRONGBOX);
834 }
835}
836
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000837/// The storage_tests module first tests the 'new_from_sql' method for KeyParameters of different
838/// data types and then tests 'to_sql' method for KeyParameters of those
839/// different data types. The five different data types for KeyParameter values are:
840/// i) enums of u32
841/// ii) u32
842/// iii) u64
843/// iv) Vec<u8>
844/// v) bool
845#[cfg(test)]
846mod storage_tests {
847 use crate::error::*;
848 use crate::key_parameter::*;
849 use anyhow::Result;
850 use rusqlite::types::ToSql;
851 use rusqlite::{params, Connection, NO_PARAMS};
852
853 /// Test initializing a KeyParameter (with key parameter value corresponding to an enum of i32)
854 /// from a database table row.
855 #[test]
856 fn test_new_from_sql_enum_i32() -> Result<()> {
857 let db = init_db()?;
858 insert_into_keyparameter(
859 &db,
860 1,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700861 Tag::ALGORITHM.0,
862 &Algorithm::RSA.0,
863 SecurityLevel::STRONGBOX.0,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000864 )?;
865 let key_param = query_from_keyparameter(&db)?;
866 assert_eq!(Tag::ALGORITHM, key_param.get_tag());
867 assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::Algorithm(Algorithm::RSA));
868 assert_eq!(*key_param.security_level(), SecurityLevel::STRONGBOX);
869 Ok(())
870 }
871
872 /// Test initializing a KeyParameter (with key parameter value which is of i32)
873 /// from a database table row.
874 #[test]
875 fn test_new_from_sql_i32() -> Result<()> {
876 let db = init_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700877 insert_into_keyparameter(&db, 1, Tag::KEY_SIZE.0, &1024, SecurityLevel::STRONGBOX.0)?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000878 let key_param = query_from_keyparameter(&db)?;
879 assert_eq!(Tag::KEY_SIZE, key_param.get_tag());
880 assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::KeySize(1024));
881 Ok(())
882 }
883
884 /// Test initializing a KeyParameter (with key parameter value which is of i64)
885 /// from a database table row.
886 #[test]
887 fn test_new_from_sql_i64() -> Result<()> {
888 let db = init_db()?;
889 // max value for i64, just to test corner cases
890 insert_into_keyparameter(
891 &db,
892 1,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700893 Tag::RSA_PUBLIC_EXPONENT.0,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000894 &(i64::MAX),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700895 SecurityLevel::STRONGBOX.0,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000896 )?;
897 let key_param = query_from_keyparameter(&db)?;
898 assert_eq!(Tag::RSA_PUBLIC_EXPONENT, key_param.get_tag());
899 assert_eq!(
900 *key_param.key_parameter_value(),
901 KeyParameterValue::RSAPublicExponent(i64::MAX)
902 );
903 Ok(())
904 }
905
906 /// Test initializing a KeyParameter (with key parameter value which is of bool)
907 /// from a database table row.
908 #[test]
909 fn test_new_from_sql_bool() -> Result<()> {
910 let db = init_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700911 insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE.0, &Null, SecurityLevel::STRONGBOX.0)?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000912 let key_param = query_from_keyparameter(&db)?;
913 assert_eq!(Tag::CALLER_NONCE, key_param.get_tag());
914 assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::CallerNonce);
915 Ok(())
916 }
917
918 /// Test initializing a KeyParameter (with key parameter value which is of Vec<u8>)
919 /// from a database table row.
920 #[test]
921 fn test_new_from_sql_vec_u8() -> Result<()> {
922 let db = init_db()?;
923 let app_id = String::from("MyAppID");
924 let app_id_bytes = app_id.into_bytes();
925 insert_into_keyparameter(
926 &db,
927 1,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700928 Tag::APPLICATION_ID.0,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000929 &app_id_bytes,
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700930 SecurityLevel::STRONGBOX.0,
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000931 )?;
932 let key_param = query_from_keyparameter(&db)?;
933 assert_eq!(Tag::APPLICATION_ID, key_param.get_tag());
934 assert_eq!(
935 *key_param.key_parameter_value(),
936 KeyParameterValue::ApplicationID(app_id_bytes)
937 );
938 Ok(())
939 }
940
941 /// Test storing a KeyParameter (with key parameter value which corresponds to an enum of i32)
942 /// in the database
943 #[test]
944 fn test_to_sql_enum_i32() -> Result<()> {
945 let db = init_db()?;
946 let kp = KeyParameter::new(
947 KeyParameterValue::Algorithm(Algorithm::RSA),
948 SecurityLevel::STRONGBOX,
949 );
950 store_keyparameter(&db, 1, &kp)?;
951 let key_param = query_from_keyparameter(&db)?;
952 assert_eq!(kp.get_tag(), key_param.get_tag());
953 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
954 assert_eq!(kp.security_level(), key_param.security_level());
955 Ok(())
956 }
957
958 /// Test storing a KeyParameter (with key parameter value which is of i32) in the database
959 #[test]
960 fn test_to_sql_i32() -> Result<()> {
961 let db = init_db()?;
962 let kp = KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::STRONGBOX);
963 store_keyparameter(&db, 1, &kp)?;
964 let key_param = query_from_keyparameter(&db)?;
965 assert_eq!(kp.get_tag(), key_param.get_tag());
966 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
967 assert_eq!(kp.security_level(), key_param.security_level());
968 Ok(())
969 }
970
971 /// Test storing a KeyParameter (with key parameter value which is of i64) in the database
972 #[test]
973 fn test_to_sql_i64() -> Result<()> {
974 let db = init_db()?;
975 // max value for i64, just to test corner cases
976 let kp = KeyParameter::new(
977 KeyParameterValue::RSAPublicExponent(i64::MAX),
978 SecurityLevel::STRONGBOX,
979 );
980 store_keyparameter(&db, 1, &kp)?;
981 let key_param = query_from_keyparameter(&db)?;
982 assert_eq!(kp.get_tag(), key_param.get_tag());
983 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
984 assert_eq!(kp.security_level(), key_param.security_level());
985 Ok(())
986 }
987
988 /// Test storing a KeyParameter (with key parameter value which is of Vec<u8>) in the database
989 #[test]
990 fn test_to_sql_vec_u8() -> Result<()> {
991 let db = init_db()?;
992 let kp = KeyParameter::new(
993 KeyParameterValue::ApplicationID(String::from("MyAppID").into_bytes()),
994 SecurityLevel::STRONGBOX,
995 );
996 store_keyparameter(&db, 1, &kp)?;
997 let key_param = query_from_keyparameter(&db)?;
998 assert_eq!(kp.get_tag(), key_param.get_tag());
999 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
1000 assert_eq!(kp.security_level(), key_param.security_level());
1001 Ok(())
1002 }
1003
1004 /// Test storing a KeyParameter (with key parameter value which is of i32) in the database
1005 #[test]
1006 fn test_to_sql_bool() -> Result<()> {
1007 let db = init_db()?;
1008 let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
1009 store_keyparameter(&db, 1, &kp)?;
1010 let key_param = query_from_keyparameter(&db)?;
1011 assert_eq!(kp.get_tag(), key_param.get_tag());
1012 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
1013 assert_eq!(kp.security_level(), key_param.security_level());
1014 Ok(())
1015 }
1016
1017 #[test]
1018 /// Test Tag::Invalid
1019 fn test_invalid_tag() -> Result<()> {
1020 let db = init_db()?;
1021 insert_into_keyparameter(&db, 1, 0, &123, 1)?;
1022 let key_param = query_from_keyparameter(&db)?;
1023 assert_eq!(Tag::INVALID, key_param.get_tag());
1024 Ok(())
1025 }
1026
1027 #[test]
1028 fn test_non_existing_enum_variant() -> Result<()> {
1029 let db = init_db()?;
1030 insert_into_keyparameter(&db, 1, 100, &123, 1)?;
Janis Danisevskise6efb242020-12-19 13:58:01 -08001031 let key_param = query_from_keyparameter(&db)?;
1032 assert_eq!(Tag::INVALID, key_param.get_tag());
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001033 Ok(())
1034 }
1035
1036 #[test]
1037 fn test_invalid_conversion_from_sql() -> Result<()> {
1038 let db = init_db()?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001039 insert_into_keyparameter(&db, 1, Tag::ALGORITHM.0, &Null, 1)?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001040 tests::check_result_contains_error_string(
1041 query_from_keyparameter(&db),
1042 "Failed to read sql data for tag: ALGORITHM.",
1043 );
1044 Ok(())
1045 }
1046
1047 /// Helper method to init database table for key parameter
1048 fn init_db() -> Result<Connection> {
1049 let db = Connection::open_in_memory().context("Failed to initialize sqlite connection.")?;
1050 db.execute("ATTACH DATABASE ? as 'persistent';", params![""])
1051 .context("Failed to attach databases.")?;
1052 db.execute(
1053 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
1054 keyentryid INTEGER,
1055 tag INTEGER,
1056 data ANY,
1057 security_level INTEGER);",
1058 NO_PARAMS,
1059 )
1060 .context("Failed to initialize \"keyparameter\" table.")?;
1061 Ok(db)
1062 }
1063
1064 /// Helper method to insert an entry into key parameter table, with individual parameters
1065 fn insert_into_keyparameter<T: ToSql>(
1066 db: &Connection,
1067 key_id: i64,
1068 tag: i32,
1069 value: &T,
1070 security_level: i32,
1071 ) -> Result<()> {
1072 db.execute(
1073 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001074 VALUES(?, ?, ?, ?);",
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001075 params![key_id, tag, *value, security_level],
1076 )?;
1077 Ok(())
1078 }
1079
1080 /// Helper method to store a key parameter instance.
1081 fn store_keyparameter(db: &Connection, key_id: i64, kp: &KeyParameter) -> Result<()> {
1082 db.execute(
1083 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001084 VALUES(?, ?, ?, ?);",
1085 params![key_id, kp.get_tag().0, kp.key_parameter_value(), kp.security_level().0],
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001086 )?;
1087 Ok(())
1088 }
1089
1090 /// Helper method to query a row from keyparameter table
1091 fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001092 let mut stmt =
1093 db.prepare("SELECT tag, data, security_level FROM persistent.keyparameter")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001094 let mut rows = stmt.query(NO_PARAMS)?;
1095 let row = rows.next()?.unwrap();
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001096 Ok(KeyParameter::new_from_sql(
1097 Tag(row.get(0)?),
Janis Danisevskis4522c2b2020-11-27 18:04:58 -08001098 &SqlField::new(1, row),
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001099 SecurityLevel(row.get(2)?),
1100 )?)
Hasini Gunasingheaf993662020-07-24 18:40:20 +00001101 }
1102}
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001103
1104/// The wire_tests module tests the 'convert_to_wire' and 'convert_from_wire' methods for
Janis Danisevskis85d47932020-10-23 16:12:59 -07001105/// KeyParameter, for the four different types used in KmKeyParameter, in addition to Invalid
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001106/// key parameter.
1107/// i) bool
1108/// ii) integer
1109/// iii) longInteger
Janis Danisevskis85d47932020-10-23 16:12:59 -07001110/// iv) blob
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001111#[cfg(test)]
1112mod wire_tests {
1113 use crate::key_parameter::*;
1114 /// unit tests for to conversions
1115 #[test]
1116 fn test_convert_to_wire_invalid() {
1117 let kp = KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::STRONGBOX);
Janis Danisevskise6efb242020-12-19 13:58:01 -08001118 assert_eq!(
1119 KmKeyParameter { tag: Tag::INVALID, value: KmKeyParameterValue::Invalid(0) },
1120 kp.value.into()
1121 );
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001122 }
1123 #[test]
1124 fn test_convert_to_wire_bool() {
1125 let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
Janis Danisevskise6efb242020-12-19 13:58:01 -08001126 assert_eq!(
1127 KmKeyParameter { tag: Tag::CALLER_NONCE, value: KmKeyParameterValue::BoolValue(true) },
1128 kp.value.into()
1129 );
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001130 }
1131 #[test]
1132 fn test_convert_to_wire_integer() {
1133 let kp = KeyParameter::new(
1134 KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
1135 SecurityLevel::STRONGBOX,
1136 );
Janis Danisevskise6efb242020-12-19 13:58:01 -08001137 assert_eq!(
1138 KmKeyParameter {
1139 tag: Tag::PURPOSE,
1140 value: KmKeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT)
1141 },
1142 kp.value.into()
1143 );
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001144 }
1145 #[test]
1146 fn test_convert_to_wire_long_integer() {
1147 let kp =
1148 KeyParameter::new(KeyParameterValue::UserSecureID(i64::MAX), SecurityLevel::STRONGBOX);
Janis Danisevskise6efb242020-12-19 13:58:01 -08001149 assert_eq!(
1150 KmKeyParameter {
1151 tag: Tag::USER_SECURE_ID,
1152 value: KmKeyParameterValue::LongInteger(i64::MAX)
1153 },
1154 kp.value.into()
1155 );
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001156 }
1157 #[test]
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001158 fn test_convert_to_wire_blob() {
1159 let kp = KeyParameter::new(
1160 KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
1161 SecurityLevel::STRONGBOX,
1162 );
Janis Danisevskis398e6be2020-12-17 09:29:25 -08001163 assert_eq!(
Janis Danisevskise6efb242020-12-19 13:58:01 -08001164 KmKeyParameter {
1165 tag: Tag::CONFIRMATION_TOKEN,
1166 value: KmKeyParameterValue::Blob(String::from("ConfirmationToken").into_bytes())
1167 },
1168 kp.value.into()
Janis Danisevskis398e6be2020-12-17 09:29:25 -08001169 );
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001170 }
1171
1172 /// unit tests for from conversion
1173 #[test]
1174 fn test_convert_from_wire_invalid() {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001175 let aidl_kp = KmKeyParameter { tag: Tag::INVALID, ..Default::default() };
Janis Danisevskise6efb242020-12-19 13:58:01 -08001176 assert_eq!(KeyParameterValue::Invalid, aidl_kp.into());
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001177 }
1178 #[test]
1179 fn test_convert_from_wire_bool() {
1180 let aidl_kp =
Janis Danisevskis398e6be2020-12-17 09:29:25 -08001181 KmKeyParameter { tag: Tag::CALLER_NONCE, value: KmKeyParameterValue::BoolValue(true) };
Janis Danisevskise6efb242020-12-19 13:58:01 -08001182 assert_eq!(KeyParameterValue::CallerNonce, aidl_kp.into());
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001183 }
1184 #[test]
1185 fn test_convert_from_wire_integer() {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001186 let aidl_kp = KmKeyParameter {
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001187 tag: Tag::PURPOSE,
Janis Danisevskis398e6be2020-12-17 09:29:25 -08001188 value: KmKeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001189 };
Janis Danisevskise6efb242020-12-19 13:58:01 -08001190 assert_eq!(KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT), aidl_kp.into());
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001191 }
1192 #[test]
1193 fn test_convert_from_wire_long_integer() {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001194 let aidl_kp = KmKeyParameter {
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001195 tag: Tag::USER_SECURE_ID,
Janis Danisevskis398e6be2020-12-17 09:29:25 -08001196 value: KmKeyParameterValue::LongInteger(i64::MAX),
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001197 };
Janis Danisevskise6efb242020-12-19 13:58:01 -08001198 assert_eq!(KeyParameterValue::UserSecureID(i64::MAX), aidl_kp.into());
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001199 }
1200 #[test]
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001201 fn test_convert_from_wire_blob() {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001202 let aidl_kp = KmKeyParameter {
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001203 tag: Tag::CONFIRMATION_TOKEN,
Janis Danisevskis398e6be2020-12-17 09:29:25 -08001204 value: KmKeyParameterValue::Blob(String::from("ConfirmationToken").into_bytes()),
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001205 };
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001206 assert_eq!(
1207 KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
Janis Danisevskise6efb242020-12-19 13:58:01 -08001208 aidl_kp.into()
Hasini Gunasinghe3eb77c22020-08-28 15:45:06 +00001209 );
1210 }
1211}