blob: 07c3d64f61f0f7166a436628564404e30df409f5 [file] [log] [blame]
// Copyright 2021, 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 provides convenience functions for keystore2 logging.
use crate::error::get_error_code;
use crate::globals::{DB, LOGS_HANDLER};
use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
use crate::operation::Outcome;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
SecurityLevel::SecurityLevel,
};
use anyhow::Result;
use keystore2_system_property::PropertyWatcher;
use statslog_rust::{
keystore2_key_creation_event_reported::{
Algorithm as StatsdAlgorithm, EcCurve as StatsdEcCurve, KeyOrigin as StatsdKeyOrigin,
Keystore2KeyCreationEventReported, SecurityLevel as StatsdKeyCreationSecurityLevel,
UserAuthType as StatsdUserAuthType,
},
keystore2_key_operation_event_reported::{
Keystore2KeyOperationEventReported, Outcome as StatsdOutcome, Purpose as StatsdKeyPurpose,
SecurityLevel as StatsdKeyOperationSecurityLevel,
},
keystore2_storage_stats::StorageType as StatsdStorageType,
};
use statslog_rust_header::Atoms;
use statspull_rust::{set_pull_atom_callback, StatsPullResult};
fn create_default_key_creation_atom() -> Keystore2KeyCreationEventReported {
// If a value is not present, fields represented by bitmaps and i32 fields
// will take 0, except error_code which defaults to 1 indicating NO_ERROR and key_size,
// and auth_time_out which default to -1.
// The boolean fields are set to false by default.
// Some keymint enums do have 0 as an enum variant value. In such cases, the corresponding
// enum variant value in atoms.proto is incremented by 1, in order to have 0 as the reserved
// value for unspecified fields.
Keystore2KeyCreationEventReported {
algorithm: StatsdAlgorithm::AlgorithmUnspecified,
key_size: -1,
key_origin: StatsdKeyOrigin::OriginUnspecified,
user_auth_type: StatsdUserAuthType::AuthTypeUnspecified,
user_auth_key_timeout_seconds: -1,
padding_mode_bitmap: 0,
digest_bitmap: 0,
block_mode_bitmap: 0,
purpose_bitmap: 0,
ec_curve: StatsdEcCurve::EcCurveUnspecified,
// as per keystore2/ResponseCode.aidl, 1 is reserved for NO_ERROR
error_code: 1,
attestation_requested: false,
security_level: StatsdKeyCreationSecurityLevel::SecurityLevelUnspecified,
}
}
fn create_default_key_operation_atom() -> Keystore2KeyOperationEventReported {
Keystore2KeyOperationEventReported {
purpose: StatsdKeyPurpose::KeyPurposeUnspecified,
padding_mode_bitmap: 0,
digest_bitmap: 0,
block_mode_bitmap: 0,
outcome: StatsdOutcome::OutcomeUnspecified,
error_code: 1,
key_upgraded: false,
security_level: StatsdKeyOperationSecurityLevel::SecurityLevelUnspecified,
}
}
/// Log key creation events via statsd API.
pub fn log_key_creation_event_stats<U>(
sec_level: SecurityLevel,
key_params: &[KeyParameter],
result: &Result<U>,
) {
let key_creation_event_stats =
construct_key_creation_event_stats(sec_level, key_params, result);
LOGS_HANDLER.queue_lo(move |_| {
let logging_result = key_creation_event_stats.stats_write();
if let Err(e) = logging_result {
log::error!("Error in logging key creation event in the async task. {:?}", e);
}
});
}
/// Log key operation events via statsd API.
pub fn log_key_operation_event_stats(
sec_level: SecurityLevel,
key_purpose: KeyPurpose,
op_params: &[KeyParameter],
op_outcome: &Outcome,
key_upgraded: bool,
) {
let key_operation_event_stats = construct_key_operation_event_stats(
sec_level,
key_purpose,
op_params,
op_outcome,
key_upgraded,
);
LOGS_HANDLER.queue_lo(move |_| {
let logging_result = key_operation_event_stats.stats_write();
if let Err(e) = logging_result {
log::error!("Error in logging key operation event in the async task. {:?}", e);
}
});
}
fn construct_key_creation_event_stats<U>(
sec_level: SecurityLevel,
key_params: &[KeyParameter],
result: &Result<U>,
) -> Keystore2KeyCreationEventReported {
let mut key_creation_event_atom = create_default_key_creation_atom();
if let Err(ref e) = result {
key_creation_event_atom.error_code = get_error_code(e);
}
key_creation_event_atom.security_level = match sec_level {
SecurityLevel::SOFTWARE => StatsdKeyCreationSecurityLevel::SecurityLevelSoftware,
SecurityLevel::TRUSTED_ENVIRONMENT => {
StatsdKeyCreationSecurityLevel::SecurityLevelTrustedEnvironment
}
SecurityLevel::STRONGBOX => StatsdKeyCreationSecurityLevel::SecurityLevelStrongbox,
//KEYSTORE is not a valid variant here
_ => StatsdKeyCreationSecurityLevel::SecurityLevelUnspecified,
};
for key_param in key_params.iter().map(KsKeyParamValue::from) {
match key_param {
KsKeyParamValue::Algorithm(a) => {
key_creation_event_atom.algorithm = match a {
Algorithm::RSA => StatsdAlgorithm::Rsa,
Algorithm::EC => StatsdAlgorithm::Ec,
Algorithm::AES => StatsdAlgorithm::Aes,
Algorithm::TRIPLE_DES => StatsdAlgorithm::TripleDes,
Algorithm::HMAC => StatsdAlgorithm::Hmac,
_ => StatsdAlgorithm::AlgorithmUnspecified,
}
}
KsKeyParamValue::KeySize(s) => {
key_creation_event_atom.key_size = s;
}
KsKeyParamValue::KeyOrigin(o) => {
key_creation_event_atom.key_origin = match o {
KeyOrigin::GENERATED => StatsdKeyOrigin::Generated,
KeyOrigin::DERIVED => StatsdKeyOrigin::Derived,
KeyOrigin::IMPORTED => StatsdKeyOrigin::Imported,
KeyOrigin::RESERVED => StatsdKeyOrigin::Reserved,
KeyOrigin::SECURELY_IMPORTED => StatsdKeyOrigin::SecurelyImported,
_ => StatsdKeyOrigin::OriginUnspecified,
}
}
KsKeyParamValue::HardwareAuthenticatorType(a) => {
key_creation_event_atom.user_auth_type = match a {
HardwareAuthenticatorType::NONE => StatsdUserAuthType::None,
HardwareAuthenticatorType::PASSWORD => StatsdUserAuthType::Password,
HardwareAuthenticatorType::FINGERPRINT => StatsdUserAuthType::Fingerprint,
HardwareAuthenticatorType::ANY => StatsdUserAuthType::Any,
_ => StatsdUserAuthType::AuthTypeUnspecified,
}
}
KsKeyParamValue::AuthTimeout(t) => {
key_creation_event_atom.user_auth_key_timeout_seconds = t;
}
KsKeyParamValue::PaddingMode(p) => {
key_creation_event_atom.padding_mode_bitmap =
compute_padding_mode_bitmap(&key_creation_event_atom.padding_mode_bitmap, p);
}
KsKeyParamValue::Digest(d) => {
key_creation_event_atom.digest_bitmap =
compute_digest_bitmap(&key_creation_event_atom.digest_bitmap, d);
}
KsKeyParamValue::BlockMode(b) => {
key_creation_event_atom.block_mode_bitmap =
compute_block_mode_bitmap(&key_creation_event_atom.block_mode_bitmap, b);
}
KsKeyParamValue::KeyPurpose(k) => {
key_creation_event_atom.purpose_bitmap =
compute_purpose_bitmap(&key_creation_event_atom.purpose_bitmap, k);
}
KsKeyParamValue::EcCurve(e) => {
key_creation_event_atom.ec_curve = match e {
EcCurve::P_224 => StatsdEcCurve::P224,
EcCurve::P_256 => StatsdEcCurve::P256,
EcCurve::P_384 => StatsdEcCurve::P384,
EcCurve::P_521 => StatsdEcCurve::P521,
_ => StatsdEcCurve::EcCurveUnspecified,
}
}
KsKeyParamValue::AttestationChallenge(_) => {
key_creation_event_atom.attestation_requested = true;
}
_ => {}
}
}
key_creation_event_atom
}
fn construct_key_operation_event_stats(
sec_level: SecurityLevel,
key_purpose: KeyPurpose,
op_params: &[KeyParameter],
op_outcome: &Outcome,
key_upgraded: bool,
) -> Keystore2KeyOperationEventReported {
let mut key_operation_event_atom = create_default_key_operation_atom();
key_operation_event_atom.security_level = match sec_level {
SecurityLevel::SOFTWARE => StatsdKeyOperationSecurityLevel::SecurityLevelSoftware,
SecurityLevel::TRUSTED_ENVIRONMENT => {
StatsdKeyOperationSecurityLevel::SecurityLevelTrustedEnvironment
}
SecurityLevel::STRONGBOX => StatsdKeyOperationSecurityLevel::SecurityLevelStrongbox,
//KEYSTORE is not a valid variant here
_ => StatsdKeyOperationSecurityLevel::SecurityLevelUnspecified,
};
key_operation_event_atom.key_upgraded = key_upgraded;
key_operation_event_atom.purpose = match key_purpose {
KeyPurpose::ENCRYPT => StatsdKeyPurpose::Encrypt,
KeyPurpose::DECRYPT => StatsdKeyPurpose::Decrypt,
KeyPurpose::SIGN => StatsdKeyPurpose::Sign,
KeyPurpose::VERIFY => StatsdKeyPurpose::Verify,
KeyPurpose::WRAP_KEY => StatsdKeyPurpose::WrapKey,
KeyPurpose::AGREE_KEY => StatsdKeyPurpose::AgreeKey,
KeyPurpose::ATTEST_KEY => StatsdKeyPurpose::AttestKey,
_ => StatsdKeyPurpose::KeyPurposeUnspecified,
};
key_operation_event_atom.outcome = match op_outcome {
Outcome::Unknown | Outcome::Dropped => StatsdOutcome::Dropped,
Outcome::Success => StatsdOutcome::Success,
Outcome::Abort => StatsdOutcome::Abort,
Outcome::Pruned => StatsdOutcome::Pruned,
Outcome::ErrorCode(e) => {
key_operation_event_atom.error_code = e.0;
StatsdOutcome::Error
}
};
for key_param in op_params.iter().map(KsKeyParamValue::from) {
match key_param {
KsKeyParamValue::PaddingMode(p) => {
key_operation_event_atom.padding_mode_bitmap =
compute_padding_mode_bitmap(&key_operation_event_atom.padding_mode_bitmap, p);
}
KsKeyParamValue::Digest(d) => {
key_operation_event_atom.digest_bitmap =
compute_digest_bitmap(&key_operation_event_atom.digest_bitmap, d);
}
KsKeyParamValue::BlockMode(b) => {
key_operation_event_atom.block_mode_bitmap =
compute_block_mode_bitmap(&key_operation_event_atom.block_mode_bitmap, b);
}
_ => {}
}
}
key_operation_event_atom
}
fn compute_purpose_bitmap(purpose_bitmap: &i32, purpose: KeyPurpose) -> i32 {
let mut bitmap = *purpose_bitmap;
match purpose {
KeyPurpose::ENCRYPT => {
bitmap |= 1 << KeyPurposeBitPosition::ENCRYPT_BIT_POS as i32;
}
KeyPurpose::DECRYPT => {
bitmap |= 1 << KeyPurposeBitPosition::DECRYPT_BIT_POS as i32;
}
KeyPurpose::SIGN => {
bitmap |= 1 << KeyPurposeBitPosition::SIGN_BIT_POS as i32;
}
KeyPurpose::VERIFY => {
bitmap |= 1 << KeyPurposeBitPosition::VERIFY_BIT_POS as i32;
}
KeyPurpose::WRAP_KEY => {
bitmap |= 1 << KeyPurposeBitPosition::WRAP_KEY_BIT_POS as i32;
}
KeyPurpose::AGREE_KEY => {
bitmap |= 1 << KeyPurposeBitPosition::AGREE_KEY_BIT_POS as i32;
}
KeyPurpose::ATTEST_KEY => {
bitmap |= 1 << KeyPurposeBitPosition::ATTEST_KEY_BIT_POS as i32;
}
_ => {}
}
bitmap
}
fn compute_padding_mode_bitmap(padding_mode_bitmap: &i32, padding_mode: PaddingMode) -> i32 {
let mut bitmap = *padding_mode_bitmap;
match padding_mode {
PaddingMode::NONE => {
bitmap |= 1 << PaddingModeBitPosition::NONE_BIT_POSITION as i32;
}
PaddingMode::RSA_OAEP => {
bitmap |= 1 << PaddingModeBitPosition::RSA_OAEP_BIT_POS as i32;
}
PaddingMode::RSA_PSS => {
bitmap |= 1 << PaddingModeBitPosition::RSA_PSS_BIT_POS as i32;
}
PaddingMode::RSA_PKCS1_1_5_ENCRYPT => {
bitmap |= 1 << PaddingModeBitPosition::RSA_PKCS1_1_5_ENCRYPT_BIT_POS as i32;
}
PaddingMode::RSA_PKCS1_1_5_SIGN => {
bitmap |= 1 << PaddingModeBitPosition::RSA_PKCS1_1_5_SIGN_BIT_POS as i32;
}
PaddingMode::PKCS7 => {
bitmap |= 1 << PaddingModeBitPosition::PKCS7_BIT_POS as i32;
}
_ => {}
}
bitmap
}
fn compute_digest_bitmap(digest_bitmap: &i32, digest: Digest) -> i32 {
let mut bitmap = *digest_bitmap;
match digest {
Digest::NONE => {
bitmap |= 1 << DigestBitPosition::NONE_BIT_POSITION as i32;
}
Digest::MD5 => {
bitmap |= 1 << DigestBitPosition::MD5_BIT_POS as i32;
}
Digest::SHA1 => {
bitmap |= 1 << DigestBitPosition::SHA_1_BIT_POS as i32;
}
Digest::SHA_2_224 => {
bitmap |= 1 << DigestBitPosition::SHA_2_224_BIT_POS as i32;
}
Digest::SHA_2_256 => {
bitmap |= 1 << DigestBitPosition::SHA_2_256_BIT_POS as i32;
}
Digest::SHA_2_384 => {
bitmap |= 1 << DigestBitPosition::SHA_2_384_BIT_POS as i32;
}
Digest::SHA_2_512 => {
bitmap |= 1 << DigestBitPosition::SHA_2_512_BIT_POS as i32;
}
_ => {}
}
bitmap
}
fn compute_block_mode_bitmap(block_mode_bitmap: &i32, block_mode: BlockMode) -> i32 {
let mut bitmap = *block_mode_bitmap;
match block_mode {
BlockMode::ECB => {
bitmap |= 1 << BlockModeBitPosition::ECB_BIT_POS as i32;
}
BlockMode::CBC => {
bitmap |= 1 << BlockModeBitPosition::CBC_BIT_POS as i32;
}
BlockMode::CTR => {
bitmap |= 1 << BlockModeBitPosition::CTR_BIT_POS as i32;
}
BlockMode::GCM => {
bitmap |= 1 << BlockModeBitPosition::GCM_BIT_POS as i32;
}
_ => {}
}
bitmap
}
/// Registers pull metrics callbacks
pub fn register_pull_metrics_callbacks() -> Result<()> {
// Before registering the callbacks with statsd, we have to wait for the system to finish
// booting up. This avoids possible races that may occur at startup. For example, statsd
// depends on a companion service, and if registration happens too soon it will fail since
// the companion service isn't up yet.
let mut watcher = PropertyWatcher::new("sys.boot_completed")?;
loop {
watcher.wait()?;
let value = watcher.read(|_name, value| Ok(value.trim().to_string()));
if value? == "1" {
set_pull_atom_callback(Atoms::Keystore2StorageStats, None, pull_metrics_callback);
break;
}
}
Ok(())
}
fn pull_metrics_callback() -> StatsPullResult {
let mut result = StatsPullResult::new();
let mut append = |stat| {
match stat {
Ok(s) => result.push(Box::new(s)),
Err(error) => {
log::error!("pull_metrics_callback: Error getting storage stat: {}", error)
}
};
};
DB.with(|db| {
let mut db = db.borrow_mut();
append(db.get_storage_stat(StatsdStorageType::Database));
append(db.get_storage_stat(StatsdStorageType::KeyEntry));
append(db.get_storage_stat(StatsdStorageType::KeyEntryIdIndex));
append(db.get_storage_stat(StatsdStorageType::KeyEntryDomainNamespaceIndex));
append(db.get_storage_stat(StatsdStorageType::BlobEntry));
append(db.get_storage_stat(StatsdStorageType::BlobEntryKeyEntryIdIndex));
append(db.get_storage_stat(StatsdStorageType::KeyParameter));
append(db.get_storage_stat(StatsdStorageType::KeyParameterKeyEntryIdIndex));
append(db.get_storage_stat(StatsdStorageType::KeyMetadata));
append(db.get_storage_stat(StatsdStorageType::KeyMetadataKeyEntryIdIndex));
append(db.get_storage_stat(StatsdStorageType::Grant));
append(db.get_storage_stat(StatsdStorageType::AuthToken));
append(db.get_storage_stat(StatsdStorageType::BlobMetadata));
append(db.get_storage_stat(StatsdStorageType::BlobMetadataBlobEntryIdIndex));
});
result
}
/// Enum defining the bit position for each padding mode. Since padding mode can be repeatable, it
/// is represented using a bitmap.
#[allow(non_camel_case_types)]
#[repr(i32)]
pub enum PaddingModeBitPosition {
///Bit position in the PaddingMode bitmap for NONE.
NONE_BIT_POSITION = 0,
///Bit position in the PaddingMode bitmap for RSA_OAEP.
RSA_OAEP_BIT_POS = 1,
///Bit position in the PaddingMode bitmap for RSA_PSS.
RSA_PSS_BIT_POS = 2,
///Bit position in the PaddingMode bitmap for RSA_PKCS1_1_5_ENCRYPT.
RSA_PKCS1_1_5_ENCRYPT_BIT_POS = 3,
///Bit position in the PaddingMode bitmap for RSA_PKCS1_1_5_SIGN.
RSA_PKCS1_1_5_SIGN_BIT_POS = 4,
///Bit position in the PaddingMode bitmap for RSA_PKCS7.
PKCS7_BIT_POS = 5,
}
/// Enum defining the bit position for each digest type. Since digest can be repeatable in
/// key parameters, it is represented using a bitmap.
#[allow(non_camel_case_types)]
#[repr(i32)]
pub enum DigestBitPosition {
///Bit position in the Digest bitmap for NONE.
NONE_BIT_POSITION = 0,
///Bit position in the Digest bitmap for MD5.
MD5_BIT_POS = 1,
///Bit position in the Digest bitmap for SHA1.
SHA_1_BIT_POS = 2,
///Bit position in the Digest bitmap for SHA_2_224.
SHA_2_224_BIT_POS = 3,
///Bit position in the Digest bitmap for SHA_2_256.
SHA_2_256_BIT_POS = 4,
///Bit position in the Digest bitmap for SHA_2_384.
SHA_2_384_BIT_POS = 5,
///Bit position in the Digest bitmap for SHA_2_512.
SHA_2_512_BIT_POS = 6,
}
/// Enum defining the bit position for each block mode type. Since block mode can be repeatable in
/// key parameters, it is represented using a bitmap.
#[allow(non_camel_case_types)]
#[repr(i32)]
enum BlockModeBitPosition {
///Bit position in the BlockMode bitmap for ECB.
ECB_BIT_POS = 1,
///Bit position in the BlockMode bitmap for CBC.
CBC_BIT_POS = 2,
///Bit position in the BlockMode bitmap for CTR.
CTR_BIT_POS = 3,
///Bit position in the BlockMode bitmap for GCM.
GCM_BIT_POS = 4,
}
/// Enum defining the bit position for each key purpose. Since key purpose can be repeatable in
/// key parameters, it is represented using a bitmap.
#[allow(non_camel_case_types)]
#[repr(i32)]
enum KeyPurposeBitPosition {
///Bit position in the KeyPurpose bitmap for Encrypt.
ENCRYPT_BIT_POS = 1,
///Bit position in the KeyPurpose bitmap for Decrypt.
DECRYPT_BIT_POS = 2,
///Bit position in the KeyPurpose bitmap for Sign.
SIGN_BIT_POS = 3,
///Bit position in the KeyPurpose bitmap for Verify.
VERIFY_BIT_POS = 4,
///Bit position in the KeyPurpose bitmap for Wrap Key.
WRAP_KEY_BIT_POS = 5,
///Bit position in the KeyPurpose bitmap for Agree Key.
AGREE_KEY_BIT_POS = 6,
///Bit position in the KeyPurpose bitmap for Attest Key.
ATTEST_KEY_BIT_POS = 7,
}