blob: 35290df51c3a766fd28da7999a6a32c39e3804f5 [file] [log] [blame] [edit]
// 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.
//! This module implements utility functions used by the Keystore 2.0 service
//! implementation.
use crate::error::{map_binder_status, map_km_error, Error, ErrorCode};
use crate::key_parameter::KeyParameter;
use crate::ks_err;
use crate::permission;
use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
pub use crate::watchdog_helper::watchdog;
use crate::{
database::{KeyType, KeystoreDB},
globals::LEGACY_IMPORTER,
km_compat,
raw_device::KeyMintDevice,
};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, IKeyMintDevice::IKeyMintDevice, KeyCharacteristics::KeyCharacteristics,
KeyParameter::KeyParameter as KmKeyParameter, KeyParameterValue::KeyParameterValue, Tag::Tag,
};
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_security_apc::aidl::android::security::apc::{
IProtectedConfirmation::{FLAG_UI_OPTION_INVERTED, FLAG_UI_OPTION_MAGNIFIED},
ResponseCode::ResponseCode as ApcResponseCode,
};
use android_system_keystore2::aidl::android::system::keystore2::{
Authorization::Authorization, Domain::Domain, KeyDescriptor::KeyDescriptor,
ResponseCode::ResponseCode,
};
use anyhow::{Context, Result};
use binder::{FromIBinder, StatusCode, Strong, ThreadState};
use keystore2_apc_compat::{
ApcCompatUiOptions, APC_COMPAT_ERROR_ABORTED, APC_COMPAT_ERROR_CANCELLED,
APC_COMPAT_ERROR_IGNORED, APC_COMPAT_ERROR_OK, APC_COMPAT_ERROR_OPERATION_PENDING,
APC_COMPAT_ERROR_SYSTEM_ERROR,
};
use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt, ZVec};
use log::{info, warn};
use std::iter::IntoIterator;
use std::thread::sleep;
use std::time::Duration;
#[cfg(test)]
mod tests;
/// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to GeneralizedTime
/// 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
pub const UNDEFINED_NOT_AFTER: i64 = 253402300799000i64;
/// This function uses its namesake in the permission module and in
/// combination with with_calling_sid from the binder crate to check
/// if the caller has the given keystore permission.
pub fn check_keystore_permission(perm: KeystorePerm) -> anyhow::Result<()> {
ThreadState::with_calling_sid(|calling_sid| {
permission::check_keystore_permission(
calling_sid
.ok_or_else(Error::sys)
.context(ks_err!("Cannot check permission without calling_sid."))?,
perm,
)
})
}
/// This function uses its namesake in the permission module and in
/// combination with with_calling_sid from the binder crate to check
/// if the caller has the given grant permission.
pub fn check_grant_permission(access_vec: KeyPermSet, key: &KeyDescriptor) -> anyhow::Result<()> {
ThreadState::with_calling_sid(|calling_sid| {
permission::check_grant_permission(
ThreadState::get_calling_uid(),
calling_sid
.ok_or_else(Error::sys)
.context(ks_err!("Cannot check permission without calling_sid."))?,
access_vec,
key,
)
})
}
/// This function uses its namesake in the permission module and in
/// combination with with_calling_sid from the binder crate to check
/// if the caller has the given key permission.
pub fn check_key_permission(
perm: KeyPerm,
key: &KeyDescriptor,
access_vector: &Option<KeyPermSet>,
) -> anyhow::Result<()> {
ThreadState::with_calling_sid(|calling_sid| {
permission::check_key_permission(
ThreadState::get_calling_uid(),
calling_sid
.ok_or_else(Error::sys)
.context(ks_err!("Cannot check permission without calling_sid."))?,
perm,
key,
access_vector,
)
})
}
/// This function checks whether a given tag corresponds to the access of device identifiers.
pub fn is_device_id_attestation_tag(tag: Tag) -> bool {
matches!(
tag,
Tag::ATTESTATION_ID_IMEI
| Tag::ATTESTATION_ID_MEID
| Tag::ATTESTATION_ID_SERIAL
| Tag::DEVICE_UNIQUE_ATTESTATION
| Tag::ATTESTATION_ID_SECOND_IMEI
)
}
/// This function checks whether the calling app has the Android permissions needed to attest device
/// identifiers. It throws an error if the permissions cannot be verified or if the caller doesn't
/// have the right permissions. Otherwise it returns silently.
pub fn check_device_attestation_permissions() -> anyhow::Result<()> {
check_android_permission(
"android.permission.READ_PRIVILEGED_PHONE_STATE",
Error::Km(ErrorCode::CANNOT_ATTEST_IDS),
)
}
/// This function checks whether the calling app has the Android permissions needed to attest the
/// device-unique identifier. It throws an error if the permissions cannot be verified or if the
/// caller doesn't have the right permissions. Otherwise it returns silently.
pub fn check_unique_id_attestation_permissions() -> anyhow::Result<()> {
check_android_permission(
"android.permission.REQUEST_UNIQUE_ID_ATTESTATION",
Error::Km(ErrorCode::CANNOT_ATTEST_IDS),
)
}
/// This function checks whether the calling app has the Android permissions needed to manage
/// users. Only callers that can manage users are allowed to get a list of apps affected
/// by a user's SID changing.
/// It throws an error if the permissions cannot be verified or if the caller doesn't
/// have the right permissions. Otherwise it returns silently.
pub fn check_get_app_uids_affected_by_sid_permissions() -> anyhow::Result<()> {
check_android_permission(
"android.permission.MANAGE_USERS",
Error::Km(ErrorCode::CANNOT_ATTEST_IDS),
)
}
/// This function checks whether the calling app has the Android permission needed to dump
/// Keystore state to logcat.
pub fn check_dump_permission() -> anyhow::Result<()> {
check_android_permission("android.permission.DUMP", Error::Rc(ResponseCode::PERMISSION_DENIED))
}
fn check_android_permission(permission: &str, err: Error) -> anyhow::Result<()> {
let permission_controller: Strong<dyn IPermissionController::IPermissionController> =
binder::get_interface("permission")?;
let binder_result = {
let _wp = watchdog::watch("check_android_permission: calling checkPermission");
permission_controller.checkPermission(
permission,
ThreadState::get_calling_pid(),
ThreadState::get_calling_uid() as i32,
)
};
let has_permissions =
map_binder_status(binder_result).context(ks_err!("checkPermission failed"))?;
match has_permissions {
true => Ok(()),
false => Err(err).context(ks_err!("caller does not have the '{permission}' permission")),
}
}
/// Converts a set of key characteristics as returned from KeyMint into the internal
/// representation of the keystore service.
pub fn key_characteristics_to_internal(
key_characteristics: Vec<KeyCharacteristics>,
) -> Vec<KeyParameter> {
key_characteristics
.into_iter()
.flat_map(|aidl_key_char| {
let sec_level = aidl_key_char.securityLevel;
aidl_key_char
.authorizations
.into_iter()
.map(move |aidl_kp| KeyParameter::new(aidl_kp.into(), sec_level))
})
.collect()
}
/// Import a keyblob that is of the format used by the software C++ KeyMint implementation. After
/// successful import, invoke both the `new_blob_handler` and `km_op` closures. On success a tuple
/// of the `km_op`s result and the optional upgraded blob is returned.
fn import_keyblob_and_perform_op<T, KmOp, NewBlobHandler>(
km_dev: &dyn IKeyMintDevice,
inner_keyblob: &[u8],
upgrade_params: &[KmKeyParameter],
km_op: KmOp,
new_blob_handler: NewBlobHandler,
) -> Result<(T, Option<Vec<u8>>)>
where
KmOp: Fn(&[u8]) -> Result<T, Error>,
NewBlobHandler: FnOnce(&[u8]) -> Result<()>,
{
let (format, key_material, mut chars) =
crate::sw_keyblob::export_key(inner_keyblob, upgrade_params)?;
log::debug!(
"importing {:?} key material (len={}) with original chars={:?}",
format,
key_material.len(),
chars
);
let asymmetric = chars.iter().any(|kp| {
kp.tag == Tag::ALGORITHM
&& (kp.value == KeyParameterValue::Algorithm(Algorithm::RSA)
|| (kp.value == KeyParameterValue::Algorithm(Algorithm::EC)))
});
// Combine the characteristics of the previous keyblob with the upgrade parameters (which might
// include special things like APPLICATION_ID / APPLICATION_DATA).
chars.extend_from_slice(upgrade_params);
// Now filter out values from the existing keyblob that shouldn't be set on import, either
// because they are per-operation parameter or because they are auto-added by KeyMint itself.
let mut import_params: Vec<KmKeyParameter> = chars
.into_iter()
.filter(|kp| {
!matches!(
kp.tag,
Tag::ORIGIN
| Tag::ROOT_OF_TRUST
| Tag::OS_VERSION
| Tag::OS_PATCHLEVEL
| Tag::UNIQUE_ID
| Tag::ATTESTATION_CHALLENGE
| Tag::ATTESTATION_APPLICATION_ID
| Tag::ATTESTATION_ID_BRAND
| Tag::ATTESTATION_ID_DEVICE
| Tag::ATTESTATION_ID_PRODUCT
| Tag::ATTESTATION_ID_SERIAL
| Tag::ATTESTATION_ID_IMEI
| Tag::ATTESTATION_ID_MEID
| Tag::ATTESTATION_ID_MANUFACTURER
| Tag::ATTESTATION_ID_MODEL
| Tag::VENDOR_PATCHLEVEL
| Tag::BOOT_PATCHLEVEL
| Tag::DEVICE_UNIQUE_ATTESTATION
| Tag::ATTESTATION_ID_SECOND_IMEI
| Tag::NONCE
| Tag::MAC_LENGTH
| Tag::CERTIFICATE_SERIAL
| Tag::CERTIFICATE_SUBJECT
| Tag::CERTIFICATE_NOT_BEFORE
| Tag::CERTIFICATE_NOT_AFTER
)
})
.collect();
// Now that any previous values have been removed, add any additional parameters that needed for
// import. In particular, if we are generating/importing an asymmetric key, we need to make sure
// that NOT_BEFORE and NOT_AFTER are present.
if asymmetric {
import_params.push(KmKeyParameter {
tag: Tag::CERTIFICATE_NOT_BEFORE,
value: KeyParameterValue::DateTime(0),
});
import_params.push(KmKeyParameter {
tag: Tag::CERTIFICATE_NOT_AFTER,
value: KeyParameterValue::DateTime(UNDEFINED_NOT_AFTER),
});
}
log::debug!("import parameters={import_params:?}");
let creation_result = {
let _wp = watchdog::watch(
"utils::import_keyblob_and_perform_op: calling IKeyMintDevice::importKey",
);
map_km_error(km_dev.importKey(&import_params, format, &key_material, None))
}
.context(ks_err!("Upgrade failed."))?;
// Note that the importKey operation will produce key characteristics that may be different
// than are already stored in Keystore's SQL database. In particular, the KeyMint
// implementation will now mark the key as `Origin::IMPORTED` not `Origin::GENERATED`, and
// the security level for characteristics will now be `TRUSTED_ENVIRONMENT` not `SOFTWARE`.
//
// However, the DB metadata still accurately reflects the original origin of the key, and
// so we leave the values as-is (and so any `KeyInfo` retrieved in the Java layer will get the
// same results before and after import).
//
// Note that this also applies to the `USAGE_COUNT_LIMIT` parameter -- if the key has already
// been used, then the DB version of the parameter will be (and will continue to be) lower
// than the original count bound to the keyblob. This means that Keystore's policing of
// usage counts will continue where it left off.
new_blob_handler(&creation_result.keyBlob).context(ks_err!("calling new_blob_handler."))?;
km_op(&creation_result.keyBlob)
.map(|v| (v, Some(creation_result.keyBlob)))
.context(ks_err!("Calling km_op after upgrade."))
}
/// Upgrade a keyblob then invoke both the `new_blob_handler` and the `km_op` closures. On success
/// a tuple of the `km_op`s result and the optional upgraded blob is returned.
fn upgrade_keyblob_and_perform_op<T, KmOp, NewBlobHandler>(
km_dev: &dyn IKeyMintDevice,
key_blob: &[u8],
upgrade_params: &[KmKeyParameter],
km_op: KmOp,
new_blob_handler: NewBlobHandler,
) -> Result<(T, Option<Vec<u8>>)>
where
KmOp: Fn(&[u8]) -> Result<T, Error>,
NewBlobHandler: FnOnce(&[u8]) -> Result<()>,
{
let upgraded_blob = {
let _wp = watchdog::watch(
"utils::upgrade_keyblob_and_perform_op: calling IKeyMintDevice::upgradeKey.",
);
map_km_error(km_dev.upgradeKey(key_blob, upgrade_params))
}
.context(ks_err!("Upgrade failed."))?;
new_blob_handler(&upgraded_blob).context(ks_err!("calling new_blob_handler."))?;
km_op(&upgraded_blob)
.map(|v| (v, Some(upgraded_blob)))
.context(ks_err!("Calling km_op after upgrade."))
}
/// This function can be used to upgrade key blobs on demand. The return value of
/// `km_op` is inspected and if ErrorCode::KEY_REQUIRES_UPGRADE is encountered,
/// an attempt is made to upgrade the key blob. On success `new_blob_handler` is called
/// with the upgraded blob as argument. Then `km_op` is called a second time with the
/// upgraded blob as argument. On success a tuple of the `km_op`s result and the
/// optional upgraded blob is returned.
pub fn upgrade_keyblob_if_required_with<T, KmOp, NewBlobHandler>(
km_dev: &dyn IKeyMintDevice,
km_dev_version: i32,
key_blob: &[u8],
upgrade_params: &[KmKeyParameter],
km_op: KmOp,
new_blob_handler: NewBlobHandler,
) -> Result<(T, Option<Vec<u8>>)>
where
KmOp: Fn(&[u8]) -> Result<T, Error>,
NewBlobHandler: FnOnce(&[u8]) -> Result<()>,
{
match km_op(key_blob) {
Err(Error::Km(ErrorCode::KEY_REQUIRES_UPGRADE)) => upgrade_keyblob_and_perform_op(
km_dev,
key_blob,
upgrade_params,
km_op,
new_blob_handler,
),
Err(Error::Km(ErrorCode::INVALID_KEY_BLOB))
if km_dev_version >= KeyMintDevice::KEY_MINT_V1 =>
{
// A KeyMint (not Keymaster via km_compat) device says that this is an invalid keyblob.
//
// This may be because the keyblob was created before an Android upgrade, and as part of
// the device upgrade the underlying Keymaster/KeyMint implementation has been upgraded.
//
// If that's the case, there are three possible scenarios:
if key_blob.starts_with(km_compat::KEYMASTER_BLOB_HW_PREFIX) {
// 1) The keyblob was created in hardware by the km_compat C++ code, using a prior
// Keymaster implementation, and wrapped.
//
// In this case, the keyblob will have the km_compat magic prefix, including the
// marker that indicates that this was a hardware-backed key.
//
// The inner keyblob should still be recognized by the hardware implementation, so
// strip the prefix and attempt a key upgrade.
log::info!(
"found apparent km_compat(Keymaster) HW blob, attempt strip-and-upgrade"
);
let inner_keyblob = &key_blob[km_compat::KEYMASTER_BLOB_HW_PREFIX.len()..];
upgrade_keyblob_and_perform_op(
km_dev,
inner_keyblob,
upgrade_params,
km_op,
new_blob_handler,
)
} else if keystore2_flags::import_previously_emulated_keys()
&& key_blob.starts_with(km_compat::KEYMASTER_BLOB_SW_PREFIX)
{
// 2) The keyblob was created in software by the km_compat C++ code because a prior
// Keymaster implementation did not support ECDH (which was only added in KeyMint).
//
// In this case, the keyblob with have the km_compat magic prefix, but with the
// marker that indicates that this was a software-emulated key.
//
// The inner keyblob should be in the format produced by the C++ reference
// implementation of KeyMint. Extract the key material and import it into the
// current KeyMint device.
log::info!("found apparent km_compat(Keymaster) SW blob, attempt strip-and-import");
let inner_keyblob = &key_blob[km_compat::KEYMASTER_BLOB_SW_PREFIX.len()..];
import_keyblob_and_perform_op(
km_dev,
inner_keyblob,
upgrade_params,
km_op,
new_blob_handler,
)
} else if let (true, km_compat::KeyBlob::Wrapped(inner_keyblob)) = (
keystore2_flags::import_previously_emulated_keys(),
km_compat::unwrap_keyblob(key_blob),
) {
// 3) The keyblob was created in software by km_compat.rs because a prior KeyMint
// implementation did not support a feature present in the current KeyMint spec.
// (For example, a curve 25519 key created when the device only supported KeyMint
// v1).
//
// In this case, the keyblob with have the km_compat.rs wrapper around it to
// indicate that this was a software-emulated key.
//
// The inner keyblob should be in the format produced by the C++ reference
// implementation of KeyMint. Extract the key material and import it into the
// current KeyMint device.
log::info!(
"found apparent km_compat.rs(KeyMint) SW blob, attempt strip-and-import"
);
import_keyblob_and_perform_op(
km_dev,
inner_keyblob,
upgrade_params,
km_op,
new_blob_handler,
)
} else {
Err(Error::Km(ErrorCode::INVALID_KEY_BLOB)).context(ks_err!("Calling km_op"))
}
}
r => r.map(|v| (v, None)).context(ks_err!("Calling km_op.")),
}
}
/// Converts a set of key characteristics from the internal representation into a set of
/// Authorizations as they are used to convey key characteristics to the clients of keystore.
pub fn key_parameters_to_authorizations(
parameters: Vec<crate::key_parameter::KeyParameter>,
) -> Vec<Authorization> {
parameters.into_iter().map(|p| p.into_authorization()).collect()
}
#[allow(clippy::unnecessary_cast)]
/// This returns the current time (in milliseconds) as an instance of a monotonic clock,
/// by invoking the system call since Rust does not support getting monotonic time instance
/// as an integer.
pub fn get_current_time_in_milliseconds() -> i64 {
let mut current_time = libc::timespec { tv_sec: 0, tv_nsec: 0 };
// SAFETY: The pointer is valid because it comes from a reference, and clock_gettime doesn't
// retain it beyond the call.
unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut current_time) };
current_time.tv_sec as i64 * 1000 + (current_time.tv_nsec as i64 / 1_000_000)
}
/// Converts a response code as returned by the Android Protected Confirmation HIDL compatibility
/// module (keystore2_apc_compat) into a ResponseCode as defined by the APC AIDL
/// (android.security.apc) spec.
pub fn compat_2_response_code(rc: u32) -> ApcResponseCode {
match rc {
APC_COMPAT_ERROR_OK => ApcResponseCode::OK,
APC_COMPAT_ERROR_CANCELLED => ApcResponseCode::CANCELLED,
APC_COMPAT_ERROR_ABORTED => ApcResponseCode::ABORTED,
APC_COMPAT_ERROR_OPERATION_PENDING => ApcResponseCode::OPERATION_PENDING,
APC_COMPAT_ERROR_IGNORED => ApcResponseCode::IGNORED,
APC_COMPAT_ERROR_SYSTEM_ERROR => ApcResponseCode::SYSTEM_ERROR,
_ => ApcResponseCode::SYSTEM_ERROR,
}
}
/// Converts the UI Options flags as defined by the APC AIDL (android.security.apc) spec into
/// UI Options flags as defined by the Android Protected Confirmation HIDL compatibility
/// module (keystore2_apc_compat).
pub fn ui_opts_2_compat(opt: i32) -> ApcCompatUiOptions {
ApcCompatUiOptions {
inverted: (opt & FLAG_UI_OPTION_INVERTED) != 0,
magnified: (opt & FLAG_UI_OPTION_MAGNIFIED) != 0,
}
}
/// AID offset for uid space partitioning.
pub const AID_USER_OFFSET: u32 = rustutils::users::AID_USER_OFFSET;
/// AID of the keystore process itself, used for keys that
/// keystore generates for its own use.
pub const AID_KEYSTORE: u32 = rustutils::users::AID_KEYSTORE;
/// Extracts the android user from the given uid.
pub fn uid_to_android_user(uid: u32) -> u32 {
rustutils::users::multiuser_get_user_id(uid)
}
/// Merges and filters two lists of key descriptors. The first input list, legacy_descriptors,
/// is assumed to not be sorted or filtered. As such, all key descriptors in that list whose
/// alias is less than, or equal to, start_past_alias (if provided) will be removed.
/// This list will then be merged with the second list, db_descriptors. The db_descriptors list
/// is assumed to be sorted and filtered so the output list will be sorted prior to returning.
/// The returned value is a list of KeyDescriptor objects whose alias is greater than
/// start_past_alias, sorted and de-duplicated.
fn merge_and_filter_key_entry_lists(
legacy_descriptors: &[KeyDescriptor],
db_descriptors: &[KeyDescriptor],
start_past_alias: Option<&str>,
) -> Vec<KeyDescriptor> {
let mut result: Vec<KeyDescriptor> =
match start_past_alias {
Some(past_alias) => legacy_descriptors
.iter()
.filter(|kd| {
if let Some(alias) = &kd.alias {
alias.as_str() > past_alias
} else {
false
}
})
.cloned()
.collect(),
None => legacy_descriptors.to_vec(),
};
result.extend_from_slice(db_descriptors);
result.sort_unstable();
result.dedup();
result
}
pub(crate) fn estimate_safe_amount_to_return(
domain: Domain,
namespace: i64,
start_past_alias: Option<&str>,
key_descriptors: &[KeyDescriptor],
response_size_limit: usize,
) -> usize {
let mut count = 0;
let mut bytes: usize = 0;
// Estimate the transaction size to avoid returning more items than what
// could fit in a binder transaction.
for kd in key_descriptors.iter() {
// 4 bytes for the Domain enum
// 8 bytes for the Namespace long.
bytes += 4 + 8;
// Size of the alias string. Includes 4 bytes for length encoding.
if let Some(alias) = &kd.alias {
bytes += 4 + alias.len();
}
// Size of the blob. Includes 4 bytes for length encoding.
if let Some(blob) = &kd.blob {
bytes += 4 + blob.len();
}
// The binder transaction size limit is 1M. Empirical measurements show
// that the binder overhead is 60% (to be confirmed). So break after
// 350KB and return a partial list.
if bytes > response_size_limit {
log::warn!(
"{domain:?}:{namespace}: Key descriptors list ({} items after {start_past_alias:?}) \
may exceed binder size, returning {count} items est. {bytes} bytes",
key_descriptors.len(),
);
break;
}
count += 1;
}
count
}
/// Estimate for maximum size of a Binder response in bytes.
pub(crate) const RESPONSE_SIZE_LIMIT: usize = 358400;
/// List all key aliases for a given domain + namespace. whose alias is greater
/// than start_past_alias (if provided).
pub fn list_key_entries(
db: &mut KeystoreDB,
domain: Domain,
namespace: i64,
start_past_alias: Option<&str>,
) -> Result<Vec<KeyDescriptor>> {
let legacy_key_descriptors: Vec<KeyDescriptor> = LEGACY_IMPORTER
.list_uid(domain, namespace)
.context(ks_err!("Trying to list legacy keys."))?;
// The results from the database will be sorted and unique
let db_key_descriptors: Vec<KeyDescriptor> = db
.list_past_alias(domain, namespace, KeyType::Client, start_past_alias)
.context(ks_err!("Trying to list keystore database past alias."))?;
let merged_key_entries = merge_and_filter_key_entry_lists(
&legacy_key_descriptors,
&db_key_descriptors,
start_past_alias,
);
let safe_amount_to_return = estimate_safe_amount_to_return(
domain,
namespace,
start_past_alias,
&merged_key_entries,
RESPONSE_SIZE_LIMIT,
);
Ok(merged_key_entries[..safe_amount_to_return].to_vec())
}
/// Count all key aliases for a given domain + namespace.
pub fn count_key_entries(db: &mut KeystoreDB, domain: Domain, namespace: i64) -> Result<i32> {
let legacy_keys = LEGACY_IMPORTER
.list_uid(domain, namespace)
.context(ks_err!("Trying to list legacy keys."))?;
let num_keys_in_db = db.count_keys(domain, namespace, KeyType::Client)?;
Ok((legacy_keys.len() + num_keys_in_db) as i32)
}
/// For params remove sensitive data before returning a string for logging
pub fn log_security_safe_params(params: &[KmKeyParameter]) -> Vec<KmKeyParameter> {
params
.iter()
.filter(|kp| (kp.tag != Tag::APPLICATION_ID && kp.tag != Tag::APPLICATION_DATA))
.cloned()
.collect::<Vec<KmKeyParameter>>()
}
/// Trait implemented by objects that can be used to decrypt cipher text using AES-GCM.
pub trait AesGcm {
/// Deciphers `data` using the initialization vector `iv` and AEAD tag `tag`
/// and AES-GCM. The implementation provides the key material and selects
/// the implementation variant, e.g., AES128 or AES265.
fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec>;
/// Encrypts `data` and returns the ciphertext, the initialization vector `iv`
/// and AEAD tag `tag`. The implementation provides the key material and selects
/// the implementation variant, e.g., AES128 or AES265.
fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)>;
}
/// Marks an object as AES-GCM key.
pub trait AesGcmKey {
/// Provides access to the raw key material.
fn key(&self) -> &[u8];
}
impl<T: AesGcmKey> AesGcm for T {
fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
aes_gcm_decrypt(data, iv, tag, self.key()).context(ks_err!("Decryption failed"))
}
fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
aes_gcm_encrypt(plaintext, self.key()).context(ks_err!("Encryption failed."))
}
}
pub(crate) fn retry_get_interface<T: FromIBinder + ?Sized>(
name: &str,
) -> Result<Strong<T>, StatusCode> {
let retry_count = if cfg!(early_vm) { 5 } else { 1 };
let mut wait_time = Duration::from_secs(5);
for i in 1..retry_count {
match binder::get_interface(name) {
Ok(res) => return Ok(res),
Err(e) => {
warn!("failed to get interface {name}. Retry {i}/{retry_count}: {e:?}");
sleep(wait_time);
wait_time *= 2;
}
}
}
if retry_count > 1 {
info!("{retry_count}-th (last) retry to get interface: {name}");
}
binder::get_interface(name)
}