| // 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, |
| } |