blob: 5698c964db4187eb479a674b29abd462528946d1 [file] [log] [blame]
// Copyright 2020, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! KeyParameter is used to express different characteristics of a key requested by the user
//! and enforced by the OEMs. This module implements the internal representation of KeyParameter
//! and the methods to work with KeyParameter.
use crate::error::Error as KeystoreError;
use crate::error::ResponseCode;
pub use android_hardware_keymint::aidl::android::hardware::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
KeyParameter::KeyParameter as KmKeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
SecurityLevel::SecurityLevel, Tag::Tag,
};
use android_system_keystore2::aidl::android::system::keystore2::Authorization::Authorization;
use anyhow::{Context, Result};
use rusqlite::types::{FromSql, Null, ToSql, ToSqlOutput};
use rusqlite::{Result as SqlResult, Row};
/// KeyParameter wraps the KeyParameterValue and the security level at which it is enforced.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct KeyParameter {
key_parameter_value: KeyParameterValue,
security_level: SecurityLevel,
}
/// KeyParameterValue holds a value corresponding to one of the Tags defined in
/// the AIDL spec at hardware/interfaces/keymint
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum KeyParameterValue {
/// Associated with Tag:INVALID
Invalid,
/// Set of purposes for which the key may be used
KeyPurpose(KeyPurpose),
/// Cryptographic algorithm with which the key is used
Algorithm(Algorithm),
/// Size of the key , in bits
KeySize(i32),
/// Block cipher mode(s) with which the key may be used
BlockMode(BlockMode),
/// Digest algorithms that may be used with the key to perform signing and verification
Digest(Digest),
/// Padding modes that may be used with the key. Relevant to RSA, AES and 3DES keys.
PaddingMode(PaddingMode),
/// Can the caller provide a nonce for nonce-requiring operations
CallerNonce,
/// Minimum length of MAC for HMAC keys and AES keys that support GCM mode
MinMacLength(i32),
/// The elliptic curve
EcCurve(EcCurve),
/// Value of the public exponent for an RSA key pair
RSAPublicExponent(i64),
/// An attestation certificate for the generated key should contain an application-scoped
/// and time-bounded device-unique ID
IncludeUniqueID,
//TODO: find out about this
// /// Necessary system environment conditions for the generated key to be used
// KeyBlobUsageRequirements(KeyBlobUsageRequirements),
/// Only the boot loader can use the key
BootLoaderOnly,
/// When deleted, the key is guaranteed to be permanently deleted and unusable
RollbackResistance,
/// The date and time at which the key becomes active
ActiveDateTime(i64),
/// The date and time at which the key expires for signing and encryption
OriginationExpireDateTime(i64),
/// The date and time at which the key expires for verification and decryption
UsageExpireDateTime(i64),
/// Minimum amount of time that elapses between allowed operations
MinSecondsBetweenOps(i32),
/// Maximum number of times that a key may be used between system reboots
MaxUsesPerBoot(i32),
/// ID of the Android user that is permitted to use the key
UserID(i32),
/// A key may only be used under a particular secure user authentication state
UserSecureID(i64),
/// No authentication is required to use this key
NoAuthRequired,
/// The types of user authenticators that may be used to authorize this key
HardwareAuthenticatorType(HardwareAuthenticatorType),
/// The time in seconds for which the key is authorized for use, after user authentication
AuthTimeout(i32),
/// The key may be used after authentication timeout if device is still on-body
AllowWhileOnBody,
/// The key must be unusable except when the user has provided proof of physical presence
TrustedUserPresenceRequired,
/// Applicable to keys with KeyPurpose SIGN, and specifies that this key must not be usable
/// unless the user provides confirmation of the data to be signed
TrustedConfirmationRequired,
/// The key may only be used when the device is unlocked
UnlockedDeviceRequired,
/// When provided to generateKey or importKey, this tag specifies data
/// that is necessary during all uses of the key
ApplicationID(Vec<u8>),
/// When provided to generateKey or importKey, this tag specifies data
/// that is necessary during all uses of the key
ApplicationData(Vec<u8>),
/// Specifies the date and time the key was created
CreationDateTime(i64),
/// Specifies where the key was created, if known
KeyOrigin(KeyOrigin),
/// The key used by verified boot to validate the operating system booted
RootOfTrust(Vec<u8>),
/// System OS version with which the key may be used
OSVersion(i32),
/// Specifies the system security patch level with which the key may be used
OSPatchLevel(i32),
/// Specifies a unique, time-based identifier
UniqueID(Vec<u8>),
/// Used to deliver a "challenge" value to the attestKey() method
AttestationChallenge(Vec<u8>),
/// The set of applications which may use a key, used only with attestKey()
AttestationApplicationID(Vec<u8>),
/// Provides the device's brand name, to attestKey()
AttestationIdBrand(Vec<u8>),
/// Provides the device's device name, to attestKey()
AttestationIdDevice(Vec<u8>),
/// Provides the device's product name, to attestKey()
AttestationIdProduct(Vec<u8>),
/// Provides the device's serial number, to attestKey()
AttestationIdSerial(Vec<u8>),
/// Provides the IMEIs for all radios on the device, to attestKey()
AttestationIdIMEI(Vec<u8>),
/// Provides the MEIDs for all radios on the device, to attestKey()
AttestationIdMEID(Vec<u8>),
/// Provides the device's manufacturer name, to attestKey()
AttestationIdManufacturer(Vec<u8>),
/// Provides the device's model name, to attestKey()
AttestationIdModel(Vec<u8>),
/// Specifies the vendor image security patch level with which the key may be used
VendorPatchLevel(i32),
/// Specifies the boot image (kernel) security patch level with which the key may be used
BootPatchLevel(i32),
/// Provides "associated data" for AES-GCM encryption or decryption
AssociatedData(Vec<u8>),
/// Provides or returns a nonce or Initialization Vector (IV) for AES-GCM,
/// AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption
Nonce(Vec<u8>),
/// Provides the requested length of a MAC or GCM authentication tag, in bits
MacLength(i32),
/// Specifies whether the device has been factory reset since the
/// last unique ID rotation. Used for key attestation
ResetSinceIdRotation,
/// Used to deliver a cryptographic token proving that the user
/// confirmed a signing request
ConfirmationToken(Vec<u8>),
}
impl KeyParameter {
/// Create an instance of KeyParameter, given the value and the security level.
pub fn new(key_parameter_value: KeyParameterValue, security_level: SecurityLevel) -> Self {
KeyParameter { key_parameter_value, security_level }
}
/// Returns the tag given the KeyParameter instance.
pub fn get_tag(&self) -> Tag {
match self.key_parameter_value {
KeyParameterValue::Invalid => Tag::INVALID,
KeyParameterValue::KeyPurpose(_) => Tag::PURPOSE,
KeyParameterValue::Algorithm(_) => Tag::ALGORITHM,
KeyParameterValue::KeySize(_) => Tag::KEY_SIZE,
KeyParameterValue::BlockMode(_) => Tag::BLOCK_MODE,
KeyParameterValue::Digest(_) => Tag::DIGEST,
KeyParameterValue::PaddingMode(_) => Tag::PADDING,
KeyParameterValue::CallerNonce => Tag::CALLER_NONCE,
KeyParameterValue::MinMacLength(_) => Tag::MIN_MAC_LENGTH,
KeyParameterValue::EcCurve(_) => Tag::EC_CURVE,
KeyParameterValue::RSAPublicExponent(_) => Tag::RSA_PUBLIC_EXPONENT,
KeyParameterValue::IncludeUniqueID => Tag::INCLUDE_UNIQUE_ID,
KeyParameterValue::BootLoaderOnly => Tag::BOOTLOADER_ONLY,
KeyParameterValue::RollbackResistance => Tag::ROLLBACK_RESISTANCE,
KeyParameterValue::ActiveDateTime(_) => Tag::ACTIVE_DATETIME,
KeyParameterValue::OriginationExpireDateTime(_) => Tag::ORIGINATION_EXPIRE_DATETIME,
KeyParameterValue::UsageExpireDateTime(_) => Tag::USAGE_EXPIRE_DATETIME,
KeyParameterValue::MinSecondsBetweenOps(_) => Tag::MIN_SECONDS_BETWEEN_OPS,
KeyParameterValue::MaxUsesPerBoot(_) => Tag::MAX_USES_PER_BOOT,
KeyParameterValue::UserID(_) => Tag::USER_ID,
KeyParameterValue::UserSecureID(_) => Tag::USER_SECURE_ID,
KeyParameterValue::NoAuthRequired => Tag::NO_AUTH_REQUIRED,
KeyParameterValue::HardwareAuthenticatorType(_) => Tag::USER_AUTH_TYPE,
KeyParameterValue::AuthTimeout(_) => Tag::AUTH_TIMEOUT,
KeyParameterValue::AllowWhileOnBody => Tag::ALLOW_WHILE_ON_BODY,
KeyParameterValue::TrustedUserPresenceRequired => Tag::TRUSTED_USER_PRESENCE_REQUIRED,
KeyParameterValue::TrustedConfirmationRequired => Tag::TRUSTED_CONFIRMATION_REQUIRED,
KeyParameterValue::UnlockedDeviceRequired => Tag::UNLOCKED_DEVICE_REQUIRED,
KeyParameterValue::ApplicationID(_) => Tag::APPLICATION_ID,
KeyParameterValue::ApplicationData(_) => Tag::APPLICATION_DATA,
KeyParameterValue::CreationDateTime(_) => Tag::CREATION_DATETIME,
KeyParameterValue::KeyOrigin(_) => Tag::ORIGIN,
KeyParameterValue::RootOfTrust(_) => Tag::ROOT_OF_TRUST,
KeyParameterValue::OSVersion(_) => Tag::OS_VERSION,
KeyParameterValue::OSPatchLevel(_) => Tag::OS_PATCHLEVEL,
KeyParameterValue::UniqueID(_) => Tag::UNIQUE_ID,
KeyParameterValue::AttestationChallenge(_) => Tag::ATTESTATION_CHALLENGE,
KeyParameterValue::AttestationApplicationID(_) => Tag::ATTESTATION_APPLICATION_ID,
KeyParameterValue::AttestationIdBrand(_) => Tag::ATTESTATION_ID_BRAND,
KeyParameterValue::AttestationIdDevice(_) => Tag::ATTESTATION_ID_DEVICE,
KeyParameterValue::AttestationIdProduct(_) => Tag::ATTESTATION_ID_PRODUCT,
KeyParameterValue::AttestationIdSerial(_) => Tag::ATTESTATION_ID_SERIAL,
KeyParameterValue::AttestationIdIMEI(_) => Tag::ATTESTATION_ID_IMEI,
KeyParameterValue::AttestationIdMEID(_) => Tag::ATTESTATION_ID_MEID,
KeyParameterValue::AttestationIdManufacturer(_) => Tag::ATTESTATION_ID_MANUFACTURER,
KeyParameterValue::AttestationIdModel(_) => Tag::ATTESTATION_ID_MODEL,
KeyParameterValue::VendorPatchLevel(_) => Tag::VENDOR_PATCHLEVEL,
KeyParameterValue::BootPatchLevel(_) => Tag::BOOT_PATCHLEVEL,
KeyParameterValue::AssociatedData(_) => Tag::ASSOCIATED_DATA,
KeyParameterValue::Nonce(_) => Tag::NONCE,
KeyParameterValue::MacLength(_) => Tag::MAC_LENGTH,
KeyParameterValue::ResetSinceIdRotation => Tag::RESET_SINCE_ID_ROTATION,
KeyParameterValue::ConfirmationToken(_) => Tag::CONFIRMATION_TOKEN,
}
}
/// Returns key parameter value.
pub fn key_parameter_value(&self) -> &KeyParameterValue {
&self.key_parameter_value
}
/// Returns the security level of a KeyParameter.
pub fn security_level(&self) -> &SecurityLevel {
&self.security_level
}
/// An authorization is a KeyParameter with an associated security level that is used
/// to convey the key characteristics to keystore clients. This function consumes
/// an internal KeyParameter representation to produce the Authorization wire type.
pub fn into_authorization(self) -> Authorization {
Authorization {
securityLevel: self.security_level,
keyParameter: self.key_parameter_value.convert_to_wire(),
}
}
}
/// This struct is defined to postpone converting rusqlite column value to the
/// appropriate key parameter value until we know the corresponding tag value.
/// Wraps the column index and a rusqlite row.
pub struct SqlField<'a>(usize, &'a Row<'a>);
impl<'a> SqlField<'a> {
/// Creates a new SqlField with the given index and row.
pub fn new(index: usize, row: &'a Row<'a>) -> Self {
Self(index, row)
}
/// Returns the column value from the row, when we know the expected type.
pub fn get<T: FromSql>(&self) -> SqlResult<T> {
self.1.get(self.0)
}
}
impl ToSql for KeyParameterValue {
/// Converts KeyParameterValue to be stored in rusqlite database.
/// Note that following variants of KeyParameterValue should not be stored:
/// IncludeUniqueID, ApplicationID, ApplicationData, RootOfTrust, UniqueID,
/// Attestation*, AssociatedData, Nonce, MacLength, ResetSinceIdRotation, ConfirmationToken.
/// This filtering is enforced at a higher level (i.e. enforcement module) and here we support
/// conversion for all the variants, to keep error handling simple.
fn to_sql(&self) -> SqlResult<ToSqlOutput> {
match self {
KeyParameterValue::Invalid => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::KeyPurpose(k) => Ok(ToSqlOutput::from(k.0 as u32)),
KeyParameterValue::Algorithm(a) => Ok(ToSqlOutput::from(a.0 as u32)),
KeyParameterValue::KeySize(k) => Ok(ToSqlOutput::from(*k)),
KeyParameterValue::BlockMode(b) => Ok(ToSqlOutput::from(b.0 as u32)),
KeyParameterValue::Digest(d) => Ok(ToSqlOutput::from(d.0 as u32)),
KeyParameterValue::PaddingMode(p) => Ok(ToSqlOutput::from(p.0 as u32)),
KeyParameterValue::CallerNonce => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::MinMacLength(m) => Ok(ToSqlOutput::from(*m)),
KeyParameterValue::EcCurve(e) => Ok(ToSqlOutput::from(e.0 as u32)),
KeyParameterValue::RSAPublicExponent(r) => Ok(ToSqlOutput::from(*r as i64)),
KeyParameterValue::IncludeUniqueID => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::BootLoaderOnly => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::RollbackResistance => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::ActiveDateTime(a) => Ok(ToSqlOutput::from(*a as i64)),
KeyParameterValue::OriginationExpireDateTime(o) => Ok(ToSqlOutput::from(*o as i64)),
KeyParameterValue::UsageExpireDateTime(u) => Ok(ToSqlOutput::from(*u as i64)),
KeyParameterValue::MinSecondsBetweenOps(m) => Ok(ToSqlOutput::from(*m)),
KeyParameterValue::MaxUsesPerBoot(m) => Ok(ToSqlOutput::from(*m)),
KeyParameterValue::UserID(u) => Ok(ToSqlOutput::from(*u)),
KeyParameterValue::UserSecureID(u) => Ok(ToSqlOutput::from(*u as i64)),
KeyParameterValue::NoAuthRequired => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::HardwareAuthenticatorType(h) => Ok(ToSqlOutput::from(h.0 as u32)),
KeyParameterValue::AuthTimeout(m) => Ok(ToSqlOutput::from(*m)),
KeyParameterValue::AllowWhileOnBody => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::TrustedUserPresenceRequired => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::TrustedConfirmationRequired => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::UnlockedDeviceRequired => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::ApplicationID(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::ApplicationData(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::CreationDateTime(c) => Ok(ToSqlOutput::from(*c as i64)),
KeyParameterValue::KeyOrigin(k) => Ok(ToSqlOutput::from(k.0 as u32)),
KeyParameterValue::RootOfTrust(r) => Ok(ToSqlOutput::from(r.to_vec())),
KeyParameterValue::OSVersion(o) => Ok(ToSqlOutput::from(*o)),
KeyParameterValue::OSPatchLevel(o) => Ok(ToSqlOutput::from(*o)),
KeyParameterValue::UniqueID(u) => Ok(ToSqlOutput::from(u.to_vec())),
KeyParameterValue::AttestationChallenge(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationApplicationID(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdBrand(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdDevice(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdProduct(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdSerial(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdIMEI(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdMEID(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdManufacturer(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::AttestationIdModel(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::VendorPatchLevel(v) => Ok(ToSqlOutput::from(*v)),
KeyParameterValue::BootPatchLevel(b) => Ok(ToSqlOutput::from(*b)),
KeyParameterValue::AssociatedData(a) => Ok(ToSqlOutput::from(a.to_vec())),
KeyParameterValue::Nonce(n) => Ok(ToSqlOutput::from(n.to_vec())),
KeyParameterValue::MacLength(m) => Ok(ToSqlOutput::from(*m)),
KeyParameterValue::ResetSinceIdRotation => Ok(ToSqlOutput::from(Null)),
KeyParameterValue::ConfirmationToken(c) => Ok(ToSqlOutput::from(c.to_vec())),
}
}
}
impl KeyParameter {
/// Construct a KeyParameter from the data from a rusqlite row.
/// Note that following variants of KeyParameterValue should not be stored:
/// IncludeUniqueID, ApplicationID, ApplicationData, RootOfTrust, UniqueID,
/// Attestation*, AssociatedData, Nonce, MacLength, ResetSinceIdRotation, ConfirmationToken.
/// This filtering is enforced at a higher level and here we support conversion for all the
/// variants.
pub fn new_from_sql(
tag_val: Tag,
data: &SqlField,
security_level_val: SecurityLevel,
) -> Result<Self> {
let key_param_value = match tag_val {
Tag::INVALID => KeyParameterValue::Invalid,
Tag::PURPOSE => {
let key_purpose: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: PURPOSE.")?;
KeyParameterValue::KeyPurpose(KeyPurpose(key_purpose))
}
Tag::ALGORITHM => {
let algorithm: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: ALGORITHM.")?;
KeyParameterValue::Algorithm(Algorithm(algorithm))
}
Tag::KEY_SIZE => {
let key_size: i32 =
data.get().context("Failed to read sql data for tag: KEY_SIZE.")?;
KeyParameterValue::KeySize(key_size)
}
Tag::BLOCK_MODE => {
let block_mode: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: BLOCK_MODE.")?;
KeyParameterValue::BlockMode(BlockMode(block_mode))
}
Tag::DIGEST => {
let digest: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: DIGEST.")?;
KeyParameterValue::Digest(Digest(digest))
}
Tag::PADDING => {
let padding: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: PADDING.")?;
KeyParameterValue::PaddingMode(PaddingMode(padding))
}
Tag::CALLER_NONCE => KeyParameterValue::CallerNonce,
Tag::MIN_MAC_LENGTH => {
let min_mac_length: i32 =
data.get().context("Failed to read sql data for tag: MIN_MAC_LENGTH.")?;
KeyParameterValue::MinMacLength(min_mac_length)
}
Tag::EC_CURVE => {
let ec_curve: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: EC_CURVE.")?;
KeyParameterValue::EcCurve(EcCurve(ec_curve))
}
Tag::RSA_PUBLIC_EXPONENT => {
let rsa_pub_exponent: i64 =
data.get().context("Failed to read sql data for tag: RSA_PUBLIC_EXPONENT.")?;
KeyParameterValue::RSAPublicExponent(rsa_pub_exponent)
}
Tag::INCLUDE_UNIQUE_ID => KeyParameterValue::IncludeUniqueID,
Tag::BOOTLOADER_ONLY => KeyParameterValue::BootLoaderOnly,
Tag::ROLLBACK_RESISTANCE => KeyParameterValue::RollbackResistance,
Tag::ACTIVE_DATETIME => {
let active_datetime: i64 =
data.get().context("Failed to read sql data for tag: ACTIVE_DATETIME.")?;
KeyParameterValue::ActiveDateTime(active_datetime)
}
Tag::ORIGINATION_EXPIRE_DATETIME => {
let origination_expire_datetime: i64 = data
.get()
.context("Failed to read sql data for tag: ORIGINATION_EXPIRE_DATETIME.")?;
KeyParameterValue::OriginationExpireDateTime(origination_expire_datetime)
}
Tag::USAGE_EXPIRE_DATETIME => {
let usage_expire_datetime: i64 = data
.get()
.context("Failed to read sql data for tag: USAGE_EXPIRE_DATETIME.")?;
KeyParameterValue::UsageExpireDateTime(usage_expire_datetime)
}
Tag::MIN_SECONDS_BETWEEN_OPS => {
let min_secs_between_ops: i32 = data
.get()
.context("Failed to read sql data for tag: MIN_SECONDS_BETWEEN_OPS.")?;
KeyParameterValue::MinSecondsBetweenOps(min_secs_between_ops)
}
Tag::MAX_USES_PER_BOOT => {
let max_uses_per_boot: i32 =
data.get().context("Failed to read sql data for tag: MAX_USES_PER_BOOT.")?;
KeyParameterValue::MaxUsesPerBoot(max_uses_per_boot)
}
Tag::USER_ID => {
let user_id: i32 =
data.get().context("Failed to read sql data for tag: USER_ID.")?;
KeyParameterValue::UserID(user_id)
}
Tag::USER_SECURE_ID => {
let user_secure_id: i64 =
data.get().context("Failed to read sql data for tag: USER_SECURE_ID.")?;
KeyParameterValue::UserSecureID(user_secure_id)
}
Tag::NO_AUTH_REQUIRED => KeyParameterValue::NoAuthRequired,
Tag::USER_AUTH_TYPE => {
let user_auth_type: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: USER_AUTH_TYPE.")?;
KeyParameterValue::HardwareAuthenticatorType(HardwareAuthenticatorType(
user_auth_type,
))
}
Tag::AUTH_TIMEOUT => {
let auth_timeout: i32 =
data.get().context("Failed to read sql data for tag: AUTH_TIMEOUT.")?;
KeyParameterValue::AuthTimeout(auth_timeout)
}
Tag::ALLOW_WHILE_ON_BODY => KeyParameterValue::AllowWhileOnBody,
Tag::TRUSTED_USER_PRESENCE_REQUIRED => KeyParameterValue::TrustedUserPresenceRequired,
Tag::TRUSTED_CONFIRMATION_REQUIRED => KeyParameterValue::TrustedConfirmationRequired,
Tag::UNLOCKED_DEVICE_REQUIRED => KeyParameterValue::UnlockedDeviceRequired,
Tag::APPLICATION_ID => {
let app_id: Vec<u8> =
data.get().context("Failed to read sql data for tag: APPLICATION_ID.")?;
KeyParameterValue::ApplicationID(app_id)
}
Tag::APPLICATION_DATA => {
let app_data: Vec<u8> =
data.get().context("Failed to read sql data for tag: APPLICATION_DATA.")?;
KeyParameterValue::ApplicationData(app_data)
}
Tag::CREATION_DATETIME => {
let creation_datetime: i64 =
data.get().context("Failed to read sql data for tag: CREATION_DATETIME.")?;
KeyParameterValue::CreationDateTime(creation_datetime)
}
Tag::ORIGIN => {
let origin: i32 = data
.get()
.map_err(|_| KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to read sql data for tag: ORIGIN.")?;
KeyParameterValue::KeyOrigin(KeyOrigin(origin))
}
Tag::ROOT_OF_TRUST => {
let root_of_trust: Vec<u8> =
data.get().context("Failed to read sql data for tag: ROOT_OF_TRUST.")?;
KeyParameterValue::RootOfTrust(root_of_trust)
}
Tag::OS_VERSION => {
let os_version: i32 =
data.get().context("Failed to read sql data for tag: OS_VERSION.")?;
KeyParameterValue::OSVersion(os_version)
}
Tag::OS_PATCHLEVEL => {
let os_patch_level: i32 =
data.get().context("Failed to read sql data for tag: OS_PATCHLEVEL.")?;
KeyParameterValue::OSPatchLevel(os_patch_level)
}
Tag::UNIQUE_ID => {
let unique_id: Vec<u8> =
data.get().context("Failed to read sql data for tag: UNIQUE_ID.")?;
KeyParameterValue::UniqueID(unique_id)
}
Tag::ATTESTATION_CHALLENGE => {
let attestation_challenge: Vec<u8> = data
.get()
.context("Failed to read sql data for tag: ATTESTATION_CHALLENGE.")?;
KeyParameterValue::AttestationChallenge(attestation_challenge)
}
Tag::ATTESTATION_APPLICATION_ID => {
let attestation_app_id: Vec<u8> = data
.get()
.context("Failed to read sql data for tag: ATTESTATION_APPLICATION_ID.")?;
KeyParameterValue::AttestationApplicationID(attestation_app_id)
}
Tag::ATTESTATION_ID_BRAND => {
let attestation_id_brand: Vec<u8> =
data.get().context("Failed to read sql data for tag: ATTESTATION_ID_BRAND.")?;
KeyParameterValue::AttestationIdBrand(attestation_id_brand)
}
Tag::ATTESTATION_ID_DEVICE => {
let attestation_id_device: Vec<u8> = data
.get()
.context("Failed to read sql data for tag: ATTESTATION_ID_DEVICE.")?;
KeyParameterValue::AttestationIdDevice(attestation_id_device)
}
Tag::ATTESTATION_ID_PRODUCT => {
let attestation_id_product: Vec<u8> = data
.get()
.context("Failed to read sql data for tag: ATTESTATION_ID_PRODUCT.")?;
KeyParameterValue::AttestationIdProduct(attestation_id_product)
}
Tag::ATTESTATION_ID_SERIAL => {
let attestation_id_serial: Vec<u8> = data
.get()
.context("Failed to read sql data for tag: ATTESTATION_ID_SERIAL.")?;
KeyParameterValue::AttestationIdSerial(attestation_id_serial)
}
Tag::ATTESTATION_ID_IMEI => {
let attestation_id_imei: Vec<u8> =
data.get().context("Failed to read sql data for tag: ATTESTATION_ID_IMEI.")?;
KeyParameterValue::AttestationIdIMEI(attestation_id_imei)
}
Tag::ATTESTATION_ID_MEID => {
let attestation_id_meid: Vec<u8> =
data.get().context("Failed to read sql data for tag: ATTESTATION_ID_MEID.")?;
KeyParameterValue::AttestationIdMEID(attestation_id_meid)
}
Tag::ATTESTATION_ID_MANUFACTURER => {
let attestation_id_manufacturer: Vec<u8> = data
.get()
.context("Failed to read sql data for tag: ATTESTATION_ID_MANUFACTURER.")?;
KeyParameterValue::AttestationIdManufacturer(attestation_id_manufacturer)
}
Tag::ATTESTATION_ID_MODEL => {
let attestation_id_model: Vec<u8> =
data.get().context("Failed to read sql data for tag: ATTESTATION_ID_MODEL.")?;
KeyParameterValue::AttestationIdModel(attestation_id_model)
}
Tag::VENDOR_PATCHLEVEL => {
let vendor_patch_level: i32 =
data.get().context("Failed to read sql data for tag: VENDOR_PATCHLEVEL.")?;
KeyParameterValue::VendorPatchLevel(vendor_patch_level)
}
Tag::BOOT_PATCHLEVEL => {
let boot_patch_level: i32 =
data.get().context("Failed to read sql data for tag: BOOT_PATCHLEVEL.")?;
KeyParameterValue::BootPatchLevel(boot_patch_level)
}
Tag::ASSOCIATED_DATA => {
let associated_data: Vec<u8> =
data.get().context("Failed to read sql data for tag: ASSOCIATED_DATA.")?;
KeyParameterValue::AssociatedData(associated_data)
}
Tag::NONCE => {
let nonce: Vec<u8> =
data.get().context("Failed to read sql data for tag: NONCE.")?;
KeyParameterValue::Nonce(nonce)
}
Tag::MAC_LENGTH => {
let mac_length: i32 =
data.get().context("Failed to read sql data for tag: MAC_LENGTH.")?;
KeyParameterValue::MacLength(mac_length)
}
Tag::RESET_SINCE_ID_ROTATION => KeyParameterValue::ResetSinceIdRotation,
Tag::CONFIRMATION_TOKEN => {
let confirmation_token: Vec<u8> =
data.get().context("Failed to read sql data for tag: CONFIRMATION_TOKEN.")?;
KeyParameterValue::ConfirmationToken(confirmation_token)
}
_ => {
return Err(KeystoreError::Rc(ResponseCode::VALUE_CORRUPTED))
.context("Failed to decode Tag enum from value.")?
}
};
Ok(KeyParameter::new(key_param_value, security_level_val))
}
}
/// Macro rules for converting key parameter to/from wire type.
/// This macro takes between three and four different pieces of information about each
/// of the KeyParameterValue variants:
/// 1. The KeyParameterValue variant name,
/// 2. the tag name corresponding to the variant,
/// 3. the field name in the KmKeyParameter struct, in which information about this variant is
/// stored when converted, and
/// 4. an optional enum type name when the nested value is of enum type.
/// The macro takes a set of lines corresponding to each KeyParameterValue variant and generates
/// the two conversion methods: convert_to_wire() and convert_from_wire().
/// ## Example
/// ```
/// implement_key_parameter_conversion_to_from_wire! {
/// Invalid, INVALID, na;
/// KeyPurpose, PURPOSE, integer, KeyPurpose;
/// CallerNonce, CALLER_NONCE, boolValue;
/// UserSecureID, USER_SECURE_ID, longInteger;
/// ApplicationID, APPLICATION_ID, blob;
/// }
/// ```
/// expands to:
/// ```
/// pub fn convert_to_wire(self) -> KmKeyParameter {
/// match self {
/// KeyParameterValue::Invalid => KmKeyParameter {
/// tag: Tag::INVALID,
/// ..Default::default()
/// },
/// KeyParameterValue::KeyPurpose(v) => KmKeyParameter {
/// tag: Tag::PURPOSE,
/// integer: v.0,
/// ..Default::default()
/// },
/// KeyParameterValue::CallerNonce => KmKeyParameter {
/// tag: Tag::CALLER_NONCE,
/// boolValue: true,
/// ..Default::default()
/// },
/// KeyParameterValue::UserSecureID(v) => KmKeyParameter {
/// tag: Tag::USER_SECURE_ID,
/// longInteger: v,
/// ..Default::default()
/// },
/// KeyParameterValue::ApplicationID(v) => KmKeyParameter {
/// tag: Tag::APPLICATION_ID,
/// blob: v,
/// ..Default::default()
/// },
/// }
/// }
/// ```
/// and
/// ```
/// pub fn convert_from_wire(aidl_kp: KmKeyParameter) -> KeyParameterValue {
/// match aidl_kp {
/// KmKeyParameter {
/// tag: Tag::INVALID,
/// ..
/// } => KeyParameterValue::Invalid,
/// KmKeyParameter {
/// tag: Tag::PURPOSE,
/// integer: v,
/// ..
/// } => KeyParameterValue::KeyPurpose(KeyPurpose(v)),
/// KmKeyParameter {
/// tag: Tag::CALLER_NONCE,
/// boolValue: true,
/// ..
/// } => KeyParameterValue::CallerNonce,
/// KmKeyParameter {
/// tag: Tag::USER_SECURE_ID,
/// longInteger: v,
/// ..
/// } => KeyParameterValue::UserSecureID(v),
/// KmKeyParameter {
/// tag: Tag::APPLICATION_ID,
/// blob: v,
/// ..
/// } => KeyParameterValue::ApplicationID(v),
/// _ => KeyParameterValue::Invalid,
/// }
/// }
///
macro_rules! implement_key_parameter_conversion_to_from_wire {
// There are three groups of rules in this macro.
// 1. The first group contains the rule which acts as the public interface. It takes the input
// given to this macro and prepares it to be given as input to the two groups of rules
// mentioned below.
// 2. The second group starts with the prefix @to and generates convert_to_wire() method.
// 3. The third group starts with the prefix @from and generates convert_from_wire() method.
//
// Input to this macro is first handled by the first macro rule (belonging to the first
// group above), which pre-processes the input such that rules in the other two groups
// generate the code for the two methods, when called recursively.
// Each of convert_to_wire() and convert_from_wire() methods are generated using a set of
// four macro rules in the second two groups. These four rules intend to do the following
// tasks respectively:
// i) generates match arms related to Invalid KeyParameterValue variant.
// ii) generates match arms related to boolValue field in KmKeyParameter struct.
// iii) generates match arms related to all the other fields in KmKeyParameter struct.
// iv) generates the method definition including the match arms generated from the above
// three recursive macro rules.
// This rule is applied on the input given to the macro invocations from outside the macro.
($($variant:ident, $tag_name:ident, $field_name:ident $(,$enum_type:ident)?;)*) => {
// pre-processes input to target the rules that generate convert_to_wire() method.
implement_key_parameter_conversion_to_from_wire! {@to
[], $($variant, $tag_name, $field_name $(,$enum_type)?;)*
}
// pre-processes input to target the rules that generate convert_from_wire() method.
implement_key_parameter_conversion_to_from_wire! {@from
[], $($variant, $tag_name, $field_name $(,$enum_type)?;)*
}
};
// Following four rules (belonging to the aforementioned second group) generate
// convert_to_wire() conversion method.
// -----------------------------------------------------------------------
// This rule handles Invalid variant.
// On an input: 'Invalid, INVALID, na;' it generates a match arm like:
// KeyParameterValue::Invalid => KmKeyParameter {
// tag: Tag::INVALID,
// ..Default::default()
// },
(@to [$($out:tt)*], Invalid, INVALID, na; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@to
[$($out)*
KeyParameterValue::Invalid => KmKeyParameter {
tag: Tag::INVALID,
..Default::default()
},
], $($in)*
}
};
// This rule handles all variants that correspond to bool values.
// On an input like: 'CallerNonce, CALLER_NONCE, boolValue;' it generates
// a match arm like:
// KeyParameterValue::CallerNonce => KmKeyParameter {
// tag: Tag::CALLER_NONCE,
// boolValue: true,
// ..Default::default()
// },
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, boolValue; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@to
[$($out)*
KeyParameterValue::$variant => KmKeyParameter {
tag: Tag::$tag_val,
boolValue: true,
..Default::default()
},
], $($in)*
}
};
// This rule handles all enum variants.
// On an input like: 'KeyPurpose, PURPOSE, integer, KeyPurpose;' it generates a match arm
// like: KeyParameterValue::KeyPurpose(v) => KmKeyParameter {
// tag: Tag::PURPOSE,
// integer: v.0,
// ..Default::default(),
// },
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident, $enum_type:ident; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@to
[$($out)*
KeyParameterValue::$variant(v) => KmKeyParameter {
tag: Tag::$tag_val,
$field: v.0,
..Default::default()
},
], $($in)*
}
};
// This rule handles all variants that are neither invalid nor bool values nor enums
// (i.e. all variants which correspond to integer, longInteger, and blob fields in
// KmKeyParameter).
// On an input like: 'ConfirmationToken, CONFIRMATION_TOKEN, blob;' it generates a match arm
// like: KeyParameterValue::ConfirmationToken(v) => KmKeyParameter {
// tag: Tag::CONFIRMATION_TOKEN,
// blob: v,
// ..Default::default(),
// },
(@to [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@to
[$($out)*
KeyParameterValue::$variant(v) => KmKeyParameter {
tag: Tag::$tag_val,
$field: v,
..Default::default()
},
], $($in)*
}
};
// After all the match arms are generated by the above three rules, this rule combines them
// into the convert_to_wire() method.
(@to [$($out:tt)*], ) => {
/// Conversion of key parameter to wire type
pub fn convert_to_wire(self) -> KmKeyParameter {
match self {
$($out)*
}
}
};
// Following four rules (belonging to the aforementioned third group) generate
// convert_from_wire() conversion method.
// ------------------------------------------------------------------------
// This rule handles Invalid variant.
// On an input: 'Invalid, INVALID, na;' it generates a match arm like:
// KmKeyParameter { tag: Tag::INVALID, .. } => KeyParameterValue::Invalid,
(@from [$($out:tt)*], Invalid, INVALID, na; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@from
[$($out)*
KmKeyParameter {
tag: Tag::INVALID,
..
} => KeyParameterValue::Invalid,
], $($in)*
}
};
// This rule handles all variants that correspond to bool values.
// On an input like: 'CallerNonce, CALLER_NONCE, boolValue;' it generates a match arm like:
// KmKeyParameter {
// tag: Tag::CALLER_NONCE,
// boolValue: true,
// ..
// } => KeyParameterValue::CallerNonce,
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, boolValue; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@from
[$($out)*
KmKeyParameter {
tag: Tag::$tag_val,
boolValue: true,
..
} => KeyParameterValue::$variant,
], $($in)*
}
};
// This rule handles all enum variants.
// On an input like: 'KeyPurpose, PURPOSE, integer, KeyPurpose;' it generates a match arm
// like:
// KmKeyParameter {
// tag: Tag::PURPOSE,
// integer: v,
// ..,
// } => KeyParameterValue::KeyPurpose(KeyPurpose(v)),
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident, $enum_type:ident; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@from
[$($out)*
KmKeyParameter {
tag: Tag::$tag_val,
$field: v,
..
} => KeyParameterValue::$variant($enum_type(v)),
], $($in)*
}
};
// This rule handles all variants that are neither invalid nor bool values nor enums
// (i.e. all variants which correspond to integer, longInteger, and blob fields in
// KmKeyParameter).
// On an input like: 'ConfirmationToken, CONFIRMATION_TOKEN, blob;' it generates a match arm
// like:
// KmKeyParameter {
// tag: Tag::CONFIRMATION_TOKEN,
// blob: v,
// ..,
// } => KeyParameterValue::ConfirmationToken(v),
(@from [$($out:tt)*], $variant:ident, $tag_val:ident, $field:ident; $($in:tt)*) => {
implement_key_parameter_conversion_to_from_wire! {@from
[$($out)*
KmKeyParameter {
tag: Tag::$tag_val,
$field: v,
..
} => KeyParameterValue::$variant(v),
], $($in)*
}
};
// After all the match arms are generated by the above three rules, this rule combines them
// into the convert_from_wire() method.
(@from [$($out:tt)*], ) => {
/// Conversion of key parameter from wire type
pub fn convert_from_wire(aidl_kp: KmKeyParameter) -> KeyParameterValue {
match aidl_kp {
$($out)*
_ => KeyParameterValue::Invalid,
}
}
};
}
impl KeyParameterValue {
// Invoke the macro that generates the code for key parameter conversion to/from wire type
// with all possible variants of KeyParameterValue. Each line corresponding to a variant
// contains: variant identifier, tag value, and the related field name (i.e.
// boolValue/integer/longInteger/blob) in the KmKeyParameter.
implement_key_parameter_conversion_to_from_wire! {
Invalid, INVALID, na;
KeyPurpose, PURPOSE, integer, KeyPurpose;
Algorithm, ALGORITHM, integer, Algorithm;
KeySize, KEY_SIZE, integer;
BlockMode, BLOCK_MODE, integer, BlockMode;
Digest, DIGEST, integer, Digest;
PaddingMode, PADDING, integer, PaddingMode;
CallerNonce, CALLER_NONCE, boolValue;
MinMacLength, MIN_MAC_LENGTH, integer;
EcCurve, EC_CURVE, integer, EcCurve;
RSAPublicExponent, RSA_PUBLIC_EXPONENT, longInteger;
IncludeUniqueID, INCLUDE_UNIQUE_ID, boolValue;
BootLoaderOnly, BOOTLOADER_ONLY, boolValue;
RollbackResistance, ROLLBACK_RESISTANCE, boolValue;
ActiveDateTime, ACTIVE_DATETIME, longInteger;
OriginationExpireDateTime, ORIGINATION_EXPIRE_DATETIME, longInteger;
UsageExpireDateTime, USAGE_EXPIRE_DATETIME, longInteger;
MinSecondsBetweenOps, MIN_SECONDS_BETWEEN_OPS, integer;
MaxUsesPerBoot, MAX_USES_PER_BOOT, integer;
UserID, USER_ID, integer;
UserSecureID, USER_SECURE_ID, longInteger;
NoAuthRequired, NO_AUTH_REQUIRED, boolValue;
HardwareAuthenticatorType, USER_AUTH_TYPE, integer, HardwareAuthenticatorType;
AuthTimeout, AUTH_TIMEOUT, integer;
AllowWhileOnBody, ALLOW_WHILE_ON_BODY, boolValue;
TrustedUserPresenceRequired, TRUSTED_USER_PRESENCE_REQUIRED, boolValue;
TrustedConfirmationRequired, TRUSTED_CONFIRMATION_REQUIRED, boolValue;
UnlockedDeviceRequired, UNLOCKED_DEVICE_REQUIRED, boolValue;
ApplicationID, APPLICATION_ID, blob;
ApplicationData, APPLICATION_DATA, blob;
CreationDateTime, CREATION_DATETIME, longInteger;
KeyOrigin, ORIGIN, integer, KeyOrigin;
RootOfTrust, ROOT_OF_TRUST, blob;
OSVersion, OS_VERSION, integer;
OSPatchLevel, OS_PATCHLEVEL, integer;
UniqueID, UNIQUE_ID, blob;
AttestationChallenge, ATTESTATION_CHALLENGE, blob;
AttestationApplicationID, ATTESTATION_APPLICATION_ID, blob;
AttestationIdBrand, ATTESTATION_ID_BRAND, blob;
AttestationIdDevice, ATTESTATION_ID_DEVICE, blob;
AttestationIdProduct, ATTESTATION_ID_PRODUCT, blob;
AttestationIdSerial, ATTESTATION_ID_SERIAL, blob;
AttestationIdIMEI, ATTESTATION_ID_IMEI, blob;
AttestationIdMEID, ATTESTATION_ID_MEID, blob;
AttestationIdManufacturer, ATTESTATION_ID_MANUFACTURER, blob;
AttestationIdModel, ATTESTATION_ID_MODEL, blob;
VendorPatchLevel, VENDOR_PATCHLEVEL, integer;
BootPatchLevel, BOOT_PATCHLEVEL, integer;
AssociatedData, ASSOCIATED_DATA, blob;
Nonce, NONCE, blob;
MacLength, MAC_LENGTH, integer;
ResetSinceIdRotation, RESET_SINCE_ID_ROTATION, boolValue;
ConfirmationToken, CONFIRMATION_TOKEN, blob;
}
}
#[cfg(test)]
mod basic_tests {
use crate::key_parameter::*;
// Test basic functionality of KeyParameter.
#[test]
fn test_key_parameter() {
let key_parameter = KeyParameter::new(
KeyParameterValue::Algorithm(Algorithm::RSA),
SecurityLevel::STRONGBOX,
);
assert_eq!(key_parameter.get_tag(), Tag::ALGORITHM);
assert_eq!(
*key_parameter.key_parameter_value(),
KeyParameterValue::Algorithm(Algorithm::RSA)
);
assert_eq!(*key_parameter.security_level(), SecurityLevel::STRONGBOX);
}
}
/// The storage_tests module first tests the 'new_from_sql' method for KeyParameters of different
/// data types and then tests 'to_sql' method for KeyParameters of those
/// different data types. The five different data types for KeyParameter values are:
/// i) enums of u32
/// ii) u32
/// iii) u64
/// iv) Vec<u8>
/// v) bool
#[cfg(test)]
mod storage_tests {
use crate::error::*;
use crate::key_parameter::*;
use anyhow::Result;
use rusqlite::types::ToSql;
use rusqlite::{params, Connection, NO_PARAMS};
/// Test initializing a KeyParameter (with key parameter value corresponding to an enum of i32)
/// from a database table row.
#[test]
fn test_new_from_sql_enum_i32() -> Result<()> {
let db = init_db()?;
insert_into_keyparameter(
&db,
1,
Tag::ALGORITHM.0,
&Algorithm::RSA.0,
SecurityLevel::STRONGBOX.0,
)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(Tag::ALGORITHM, key_param.get_tag());
assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::Algorithm(Algorithm::RSA));
assert_eq!(*key_param.security_level(), SecurityLevel::STRONGBOX);
Ok(())
}
/// Test initializing a KeyParameter (with key parameter value which is of i32)
/// from a database table row.
#[test]
fn test_new_from_sql_i32() -> Result<()> {
let db = init_db()?;
insert_into_keyparameter(&db, 1, Tag::KEY_SIZE.0, &1024, SecurityLevel::STRONGBOX.0)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(Tag::KEY_SIZE, key_param.get_tag());
assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::KeySize(1024));
Ok(())
}
/// Test initializing a KeyParameter (with key parameter value which is of i64)
/// from a database table row.
#[test]
fn test_new_from_sql_i64() -> Result<()> {
let db = init_db()?;
// max value for i64, just to test corner cases
insert_into_keyparameter(
&db,
1,
Tag::RSA_PUBLIC_EXPONENT.0,
&(i64::MAX),
SecurityLevel::STRONGBOX.0,
)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(Tag::RSA_PUBLIC_EXPONENT, key_param.get_tag());
assert_eq!(
*key_param.key_parameter_value(),
KeyParameterValue::RSAPublicExponent(i64::MAX)
);
Ok(())
}
/// Test initializing a KeyParameter (with key parameter value which is of bool)
/// from a database table row.
#[test]
fn test_new_from_sql_bool() -> Result<()> {
let db = init_db()?;
insert_into_keyparameter(&db, 1, Tag::CALLER_NONCE.0, &Null, SecurityLevel::STRONGBOX.0)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(Tag::CALLER_NONCE, key_param.get_tag());
assert_eq!(*key_param.key_parameter_value(), KeyParameterValue::CallerNonce);
Ok(())
}
/// Test initializing a KeyParameter (with key parameter value which is of Vec<u8>)
/// from a database table row.
#[test]
fn test_new_from_sql_vec_u8() -> Result<()> {
let db = init_db()?;
let app_id = String::from("MyAppID");
let app_id_bytes = app_id.into_bytes();
insert_into_keyparameter(
&db,
1,
Tag::APPLICATION_ID.0,
&app_id_bytes,
SecurityLevel::STRONGBOX.0,
)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(Tag::APPLICATION_ID, key_param.get_tag());
assert_eq!(
*key_param.key_parameter_value(),
KeyParameterValue::ApplicationID(app_id_bytes)
);
Ok(())
}
/// Test storing a KeyParameter (with key parameter value which corresponds to an enum of i32)
/// in the database
#[test]
fn test_to_sql_enum_i32() -> Result<()> {
let db = init_db()?;
let kp = KeyParameter::new(
KeyParameterValue::Algorithm(Algorithm::RSA),
SecurityLevel::STRONGBOX,
);
store_keyparameter(&db, 1, &kp)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(kp.get_tag(), key_param.get_tag());
assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
assert_eq!(kp.security_level(), key_param.security_level());
Ok(())
}
/// Test storing a KeyParameter (with key parameter value which is of i32) in the database
#[test]
fn test_to_sql_i32() -> Result<()> {
let db = init_db()?;
let kp = KeyParameter::new(KeyParameterValue::KeySize(1024), SecurityLevel::STRONGBOX);
store_keyparameter(&db, 1, &kp)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(kp.get_tag(), key_param.get_tag());
assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
assert_eq!(kp.security_level(), key_param.security_level());
Ok(())
}
/// Test storing a KeyParameter (with key parameter value which is of i64) in the database
#[test]
fn test_to_sql_i64() -> Result<()> {
let db = init_db()?;
// max value for i64, just to test corner cases
let kp = KeyParameter::new(
KeyParameterValue::RSAPublicExponent(i64::MAX),
SecurityLevel::STRONGBOX,
);
store_keyparameter(&db, 1, &kp)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(kp.get_tag(), key_param.get_tag());
assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
assert_eq!(kp.security_level(), key_param.security_level());
Ok(())
}
/// Test storing a KeyParameter (with key parameter value which is of Vec<u8>) in the database
#[test]
fn test_to_sql_vec_u8() -> Result<()> {
let db = init_db()?;
let kp = KeyParameter::new(
KeyParameterValue::ApplicationID(String::from("MyAppID").into_bytes()),
SecurityLevel::STRONGBOX,
);
store_keyparameter(&db, 1, &kp)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(kp.get_tag(), key_param.get_tag());
assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
assert_eq!(kp.security_level(), key_param.security_level());
Ok(())
}
/// Test storing a KeyParameter (with key parameter value which is of i32) in the database
#[test]
fn test_to_sql_bool() -> Result<()> {
let db = init_db()?;
let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
store_keyparameter(&db, 1, &kp)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(kp.get_tag(), key_param.get_tag());
assert_eq!(kp.key_parameter_value(), key_param.key_parameter_value());
assert_eq!(kp.security_level(), key_param.security_level());
Ok(())
}
#[test]
/// Test Tag::Invalid
fn test_invalid_tag() -> Result<()> {
let db = init_db()?;
insert_into_keyparameter(&db, 1, 0, &123, 1)?;
let key_param = query_from_keyparameter(&db)?;
assert_eq!(Tag::INVALID, key_param.get_tag());
Ok(())
}
#[test]
fn test_non_existing_enum_variant() -> Result<()> {
let db = init_db()?;
insert_into_keyparameter(&db, 1, 100, &123, 1)?;
tests::check_result_contains_error_string(
query_from_keyparameter(&db),
"Failed to decode Tag enum from value.",
);
Ok(())
}
#[test]
fn test_invalid_conversion_from_sql() -> Result<()> {
let db = init_db()?;
insert_into_keyparameter(&db, 1, Tag::ALGORITHM.0, &Null, 1)?;
tests::check_result_contains_error_string(
query_from_keyparameter(&db),
"Failed to read sql data for tag: ALGORITHM.",
);
Ok(())
}
/// Helper method to init database table for key parameter
fn init_db() -> Result<Connection> {
let db = Connection::open_in_memory().context("Failed to initialize sqlite connection.")?;
db.execute("ATTACH DATABASE ? as 'persistent';", params![""])
.context("Failed to attach databases.")?;
db.execute(
"CREATE TABLE IF NOT EXISTS persistent.keyparameter (
keyentryid INTEGER,
tag INTEGER,
data ANY,
security_level INTEGER);",
NO_PARAMS,
)
.context("Failed to initialize \"keyparameter\" table.")?;
Ok(db)
}
/// Helper method to insert an entry into key parameter table, with individual parameters
fn insert_into_keyparameter<T: ToSql>(
db: &Connection,
key_id: i64,
tag: i32,
value: &T,
security_level: i32,
) -> Result<()> {
db.execute(
"INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
VALUES(?, ?, ?, ?);",
params![key_id, tag, *value, security_level],
)?;
Ok(())
}
/// Helper method to store a key parameter instance.
fn store_keyparameter(db: &Connection, key_id: i64, kp: &KeyParameter) -> Result<()> {
db.execute(
"INSERT into persistent.keyparameter (keyentryid, tag, data, security_level)
VALUES(?, ?, ?, ?);",
params![key_id, kp.get_tag().0, kp.key_parameter_value(), kp.security_level().0],
)?;
Ok(())
}
/// Helper method to query a row from keyparameter table
fn query_from_keyparameter(db: &Connection) -> Result<KeyParameter> {
let mut stmt =
db.prepare("SELECT tag, data, security_level FROM persistent.keyparameter")?;
let mut rows = stmt.query(NO_PARAMS)?;
let row = rows.next()?.unwrap();
Ok(KeyParameter::new_from_sql(
Tag(row.get(0)?),
&SqlField(1, row),
SecurityLevel(row.get(2)?),
)?)
}
}
/// The wire_tests module tests the 'convert_to_wire' and 'convert_from_wire' methods for
/// KeyParameter, for the four different types used in KmKeyParameter, in addition to Invalid
/// key parameter.
/// i) bool
/// ii) integer
/// iii) longInteger
/// iv) blob
#[cfg(test)]
mod wire_tests {
use crate::key_parameter::*;
/// unit tests for to conversions
#[test]
fn test_convert_to_wire_invalid() {
let kp = KeyParameter::new(KeyParameterValue::Invalid, SecurityLevel::STRONGBOX);
let actual = KeyParameterValue::convert_to_wire(kp.key_parameter_value);
assert_eq!(Tag::INVALID, actual.tag);
}
#[test]
fn test_convert_to_wire_bool() {
let kp = KeyParameter::new(KeyParameterValue::CallerNonce, SecurityLevel::STRONGBOX);
let actual = KeyParameterValue::convert_to_wire(kp.key_parameter_value);
assert_eq!(Tag::CALLER_NONCE, actual.tag);
assert_eq!(true, actual.boolValue);
}
#[test]
fn test_convert_to_wire_integer() {
let kp = KeyParameter::new(
KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT),
SecurityLevel::STRONGBOX,
);
let actual = KeyParameterValue::convert_to_wire(kp.key_parameter_value);
assert_eq!(Tag::PURPOSE, actual.tag);
assert_eq!(KeyPurpose::ENCRYPT.0, actual.integer);
}
#[test]
fn test_convert_to_wire_long_integer() {
let kp =
KeyParameter::new(KeyParameterValue::UserSecureID(i64::MAX), SecurityLevel::STRONGBOX);
let actual = KeyParameterValue::convert_to_wire(kp.key_parameter_value);
assert_eq!(Tag::USER_SECURE_ID, actual.tag);
assert_eq!(i64::MAX, actual.longInteger);
}
#[test]
fn test_convert_to_wire_blob() {
let kp = KeyParameter::new(
KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
SecurityLevel::STRONGBOX,
);
let actual = KeyParameterValue::convert_to_wire(kp.key_parameter_value);
assert_eq!(Tag::CONFIRMATION_TOKEN, actual.tag);
assert_eq!(String::from("ConfirmationToken").into_bytes(), actual.blob);
}
/// unit tests for from conversion
#[test]
fn test_convert_from_wire_invalid() {
let aidl_kp = KmKeyParameter { tag: Tag::INVALID, ..Default::default() };
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
assert_eq!(KeyParameterValue::Invalid, actual);
}
#[test]
fn test_convert_from_wire_bool() {
let aidl_kp =
KmKeyParameter { tag: Tag::CALLER_NONCE, boolValue: true, ..Default::default() };
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
assert_eq!(KeyParameterValue::CallerNonce, actual);
}
#[test]
fn test_convert_from_wire_integer() {
let aidl_kp = KmKeyParameter {
tag: Tag::PURPOSE,
integer: KeyPurpose::ENCRYPT.0,
..Default::default()
};
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
assert_eq!(KeyParameterValue::KeyPurpose(KeyPurpose::ENCRYPT), actual);
}
#[test]
fn test_convert_from_wire_long_integer() {
let aidl_kp = KmKeyParameter {
tag: Tag::USER_SECURE_ID,
longInteger: i64::MAX,
..Default::default()
};
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
assert_eq!(KeyParameterValue::UserSecureID(i64::MAX), actual);
}
#[test]
fn test_convert_from_wire_blob() {
let aidl_kp = KmKeyParameter {
tag: Tag::CONFIRMATION_TOKEN,
blob: String::from("ConfirmationToken").into_bytes(),
..Default::default()
};
let actual = KeyParameterValue::convert_from_wire(aidl_kp);
assert_eq!(
KeyParameterValue::ConfirmationToken(String::from("ConfirmationToken").into_bytes()),
actual
);
}
}