blob: ae3d774565fcfae3083176252246962a2bb12851 [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
15//! KeyParameter is used to express different characteristics of a key requested by the user
16//! and enforced by the OEMs. This module implements the internal representation of KeyParameter
17//! and the methods to work with KeyParameter.
18
Hasini Gunasingheaf993662020-07-24 18:40:20 +000019use crate::error::Error as KeystoreError;
Janis Danisevskise24f3472020-08-12 17:58:49 -070020use crate::error::Rc;
Hasini Gunasingheaf993662020-07-24 18:40:20 +000021pub use android_hardware_keymint::aidl::android::hardware::keymint::{
22 Algorithm, Algorithm::Algorithm as AlgorithmType, BlockMode,
23 BlockMode::BlockMode as BlockModeType, Digest, Digest::Digest as DigestType, EcCurve,
24 EcCurve::EcCurve as EcCurveType, HardwareAuthenticatorType,
25 HardwareAuthenticatorType::HardwareAuthenticatorType as HardwareAuthenticatorTypeType,
26 KeyOrigin, KeyOrigin::KeyOrigin as KeyOriginType, KeyPurpose,
27 KeyPurpose::KeyPurpose as KeyPurposeType, PaddingMode,
28 PaddingMode::PaddingMode as PaddingModeType, SecurityLevel,
29 SecurityLevel::SecurityLevel as SecurityLevelType, Tag, Tag::Tag as TagType,
Hasini Gunasinghe12486362020-07-24 18:40:20 +000030};
Hasini Gunasingheaf993662020-07-24 18:40:20 +000031use anyhow::{Context, Result};
32use rusqlite::types::{FromSql, Null, ToSql, ToSqlOutput};
33use rusqlite::{Result as SqlResult, Row};
Hasini Gunasinghe12486362020-07-24 18:40:20 +000034
35/// KeyParameter wraps the KeyParameterValue and the security level at which it is enforced.
Janis Danisevskis3f322cb2020-09-03 14:46:22 -070036#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
Hasini Gunasinghe12486362020-07-24 18:40:20 +000037pub struct KeyParameter {
38 key_parameter_value: KeyParameterValue,
Hasini Gunasingheaf993662020-07-24 18:40:20 +000039 security_level: SecurityLevelType,
Hasini Gunasinghe12486362020-07-24 18:40:20 +000040}
41
42/// KeyParameterValue holds a value corresponding to one of the Tags defined in
43/// the AIDL spec at hardware/interfaces/keymint
Janis Danisevskis3f322cb2020-09-03 14:46:22 -070044#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
Hasini Gunasinghe12486362020-07-24 18:40:20 +000045pub enum KeyParameterValue {
46 /// Associated with Tag:INVALID
47 Invalid,
48 /// Set of purposes for which the key may be used
Hasini Gunasingheaf993662020-07-24 18:40:20 +000049 KeyPurpose(KeyPurposeType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000050 /// Cryptographic algorithm with which the key is used
Hasini Gunasingheaf993662020-07-24 18:40:20 +000051 Algorithm(AlgorithmType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000052 /// Size of the key , in bits
Hasini Gunasingheaf993662020-07-24 18:40:20 +000053 KeySize(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000054 /// Block cipher mode(s) with which the key may be used
Hasini Gunasingheaf993662020-07-24 18:40:20 +000055 BlockMode(BlockModeType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000056 /// Digest algorithms that may be used with the key to perform signing and verification
Hasini Gunasingheaf993662020-07-24 18:40:20 +000057 Digest(DigestType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000058 /// Padding modes that may be used with the key. Relevant to RSA, AES and 3DES keys.
Hasini Gunasingheaf993662020-07-24 18:40:20 +000059 PaddingMode(PaddingModeType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000060 /// Can the caller provide a nonce for nonce-requiring operations
61 CallerNonce,
62 /// Minimum length of MAC for HMAC keys and AES keys that support GCM mode
Hasini Gunasingheaf993662020-07-24 18:40:20 +000063 MinMacLength(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000064 /// The elliptic curve
Hasini Gunasingheaf993662020-07-24 18:40:20 +000065 EcCurve(EcCurveType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000066 /// Value of the public exponent for an RSA key pair
Hasini Gunasingheaf993662020-07-24 18:40:20 +000067 RSAPublicExponent(i64),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000068 /// An attestation certificate for the generated key should contain an application-scoped
69 /// and time-bounded device-unique ID
70 IncludeUniqueID,
Hasini Gunasingheaf993662020-07-24 18:40:20 +000071 //TODO: find out about this
72 // /// Necessary system environment conditions for the generated key to be used
73 // KeyBlobUsageRequirements(KeyBlobUsageRequirements),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000074 /// Only the boot loader can use the key
75 BootLoaderOnly,
76 /// When deleted, the key is guaranteed to be permanently deleted and unusable
77 RollbackResistance,
Hasini Gunasinghe12486362020-07-24 18:40:20 +000078 /// The date and time at which the key becomes active
Hasini Gunasingheaf993662020-07-24 18:40:20 +000079 ActiveDateTime(i64),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000080 /// The date and time at which the key expires for signing and encryption
Hasini Gunasingheaf993662020-07-24 18:40:20 +000081 OriginationExpireDateTime(i64),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000082 /// The date and time at which the key expires for verification and decryption
Hasini Gunasingheaf993662020-07-24 18:40:20 +000083 UsageExpireDateTime(i64),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000084 /// Minimum amount of time that elapses between allowed operations
Hasini Gunasingheaf993662020-07-24 18:40:20 +000085 MinSecondsBetweenOps(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000086 /// Maximum number of times that a key may be used between system reboots
Hasini Gunasingheaf993662020-07-24 18:40:20 +000087 MaxUsesPerBoot(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000088 /// ID of the Android user that is permitted to use the key
Hasini Gunasingheaf993662020-07-24 18:40:20 +000089 UserID(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000090 /// A key may only be used under a particular secure user authentication state
Hasini Gunasingheaf993662020-07-24 18:40:20 +000091 UserSecureID(i64),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000092 /// No authentication is required to use this key
93 NoAuthRequired,
94 /// The types of user authenticators that may be used to authorize this key
Hasini Gunasingheaf993662020-07-24 18:40:20 +000095 HardwareAuthenticatorType(HardwareAuthenticatorTypeType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000096 /// The time in seconds for which the key is authorized for use, after user authentication
Hasini Gunasingheaf993662020-07-24 18:40:20 +000097 AuthTimeout(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +000098 /// The key may be used after authentication timeout if device is still on-body
99 AllowWhileOnBody,
100 /// The key must be unusable except when the user has provided proof of physical presence
101 TrustedUserPresenceRequired,
102 /// Applicable to keys with KeyPurpose SIGN, and specifies that this key must not be usable
103 /// unless the user provides confirmation of the data to be signed
104 TrustedConfirmationRequired,
105 /// The key may only be used when the device is unlocked
106 UnlockedDeviceRequired,
107 /// When provided to generateKey or importKey, this tag specifies data
108 /// that is necessary during all uses of the key
109 ApplicationID(Vec<u8>),
110 /// When provided to generateKey or importKey, this tag specifies data
111 /// that is necessary during all uses of the key
112 ApplicationData(Vec<u8>),
113 /// Specifies the date and time the key was created
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000114 CreationDateTime(i64),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000115 /// Specifies where the key was created, if known
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000116 KeyOrigin(KeyOriginType),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000117 /// The key used by verified boot to validate the operating system booted
118 RootOfTrust(Vec<u8>),
119 /// System OS version with which the key may be used
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000120 OSVersion(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000121 /// Specifies the system security patch level with which the key may be used
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000122 OSPatchLevel(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000123 /// Specifies a unique, time-based identifier
124 UniqueID(Vec<u8>),
125 /// Used to deliver a "challenge" value to the attestKey() method
126 AttestationChallenge(Vec<u8>),
127 /// The set of applications which may use a key, used only with attestKey()
128 AttestationApplicationID(Vec<u8>),
129 /// Provides the device's brand name, to attestKey()
130 AttestationIdBrand(Vec<u8>),
131 /// Provides the device's device name, to attestKey()
132 AttestationIdDevice(Vec<u8>),
133 /// Provides the device's product name, to attestKey()
134 AttestationIdProduct(Vec<u8>),
135 /// Provides the device's serial number, to attestKey()
136 AttestationIdSerial(Vec<u8>),
137 /// Provides the IMEIs for all radios on the device, to attestKey()
138 AttestationIdIMEI(Vec<u8>),
139 /// Provides the MEIDs for all radios on the device, to attestKey()
140 AttestationIdMEID(Vec<u8>),
141 /// Provides the device's manufacturer name, to attestKey()
142 AttestationIdManufacturer(Vec<u8>),
143 /// Provides the device's model name, to attestKey()
144 AttestationIdModel(Vec<u8>),
145 /// Specifies the vendor image security patch level with which the key may be used
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000146 VendorPatchLevel(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000147 /// Specifies the boot image (kernel) security patch level with which the key may be used
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000148 BootPatchLevel(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000149 /// Provides "associated data" for AES-GCM encryption or decryption
150 AssociatedData(Vec<u8>),
151 /// Provides or returns a nonce or Initialization Vector (IV) for AES-GCM,
152 /// AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption
153 Nonce(Vec<u8>),
154 /// Provides the requested length of a MAC or GCM authentication tag, in bits
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000155 MacLength(i32),
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000156 /// Specifies whether the device has been factory reset since the
157 /// last unique ID rotation. Used for key attestation
158 ResetSinceIdRotation,
159 /// Used to deliver a cryptographic token proving that the user
160 /// confirmed a signing request
161 ConfirmationToken(Vec<u8>),
162}
163
164impl KeyParameter {
165 /// Create an instance of KeyParameter, given the value and the security level.
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000166 pub fn new(key_parameter_value: KeyParameterValue, security_level: SecurityLevelType) -> Self {
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000167 KeyParameter { key_parameter_value, security_level }
168 }
169
170 /// Returns the tag given the KeyParameter instance.
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000171 pub fn get_tag(&self) -> TagType {
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000172 match self.key_parameter_value {
173 KeyParameterValue::Invalid => Tag::INVALID,
174 KeyParameterValue::KeyPurpose(_) => Tag::PURPOSE,
175 KeyParameterValue::Algorithm(_) => Tag::ALGORITHM,
176 KeyParameterValue::KeySize(_) => Tag::KEY_SIZE,
177 KeyParameterValue::BlockMode(_) => Tag::BLOCK_MODE,
178 KeyParameterValue::Digest(_) => Tag::DIGEST,
179 KeyParameterValue::PaddingMode(_) => Tag::PADDING,
180 KeyParameterValue::CallerNonce => Tag::CALLER_NONCE,
181 KeyParameterValue::MinMacLength(_) => Tag::MIN_MAC_LENGTH,
182 KeyParameterValue::EcCurve(_) => Tag::EC_CURVE,
183 KeyParameterValue::RSAPublicExponent(_) => Tag::RSA_PUBLIC_EXPONENT,
184 KeyParameterValue::IncludeUniqueID => Tag::INCLUDE_UNIQUE_ID,
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000185 KeyParameterValue::BootLoaderOnly => Tag::BOOTLOADER_ONLY,
186 KeyParameterValue::RollbackResistance => Tag::ROLLBACK_RESISTANCE,
187 KeyParameterValue::ActiveDateTime(_) => Tag::ACTIVE_DATETIME,
188 KeyParameterValue::OriginationExpireDateTime(_) => Tag::ORIGINATION_EXPIRE_DATETIME,
189 KeyParameterValue::UsageExpireDateTime(_) => Tag::USAGE_EXPIRE_DATETIME,
190 KeyParameterValue::MinSecondsBetweenOps(_) => Tag::MIN_SECONDS_BETWEEN_OPS,
191 KeyParameterValue::MaxUsesPerBoot(_) => Tag::MAX_USES_PER_BOOT,
192 KeyParameterValue::UserID(_) => Tag::USER_ID,
193 KeyParameterValue::UserSecureID(_) => Tag::USER_SECURE_ID,
194 KeyParameterValue::NoAuthRequired => Tag::NO_AUTH_REQUIRED,
195 KeyParameterValue::HardwareAuthenticatorType(_) => Tag::USER_AUTH_TYPE,
196 KeyParameterValue::AuthTimeout(_) => Tag::AUTH_TIMEOUT,
197 KeyParameterValue::AllowWhileOnBody => Tag::ALLOW_WHILE_ON_BODY,
198 KeyParameterValue::TrustedUserPresenceRequired => Tag::TRUSTED_USER_PRESENCE_REQUIRED,
199 KeyParameterValue::TrustedConfirmationRequired => Tag::TRUSTED_CONFIRMATION_REQUIRED,
200 KeyParameterValue::UnlockedDeviceRequired => Tag::UNLOCKED_DEVICE_REQUIRED,
201 KeyParameterValue::ApplicationID(_) => Tag::APPLICATION_ID,
202 KeyParameterValue::ApplicationData(_) => Tag::APPLICATION_DATA,
203 KeyParameterValue::CreationDateTime(_) => Tag::CREATION_DATETIME,
204 KeyParameterValue::KeyOrigin(_) => Tag::ORIGIN,
205 KeyParameterValue::RootOfTrust(_) => Tag::ROOT_OF_TRUST,
206 KeyParameterValue::OSVersion(_) => Tag::OS_VERSION,
207 KeyParameterValue::OSPatchLevel(_) => Tag::OS_PATCHLEVEL,
208 KeyParameterValue::UniqueID(_) => Tag::UNIQUE_ID,
209 KeyParameterValue::AttestationChallenge(_) => Tag::ATTESTATION_CHALLENGE,
210 KeyParameterValue::AttestationApplicationID(_) => Tag::ATTESTATION_APPLICATION_ID,
211 KeyParameterValue::AttestationIdBrand(_) => Tag::ATTESTATION_ID_BRAND,
212 KeyParameterValue::AttestationIdDevice(_) => Tag::ATTESTATION_ID_DEVICE,
213 KeyParameterValue::AttestationIdProduct(_) => Tag::ATTESTATION_ID_PRODUCT,
214 KeyParameterValue::AttestationIdSerial(_) => Tag::ATTESTATION_ID_SERIAL,
215 KeyParameterValue::AttestationIdIMEI(_) => Tag::ATTESTATION_ID_IMEI,
216 KeyParameterValue::AttestationIdMEID(_) => Tag::ATTESTATION_ID_MEID,
217 KeyParameterValue::AttestationIdManufacturer(_) => Tag::ATTESTATION_ID_MANUFACTURER,
218 KeyParameterValue::AttestationIdModel(_) => Tag::ATTESTATION_ID_MODEL,
219 KeyParameterValue::VendorPatchLevel(_) => Tag::VENDOR_PATCHLEVEL,
220 KeyParameterValue::BootPatchLevel(_) => Tag::BOOT_PATCHLEVEL,
221 KeyParameterValue::AssociatedData(_) => Tag::ASSOCIATED_DATA,
222 KeyParameterValue::Nonce(_) => Tag::NONCE,
223 KeyParameterValue::MacLength(_) => Tag::MAC_LENGTH,
224 KeyParameterValue::ResetSinceIdRotation => Tag::RESET_SINCE_ID_ROTATION,
225 KeyParameterValue::ConfirmationToken(_) => Tag::CONFIRMATION_TOKEN,
226 }
227 }
228
229 /// Returns key parameter value.
230 pub fn key_parameter_value(&self) -> &KeyParameterValue {
231 &self.key_parameter_value
232 }
233
234 /// Returns the security level of a KeyParameter.
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000235 pub fn security_level(&self) -> &SecurityLevelType {
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000236 &self.security_level
237 }
238}
239
240#[cfg(test)]
241mod basic_tests {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700242 use super::*;
Hasini Gunasinghe12486362020-07-24 18:40:20 +0000243
244 // Test basic functionality of KeyParameter.
245 #[test]
246 fn test_key_parameter() {
247 let key_parameter = KeyParameter::new(
248 KeyParameterValue::Algorithm(Algorithm::RSA),
249 SecurityLevel::STRONGBOX,
250 );
251
252 assert_eq!(key_parameter.get_tag(), Tag::ALGORITHM);
253
254 assert_eq!(
255 *key_parameter.key_parameter_value(),
256 KeyParameterValue::Algorithm(Algorithm::RSA)
257 );
258
259 assert_eq!(*key_parameter.security_level(), SecurityLevel::STRONGBOX);
260 }
261}
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000262
263/// This struct is defined to postpone converting rusqlite column value to the
264/// appropriate key parameter value until we know the corresponding tag value.
265/// Wraps the column index and a rusqlite row.
266pub struct SqlField<'a>(usize, &'a Row<'a>);
267
268impl<'a> SqlField<'a> {
Janis Danisevskis3f322cb2020-09-03 14:46:22 -0700269 /// Creates a new SqlField with the given index and row.
270 pub fn new(index: usize, row: &'a Row<'a>) -> Self {
271 Self(index, row)
272 }
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000273 /// Returns the column value from the row, when we know the expected type.
274 pub fn get<T: FromSql>(&self) -> SqlResult<T> {
275 self.1.get(self.0)
276 }
277}
278
279impl ToSql for KeyParameterValue {
280 /// Converts KeyParameterValue to be stored in rusqlite database.
281 /// Note that following variants of KeyParameterValue should not be stored:
282 /// IncludeUniqueID, ApplicationID, ApplicationData, RootOfTrust, UniqueID,
283 /// Attestation*, AssociatedData, Nonce, MacLength, ResetSinceIdRotation, ConfirmationToken.
284 /// This filtering is enforced at a higher level (i.e. enforcement module) and here we support
285 /// conversion for all the variants, to keep error handling simple.
286 fn to_sql(&self) -> SqlResult<ToSqlOutput> {
287 match self {
288 KeyParameterValue::Invalid => Ok(ToSqlOutput::from(Null)),
289 KeyParameterValue::KeyPurpose(k) => Ok(ToSqlOutput::from(*k as u32)),
290 KeyParameterValue::Algorithm(a) => Ok(ToSqlOutput::from(*a as u32)),
291 KeyParameterValue::KeySize(k) => Ok(ToSqlOutput::from(*k)),
292 KeyParameterValue::BlockMode(b) => Ok(ToSqlOutput::from(*b as u32)),
293 KeyParameterValue::Digest(d) => Ok(ToSqlOutput::from(*d as u32)),
294 KeyParameterValue::PaddingMode(p) => Ok(ToSqlOutput::from(*p as u32)),
295 KeyParameterValue::CallerNonce => Ok(ToSqlOutput::from(Null)),
296 KeyParameterValue::MinMacLength(m) => Ok(ToSqlOutput::from(*m)),
297 KeyParameterValue::EcCurve(e) => Ok(ToSqlOutput::from(*e as u32)),
298 KeyParameterValue::RSAPublicExponent(r) => Ok(ToSqlOutput::from(*r as i64)),
299 KeyParameterValue::IncludeUniqueID => Ok(ToSqlOutput::from(Null)),
300 KeyParameterValue::BootLoaderOnly => Ok(ToSqlOutput::from(Null)),
301 KeyParameterValue::RollbackResistance => Ok(ToSqlOutput::from(Null)),
302 KeyParameterValue::ActiveDateTime(a) => Ok(ToSqlOutput::from(*a as i64)),
303 KeyParameterValue::OriginationExpireDateTime(o) => Ok(ToSqlOutput::from(*o as i64)),
304 KeyParameterValue::UsageExpireDateTime(u) => Ok(ToSqlOutput::from(*u as i64)),
305 KeyParameterValue::MinSecondsBetweenOps(m) => Ok(ToSqlOutput::from(*m)),
306 KeyParameterValue::MaxUsesPerBoot(m) => Ok(ToSqlOutput::from(*m)),
307 KeyParameterValue::UserID(u) => Ok(ToSqlOutput::from(*u)),
308 KeyParameterValue::UserSecureID(u) => Ok(ToSqlOutput::from(*u as i64)),
309 KeyParameterValue::NoAuthRequired => Ok(ToSqlOutput::from(Null)),
310 KeyParameterValue::HardwareAuthenticatorType(h) => Ok(ToSqlOutput::from(*h as u32)),
311 KeyParameterValue::AuthTimeout(m) => Ok(ToSqlOutput::from(*m)),
312 KeyParameterValue::AllowWhileOnBody => Ok(ToSqlOutput::from(Null)),
313 KeyParameterValue::TrustedUserPresenceRequired => Ok(ToSqlOutput::from(Null)),
314 KeyParameterValue::TrustedConfirmationRequired => Ok(ToSqlOutput::from(Null)),
315 KeyParameterValue::UnlockedDeviceRequired => Ok(ToSqlOutput::from(Null)),
316 KeyParameterValue::ApplicationID(a) => Ok(ToSqlOutput::from(a.to_vec())),
317 KeyParameterValue::ApplicationData(a) => Ok(ToSqlOutput::from(a.to_vec())),
318 KeyParameterValue::CreationDateTime(c) => Ok(ToSqlOutput::from(*c as i64)),
319 KeyParameterValue::KeyOrigin(k) => Ok(ToSqlOutput::from(*k as u32)),
320 KeyParameterValue::RootOfTrust(r) => Ok(ToSqlOutput::from(r.to_vec())),
321 KeyParameterValue::OSVersion(o) => Ok(ToSqlOutput::from(*o)),
322 KeyParameterValue::OSPatchLevel(o) => Ok(ToSqlOutput::from(*o)),
323 KeyParameterValue::UniqueID(u) => Ok(ToSqlOutput::from(u.to_vec())),
324 KeyParameterValue::AttestationChallenge(a) => Ok(ToSqlOutput::from(a.to_vec())),
325 KeyParameterValue::AttestationApplicationID(a) => Ok(ToSqlOutput::from(a.to_vec())),
326 KeyParameterValue::AttestationIdBrand(a) => Ok(ToSqlOutput::from(a.to_vec())),
327 KeyParameterValue::AttestationIdDevice(a) => Ok(ToSqlOutput::from(a.to_vec())),
328 KeyParameterValue::AttestationIdProduct(a) => Ok(ToSqlOutput::from(a.to_vec())),
329 KeyParameterValue::AttestationIdSerial(a) => Ok(ToSqlOutput::from(a.to_vec())),
330 KeyParameterValue::AttestationIdIMEI(a) => Ok(ToSqlOutput::from(a.to_vec())),
331 KeyParameterValue::AttestationIdMEID(a) => Ok(ToSqlOutput::from(a.to_vec())),
332 KeyParameterValue::AttestationIdManufacturer(a) => Ok(ToSqlOutput::from(a.to_vec())),
333 KeyParameterValue::AttestationIdModel(a) => Ok(ToSqlOutput::from(a.to_vec())),
334 KeyParameterValue::VendorPatchLevel(v) => Ok(ToSqlOutput::from(*v)),
335 KeyParameterValue::BootPatchLevel(b) => Ok(ToSqlOutput::from(*b)),
336 KeyParameterValue::AssociatedData(a) => Ok(ToSqlOutput::from(a.to_vec())),
337 KeyParameterValue::Nonce(n) => Ok(ToSqlOutput::from(n.to_vec())),
338 KeyParameterValue::MacLength(m) => Ok(ToSqlOutput::from(*m)),
339 KeyParameterValue::ResetSinceIdRotation => Ok(ToSqlOutput::from(Null)),
340 KeyParameterValue::ConfirmationToken(c) => Ok(ToSqlOutput::from(c.to_vec())),
341 }
342 }
343}
344
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000345impl KeyParameter {
346 /// Construct a KeyParameter from the data from a rusqlite row.
347 /// Note that following variants of KeyParameterValue should not be stored:
348 /// IncludeUniqueID, ApplicationID, ApplicationData, RootOfTrust, UniqueID,
349 /// Attestation*, AssociatedData, Nonce, MacLength, ResetSinceIdRotation, ConfirmationToken.
350 /// This filtering is enforced at a higher level and here we support conversion for all the
351 /// variants.
352 pub fn new_from_sql(
353 tag_val: TagType,
354 data: &SqlField,
355 security_level_val: SecurityLevelType,
356 ) -> Result<Self> {
357 let key_param_value = match tag_val {
358 Tag::INVALID => KeyParameterValue::Invalid,
359 Tag::PURPOSE => {
360 let key_purpose: KeyPurposeType = data
361 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700362 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700363 .context("Failed to read sql data for tag: PURPOSE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000364 KeyParameterValue::KeyPurpose(key_purpose)
365 }
366 Tag::ALGORITHM => {
367 let algorithm: AlgorithmType = data
368 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700369 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700370 .context("Failed to read sql data for tag: ALGORITHM.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000371 KeyParameterValue::Algorithm(algorithm)
372 }
373 Tag::KEY_SIZE => {
374 let key_size: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700375 data.get().context("Failed to read sql data for tag: KEY_SIZE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000376 KeyParameterValue::KeySize(key_size)
377 }
378 Tag::BLOCK_MODE => {
379 let block_mode: BlockModeType = data
380 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700381 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700382 .context("Failed to read sql data for tag: BLOCK_MODE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000383 KeyParameterValue::BlockMode(block_mode)
384 }
385 Tag::DIGEST => {
386 let digest: DigestType = data
387 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700388 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700389 .context("Failed to read sql data for tag: DIGEST.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000390 KeyParameterValue::Digest(digest)
391 }
392 Tag::PADDING => {
393 let padding: PaddingModeType = data
394 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700395 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700396 .context("Failed to read sql data for tag: PADDING.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000397 KeyParameterValue::PaddingMode(padding)
398 }
399 Tag::CALLER_NONCE => KeyParameterValue::CallerNonce,
400 Tag::MIN_MAC_LENGTH => {
401 let min_mac_length: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700402 data.get().context("Failed to read sql data for tag: MIN_MAC_LENGTH.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000403 KeyParameterValue::MinMacLength(min_mac_length)
404 }
405 Tag::EC_CURVE => {
406 let ec_curve: EcCurveType = data
407 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700408 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700409 .context("Failed to read sql data for tag: EC_CURVE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000410 KeyParameterValue::EcCurve(ec_curve)
411 }
412 Tag::RSA_PUBLIC_EXPONENT => {
413 let rsa_pub_exponent: i64 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700414 data.get().context("Failed to read sql data for tag: RSA_PUBLIC_EXPONENT.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000415
416 KeyParameterValue::RSAPublicExponent(rsa_pub_exponent)
417 }
418 Tag::INCLUDE_UNIQUE_ID => KeyParameterValue::IncludeUniqueID,
419 Tag::BOOTLOADER_ONLY => KeyParameterValue::BootLoaderOnly,
420 Tag::ROLLBACK_RESISTANCE => KeyParameterValue::RollbackResistance,
421 Tag::ACTIVE_DATETIME => {
422 let active_datetime: i64 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700423 data.get().context("Failed to read sql data for tag: ACTIVE_DATETIME.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000424 KeyParameterValue::ActiveDateTime(active_datetime)
425 }
426 Tag::ORIGINATION_EXPIRE_DATETIME => {
427 let origination_expire_datetime: i64 = data
428 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700429 .context("Failed to read sql data for tag: ORIGINATION_EXPIRE_DATETIME.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000430 KeyParameterValue::OriginationExpireDateTime(origination_expire_datetime)
431 }
432 Tag::USAGE_EXPIRE_DATETIME => {
433 let usage_expire_datetime: i64 = data
434 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700435 .context("Failed to read sql data for tag: USAGE_EXPIRE_DATETIME.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000436 KeyParameterValue::UsageExpireDateTime(usage_expire_datetime)
437 }
438 Tag::MIN_SECONDS_BETWEEN_OPS => {
439 let min_secs_between_ops: i32 = data
440 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700441 .context("Failed to read sql data for tag: MIN_SECONDS_BETWEEN_OPS.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000442 KeyParameterValue::MinSecondsBetweenOps(min_secs_between_ops)
443 }
444 Tag::MAX_USES_PER_BOOT => {
445 let max_uses_per_boot: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700446 data.get().context("Failed to read sql data for tag: MAX_USES_PER_BOOT.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000447 KeyParameterValue::MaxUsesPerBoot(max_uses_per_boot)
448 }
449 Tag::USER_ID => {
450 let user_id: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700451 data.get().context("Failed to read sql data for tag: USER_ID.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000452 KeyParameterValue::UserID(user_id)
453 }
454 Tag::USER_SECURE_ID => {
455 let user_secure_id: i64 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700456 data.get().context("Failed to read sql data for tag: USER_SECURE_ID.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000457 KeyParameterValue::UserSecureID(user_secure_id)
458 }
459 Tag::NO_AUTH_REQUIRED => KeyParameterValue::NoAuthRequired,
460 Tag::USER_AUTH_TYPE => {
461 let user_auth_type: HardwareAuthenticatorTypeType = data
462 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700463 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700464 .context("Failed to read sql data for tag: USER_AUTH_TYPE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000465 KeyParameterValue::HardwareAuthenticatorType(user_auth_type)
466 }
467 Tag::AUTH_TIMEOUT => {
468 let auth_timeout: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700469 data.get().context("Failed to read sql data for tag: AUTH_TIMEOUT.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000470 KeyParameterValue::AuthTimeout(auth_timeout)
471 }
472 Tag::ALLOW_WHILE_ON_BODY => KeyParameterValue::AllowWhileOnBody,
473 Tag::TRUSTED_USER_PRESENCE_REQUIRED => KeyParameterValue::TrustedUserPresenceRequired,
474 Tag::TRUSTED_CONFIRMATION_REQUIRED => KeyParameterValue::TrustedConfirmationRequired,
475 Tag::UNLOCKED_DEVICE_REQUIRED => KeyParameterValue::UnlockedDeviceRequired,
476 Tag::APPLICATION_ID => {
477 let app_id: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700478 data.get().context("Failed to read sql data for tag: APPLICATION_ID.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000479 KeyParameterValue::ApplicationID(app_id)
480 }
481 Tag::APPLICATION_DATA => {
482 let app_data: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700483 data.get().context("Failed to read sql data for tag: APPLICATION_DATA.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000484 KeyParameterValue::ApplicationData(app_data)
485 }
486 Tag::CREATION_DATETIME => {
487 let creation_datetime: i64 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700488 data.get().context("Failed to read sql data for tag: CREATION_DATETIME.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000489 KeyParameterValue::CreationDateTime(creation_datetime)
490 }
491 Tag::ORIGIN => {
492 let origin: KeyOriginType = data
493 .get()
Janis Danisevskise24f3472020-08-12 17:58:49 -0700494 .map_err(|_| KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700495 .context("Failed to read sql data for tag: ORIGIN.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000496 KeyParameterValue::KeyOrigin(origin)
497 }
498 Tag::ROOT_OF_TRUST => {
499 let root_of_trust: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700500 data.get().context("Failed to read sql data for tag: ROOT_OF_TRUST.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000501 KeyParameterValue::RootOfTrust(root_of_trust)
502 }
503 Tag::OS_VERSION => {
504 let os_version: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700505 data.get().context("Failed to read sql data for tag: OS_VERSION.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000506 KeyParameterValue::OSVersion(os_version)
507 }
508 Tag::OS_PATCHLEVEL => {
509 let os_patch_level: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700510 data.get().context("Failed to read sql data for tag: OS_PATCHLEVEL.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000511 KeyParameterValue::OSPatchLevel(os_patch_level)
512 }
513 Tag::UNIQUE_ID => {
514 let unique_id: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700515 data.get().context("Failed to read sql data for tag: UNIQUE_ID.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000516 KeyParameterValue::UniqueID(unique_id)
517 }
518 Tag::ATTESTATION_CHALLENGE => {
519 let attestation_challenge: Vec<u8> = data
520 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700521 .context("Failed to read sql data for tag: ATTESTATION_CHALLENGE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000522 KeyParameterValue::AttestationChallenge(attestation_challenge)
523 }
524 Tag::ATTESTATION_APPLICATION_ID => {
525 let attestation_app_id: Vec<u8> = data
526 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700527 .context("Failed to read sql data for tag: ATTESTATION_APPLICATION_ID.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000528 KeyParameterValue::AttestationApplicationID(attestation_app_id)
529 }
530 Tag::ATTESTATION_ID_BRAND => {
531 let attestation_id_brand: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700532 data.get().context("Failed to read sql data for tag: ATTESTATION_ID_BRAND.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000533 KeyParameterValue::AttestationIdBrand(attestation_id_brand)
534 }
535 Tag::ATTESTATION_ID_DEVICE => {
536 let attestation_id_device: Vec<u8> = data
537 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700538 .context("Failed to read sql data for tag: ATTESTATION_ID_DEVICE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000539 KeyParameterValue::AttestationIdDevice(attestation_id_device)
540 }
541 Tag::ATTESTATION_ID_PRODUCT => {
542 let attestation_id_product: Vec<u8> = data
543 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700544 .context("Failed to read sql data for tag: ATTESTATION_ID_PRODUCT.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000545 KeyParameterValue::AttestationIdProduct(attestation_id_product)
546 }
547 Tag::ATTESTATION_ID_SERIAL => {
548 let attestation_id_serial: Vec<u8> = data
549 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700550 .context("Failed to read sql data for tag: ATTESTATION_ID_SERIAL.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000551 KeyParameterValue::AttestationIdSerial(attestation_id_serial)
552 }
553 Tag::ATTESTATION_ID_IMEI => {
554 let attestation_id_imei: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700555 data.get().context("Failed to read sql data for tag: ATTESTATION_ID_IMEI.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000556 KeyParameterValue::AttestationIdIMEI(attestation_id_imei)
557 }
558 Tag::ATTESTATION_ID_MEID => {
559 let attestation_id_meid: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700560 data.get().context("Failed to read sql data for tag: ATTESTATION_ID_MEID.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000561 KeyParameterValue::AttestationIdMEID(attestation_id_meid)
562 }
563 Tag::ATTESTATION_ID_MANUFACTURER => {
564 let attestation_id_manufacturer: Vec<u8> = data
565 .get()
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700566 .context("Failed to read sql data for tag: ATTESTATION_ID_MANUFACTURER.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000567 KeyParameterValue::AttestationIdManufacturer(attestation_id_manufacturer)
568 }
569 Tag::ATTESTATION_ID_MODEL => {
570 let attestation_id_model: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700571 data.get().context("Failed to read sql data for tag: ATTESTATION_ID_MODEL.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000572 KeyParameterValue::AttestationIdModel(attestation_id_model)
573 }
574 Tag::VENDOR_PATCHLEVEL => {
575 let vendor_patch_level: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700576 data.get().context("Failed to read sql data for tag: VENDOR_PATCHLEVEL.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000577 KeyParameterValue::VendorPatchLevel(vendor_patch_level)
578 }
579 Tag::BOOT_PATCHLEVEL => {
580 let boot_patch_level: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700581 data.get().context("Failed to read sql data for tag: BOOT_PATCHLEVEL.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000582 KeyParameterValue::BootPatchLevel(boot_patch_level)
583 }
584 Tag::ASSOCIATED_DATA => {
585 let associated_data: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700586 data.get().context("Failed to read sql data for tag: ASSOCIATED_DATA.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000587 KeyParameterValue::AssociatedData(associated_data)
588 }
589 Tag::NONCE => {
590 let nonce: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700591 data.get().context("Failed to read sql data for tag: NONCE.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000592 KeyParameterValue::Nonce(nonce)
593 }
594 Tag::MAC_LENGTH => {
595 let mac_length: i32 =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700596 data.get().context("Failed to read sql data for tag: MAC_LENGTH.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000597 KeyParameterValue::MacLength(mac_length)
598 }
599 Tag::RESET_SINCE_ID_ROTATION => KeyParameterValue::ResetSinceIdRotation,
600 Tag::CONFIRMATION_TOKEN => {
601 let confirmation_token: Vec<u8> =
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700602 data.get().context("Failed to read sql data for tag: CONFIRMATION_TOKEN.")?;
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000603 KeyParameterValue::ConfirmationToken(confirmation_token)
604 }
605 _ => {
Janis Danisevskise24f3472020-08-12 17:58:49 -0700606 return Err(KeystoreError::Rc(Rc::ValueCorrupted))
Joel Galenson5c0ec0d2020-09-02 14:24:30 -0700607 .context("Failed to decode Tag enum from value.")?
Hasini Gunasingheaf993662020-07-24 18:40:20 +0000608 }
609 };
610 Ok(KeyParameter::new(key_param_value, security_level_val))
611 }
612}
613
614/// The storage_tests module first tests the 'new_from_sql' method for KeyParameters of different
615/// data types and then tests 'to_sql' method for KeyParameters of those
616/// different data types. The five different data types for KeyParameter values are:
617/// i) enums of u32
618/// ii) u32
619/// iii) u64
620/// iv) Vec<u8>
621/// v) bool
622#[cfg(test)]
623mod storage_tests {
624 use crate::error::*;
625 use crate::key_parameter::*;
626 use anyhow::Result;
627 use rusqlite::types::ToSql;
628 use rusqlite::{params, Connection, NO_PARAMS};
629
630 /// Test initializing a KeyParameter (with key parameter value corresponding to an enum of i32)
631 /// from a database table row.
632 #[test]
633 fn test_new_from_sql_enum_i32() -> Result<()> {
634 let db = init_db()?;
635 insert_into_keyparameter(
636 &db,
637 1,
638 Tag::ALGORITHM,
639 &Algorithm::RSA,
640 SecurityLevel::STRONGBOX,
641 )?;
642 let key_param = query_from_keyparameter(&db)?;
643 assert_eq!(Tag::ALGORITHM, key_param.get_tag());
644 assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::Algorithm(Algorithm::RSA));
645 assert_eq!(*key_param.security_level(), SecurityLevel::STRONGBOX);
646 Ok(())
647 }
648
649 /// Test initializing a KeyParameter (with key parameter value which is of i32)
650 /// from a database table row.
651 #[test]
652 fn test_new_from_sql_i32() -> Result<()> {
653 let db = init_db()?;
654 insert_into_keyparameter(&db, 1, Tag::KEY_SIZE, &1024, SecurityLevel::STRONGBOX)?;
655 let key_param = query_from_keyparameter(&db)?;
656 assert_eq!(Tag::KEY_SIZE, key_param.get_tag());
657 assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::KeySize(1024));
658 Ok(())
659 }
660
661 /// Test initializing a KeyParameter (with key parameter value which is of i64)
662 /// from a database table row.
663 #[test]
664 fn test_new_from_sql_i64() -> Result<()> {
665 let db = init_db()?;
666 // max value for i64, just to test corner cases
667 insert_into_keyparameter(
668 &db,
669 1,
670 Tag::RSA_PUBLIC_EXPONENT,
671 &(i64::MAX),
672 SecurityLevel::STRONGBOX,
673 )?;
674 let key_param = query_from_keyparameter(&db)?;
675 assert_eq!(Tag::RSA_PUBLIC_EXPONENT, key_param.get_tag());
676 assert_eq!(
677 *key_param.key_parameter_value(),
678 KeyParameterValue::RSAPublicExponent(i64::MAX)
679 );
680 Ok(())
681 }
682
683 /// Test initializing a KeyParameter (with key parameter value which is of bool)
684 /// from a database table row.
685 #[test]
686 fn test_new_from_sql_bool() -> Result<()> {
687 let db = init_db()?;
688 insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE, &Null, SecurityLevel::STRONGBOX)?;
689 let key_param = query_from_keyparameter(&db)?;
690 assert_eq!(Tag::CALLER_NONCE, key_param.get_tag());
691 assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::CallerNonce);
692 Ok(())
693 }
694
695 /// Test initializing a KeyParameter (with key parameter value which is of Vec<u8>)
696 /// from a database table row.
697 #[test]
698 fn test_new_from_sql_vec_u8() -> Result<()> {
699 let db = init_db()?;
700 let app_id = String::from("MyAppID");
701 let app_id_bytes = app_id.into_bytes();
702 insert_into_keyparameter(
703 &db,
704 1,
705 Tag::APPLICATION_ID,
706 &app_id_bytes,
707 SecurityLevel::STRONGBOX,
708 )?;
709 let key_param = query_from_keyparameter(&db)?;
710 assert_eq!(Tag::APPLICATION_ID, key_param.get_tag());
711 assert_eq!(
712 *key_param.key_parameter_value(),
713 KeyParameterValue::ApplicationID(app_id_bytes)
714 );
715 Ok(())
716 }
717
718 /// Test storing a KeyParameter (with key parameter value which corresponds to an enum of i32)
719 /// in the database
720 #[test]
721 fn test_to_sql_enum_i32() -> Result<()> {
722 let db = init_db()?;
723 let kp = KeyParameter::new(
724 KeyParameterValue::Algorithm(Algorithm::RSA),
725 SecurityLevel::STRONGBOX,
726 );
727 store_keyparameter(&db, 1, &kp)?;
728 let key_param = query_from_keyparameter(&db)?;
729 assert_eq!(kp.get_tag(), key_param.get_tag());
730 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
731 assert_eq!(kp.security_level(), key_param.security_level());
732 Ok(())
733 }
734
735 /// Test storing a KeyParameter (with key parameter value which is of i32) in the database
736 #[test]
737 fn test_to_sql_i32() -> Result<()> {
738 let db = init_db()?;
739 let kp = KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::STRONGBOX);
740 store_keyparameter(&db, 1, &kp)?;
741 let key_param = query_from_keyparameter(&db)?;
742 assert_eq!(kp.get_tag(), key_param.get_tag());
743 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
744 assert_eq!(kp.security_level(), key_param.security_level());
745 Ok(())
746 }
747
748 /// Test storing a KeyParameter (with key parameter value which is of i64) in the database
749 #[test]
750 fn test_to_sql_i64() -> Result<()> {
751 let db = init_db()?;
752 // max value for i64, just to test corner cases
753 let kp = KeyParameter::new(
754 KeyParameterValue::RSAPublicExponent(i64::MAX),
755 SecurityLevel::STRONGBOX,
756 );
757 store_keyparameter(&db, 1, &kp)?;
758 let key_param = query_from_keyparameter(&db)?;
759 assert_eq!(kp.get_tag(), key_param.get_tag());
760 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
761 assert_eq!(kp.security_level(), key_param.security_level());
762 Ok(())
763 }
764
765 /// Test storing a KeyParameter (with key parameter value which is of Vec<u8>) in the database
766 #[test]
767 fn test_to_sql_vec_u8() -> Result<()> {
768 let db = init_db()?;
769 let kp = KeyParameter::new(
770 KeyParameterValue::ApplicationID(String::from("MyAppID").into_bytes()),
771 SecurityLevel::STRONGBOX,
772 );
773 store_keyparameter(&db, 1, &kp)?;
774 let key_param = query_from_keyparameter(&db)?;
775 assert_eq!(kp.get_tag(), key_param.get_tag());
776 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
777 assert_eq!(kp.security_level(), key_param.security_level());
778 Ok(())
779 }
780
781 /// Test storing a KeyParameter (with key parameter value which is of i32) in the database
782 #[test]
783 fn test_to_sql_bool() -> Result<()> {
784 let db = init_db()?;
785 let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
786 store_keyparameter(&db, 1, &kp)?;
787 let key_param = query_from_keyparameter(&db)?;
788 assert_eq!(kp.get_tag(), key_param.get_tag());
789 assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
790 assert_eq!(kp.security_level(), key_param.security_level());
791 Ok(())
792 }
793
794 #[test]
795 /// Test Tag::Invalid
796 fn test_invalid_tag() -> Result<()> {
797 let db = init_db()?;
798 insert_into_keyparameter(&db, 1, 0, &123, 1)?;
799 let key_param = query_from_keyparameter(&db)?;
800 assert_eq!(Tag::INVALID, key_param.get_tag());
801 Ok(())
802 }
803
804 #[test]
805 fn test_non_existing_enum_variant() -> Result<()> {
806 let db = init_db()?;
807 insert_into_keyparameter(&db, 1, 100, &123, 1)?;
808 tests::check_result_contains_error_string(
809 query_from_keyparameter(&db),
810 "Failed to decode Tag enum from value.",
811 );
812 Ok(())
813 }
814
815 #[test]
816 fn test_invalid_conversion_from_sql() -> Result<()> {
817 let db = init_db()?;
818 insert_into_keyparameter(&db, 1, Tag::ALGORITHM, &Null, 1)?;
819 tests::check_result_contains_error_string(
820 query_from_keyparameter(&db),
821 "Failed to read sql data for tag: ALGORITHM.",
822 );
823 Ok(())
824 }
825
826 /// Helper method to init database table for key parameter
827 fn init_db() -> Result<Connection> {
828 let db = Connection::open_in_memory().context("Failed to initialize sqlite connection.")?;
829 db.execute("ATTACH DATABASE ? as 'persistent';", params![""])
830 .context("Failed to attach databases.")?;
831 db.execute(
832 "CREATE TABLE IF NOT EXISTS persistent.keyparameter (
833 keyentryid INTEGER,
834 tag INTEGER,
835 data ANY,
836 security_level INTEGER);",
837 NO_PARAMS,
838 )
839 .context("Failed to initialize \"keyparameter\" table.")?;
840 Ok(db)
841 }
842
843 /// Helper method to insert an entry into key parameter table, with individual parameters
844 fn insert_into_keyparameter<T: ToSql>(
845 db: &Connection,
846 key_id: i64,
847 tag: i32,
848 value: &T,
849 security_level: i32,
850 ) -> Result<()> {
851 db.execute(
852 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
853VALUES(?, ?, ?, ?);",
854 params![key_id, tag, *value, security_level],
855 )?;
856 Ok(())
857 }
858
859 /// Helper method to store a key parameter instance.
860 fn store_keyparameter(db: &Connection, key_id: i64, kp: &KeyParameter) -> Result<()> {
861 db.execute(
862 "INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
863VALUES(?, ?, ?, ?);",
864 params![key_id, kp.get_tag(), kp.key_parameter_value(), kp.security_level()],
865 )?;
866 Ok(())
867 }
868
869 /// Helper method to query a row from keyparameter table
870 fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
871 let mut stmt = db.prepare(
872 "SELECT tag, data, security_level FROM
873persistent.keyparameter",
874 )?;
875 let mut rows = stmt.query(NO_PARAMS)?;
876 let row = rows.next()?.unwrap();
877 Ok(KeyParameter::new_from_sql(row.get(0)?, &SqlField(1, row), row.get(2)?)?)
878 }
879}