blob: 72bbfe297a6fd09cfe7ef09b2e3fb98209439db4 [file] [log] [blame]
Hasini Gunasinghe15891e62021-06-10 16:23:27 +00001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This is the metrics store module of keystore. It does the following tasks:
16//! 1. Processes the data about keystore events asynchronously, and
17//! stores them in an in-memory store.
18//! 2. Returns the collected metrics when requested by the statsd proxy.
19
Tri Vocd6fc7a2023-08-31 11:46:32 -040020use crate::error::anyhow_error_to_serialized_error;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000021use crate::globals::DB;
22use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
Shaquille Johnson9da2e1c2022-09-19 12:39:01 +000023use crate::ks_err;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000024use crate::operation::Outcome;
David Drysdale703bcc12024-11-26 14:15:03 +000025use crate::utils::watchdog as wd;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000026use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
27 Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
28 HardwareAuthenticatorType::HardwareAuthenticatorType, KeyOrigin::KeyOrigin,
29 KeyParameter::KeyParameter, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
30 SecurityLevel::SecurityLevel,
31};
32use android_security_metrics::aidl::android::security::metrics::{
Hasini Gunasinghe365ce372021-07-02 23:13:11 +000033 Algorithm::Algorithm as MetricsAlgorithm, AtomID::AtomID, CrashStats::CrashStats,
34 EcCurve::EcCurve as MetricsEcCurve,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000035 HardwareAuthenticatorType::HardwareAuthenticatorType as MetricsHardwareAuthenticatorType,
36 KeyCreationWithAuthInfo::KeyCreationWithAuthInfo,
37 KeyCreationWithGeneralInfo::KeyCreationWithGeneralInfo,
38 KeyCreationWithPurposeAndModesInfo::KeyCreationWithPurposeAndModesInfo,
39 KeyOperationWithGeneralInfo::KeyOperationWithGeneralInfo,
40 KeyOperationWithPurposeAndModesInfo::KeyOperationWithPurposeAndModesInfo,
41 KeyOrigin::KeyOrigin as MetricsKeyOrigin, Keystore2AtomWithOverflow::Keystore2AtomWithOverflow,
42 KeystoreAtom::KeystoreAtom, KeystoreAtomPayload::KeystoreAtomPayload,
43 Outcome::Outcome as MetricsOutcome, Purpose::Purpose as MetricsPurpose,
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +000044 RkpError::RkpError as MetricsRkpError, RkpErrorStats::RkpErrorStats,
Tri Voa1634bb2022-12-01 15:54:19 -080045 SecurityLevel::SecurityLevel as MetricsSecurityLevel, Storage::Storage as MetricsStorage,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000046};
Eric Biggers9f9ab182023-05-31 21:37:32 +000047use anyhow::{anyhow, Context, Result};
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000048use std::collections::HashMap;
Andrew Walbrana4bc1a92024-09-03 13:08:17 +010049use std::sync::{LazyLock, Mutex};
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000050
Hasini Gunasinghe365ce372021-07-02 23:13:11 +000051// Note: Crash events are recorded at keystore restarts, based on the assumption that keystore only
52// gets restarted after a crash, during a boot cycle.
53const KEYSTORE_CRASH_COUNT_PROPERTY: &str = "keystore.crash_count";
54
Andrew Walbrana4bc1a92024-09-03 13:08:17 +010055/// Singleton for MetricsStore.
56pub static METRICS_STORE: LazyLock<MetricsStore> = LazyLock::new(Default::default);
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000057
58/// MetricsStore stores the <atom object, count> as <key, value> in the inner hash map,
59/// indexed by the atom id, in the outer hash map.
60/// There can be different atom objects with the same atom id based on the values assigned to the
61/// fields of the atom objects. When an atom object with a particular combination of field values is
62/// inserted, we first check if that atom object is in the inner hash map. If one exists, count
63/// is inceremented. Otherwise, the atom object is inserted with count = 1. Note that count field
64/// of the atom object itself is set to 0 while the object is stored in the hash map. When the atom
65/// objects are queried by the atom id, the corresponding atom objects are retrieved, cloned, and
66/// the count field of the cloned objects is set to the corresponding value field in the inner hash
67/// map before the query result is returned.
68#[derive(Default)]
69pub struct MetricsStore {
70 metrics_store: Mutex<HashMap<AtomID, HashMap<KeystoreAtomPayload, i32>>>,
71}
72
David Drysdale49811e22023-05-22 18:51:30 +010073impl std::fmt::Debug for MetricsStore {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
75 let store = self.metrics_store.lock().unwrap();
76 let mut atom_ids: Vec<&AtomID> = store.keys().collect();
77 atom_ids.sort();
78 for atom_id in atom_ids {
79 writeln!(f, " {} : [", atom_id.show())?;
80 let data = store.get(atom_id).unwrap();
81 let mut payloads: Vec<&KeystoreAtomPayload> = data.keys().collect();
82 payloads.sort();
83 for payload in payloads {
84 let count = data.get(payload).unwrap();
85 writeln!(f, " {} => count={count}", payload.show())?;
86 }
87 writeln!(f, " ]")?;
88 }
89 Ok(())
90 }
91}
92
Hasini Gunasinghe15891e62021-06-10 16:23:27 +000093impl MetricsStore {
94 /// There are some atoms whose maximum cardinality exceeds the cardinality limits tolerated
95 /// by statsd. Statsd tolerates cardinality between 200-300. Therefore, the in-memory storage
96 /// limit for a single atom is set to 250. If the number of atom objects created for a
97 /// particular atom exceeds this limit, an overflow atom object is created to track the ID of
98 /// such atoms.
99 const SINGLE_ATOM_STORE_MAX_SIZE: usize = 250;
100
101 /// Return a vector of atom objects with the given atom ID, if one exists in the metrics_store.
102 /// If any atom object does not exist in the metrics_store for the given atom ID, return an
103 /// empty vector.
104 pub fn get_atoms(&self, atom_id: AtomID) -> Result<Vec<KeystoreAtom>> {
105 // StorageStats is an original pulled atom (i.e. not a pushed atom converted to a
David Drysdale49811e22023-05-22 18:51:30 +0100106 // pulled atom). Therefore, it is handled separately.
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000107 if AtomID::STORAGE_STATS == atom_id {
David Drysdale703bcc12024-11-26 14:15:03 +0000108 let _wp = wd::watch("MetricsStore::get_atoms calling pull_storage_stats");
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000109 return pull_storage_stats();
110 }
111
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000112 // Process keystore crash stats.
113 if AtomID::CRASH_STATS == atom_id {
David Drysdale703bcc12024-11-26 14:15:03 +0000114 let _wp = wd::watch("MetricsStore::get_atoms calling read_keystore_crash_count");
Eric Biggers9f9ab182023-05-31 21:37:32 +0000115 return match read_keystore_crash_count()? {
116 Some(count) => Ok(vec![KeystoreAtom {
117 payload: KeystoreAtomPayload::CrashStats(CrashStats {
118 count_of_crash_events: count,
119 }),
120 ..Default::default()
121 }]),
122 None => Err(anyhow!("Crash count property is not set")),
123 };
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000124 }
125
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000126 let metrics_store_guard = self.metrics_store.lock().unwrap();
127 metrics_store_guard.get(&atom_id).map_or(Ok(Vec::<KeystoreAtom>::new()), |atom_count_map| {
128 Ok(atom_count_map
129 .iter()
130 .map(|(atom, count)| KeystoreAtom { payload: atom.clone(), count: *count })
131 .collect())
132 })
133 }
134
135 /// Insert an atom object to the metrics_store indexed by the atom ID.
136 fn insert_atom(&self, atom_id: AtomID, atom: KeystoreAtomPayload) {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000137 let mut metrics_store_guard = self.metrics_store.lock().unwrap();
Charisee6fff58e2023-10-14 21:09:04 +0000138 let atom_count_map = metrics_store_guard.entry(atom_id).or_default();
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000139 if atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
140 let atom_count = atom_count_map.entry(atom).or_insert(0);
141 *atom_count += 1;
142 } else {
143 // Insert an overflow atom
Charisee6fff58e2023-10-14 21:09:04 +0000144 let overflow_atom_count_map =
145 metrics_store_guard.entry(AtomID::KEYSTORE2_ATOM_WITH_OVERFLOW).or_default();
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000146
147 if overflow_atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
148 let overflow_atom = Keystore2AtomWithOverflow { atom_id };
149 let atom_count = overflow_atom_count_map
150 .entry(KeystoreAtomPayload::Keystore2AtomWithOverflow(overflow_atom))
151 .or_insert(0);
152 *atom_count += 1;
153 } else {
154 // This is a rare case, if at all.
155 log::error!("In insert_atom: Maximum storage limit reached for overflow atom.")
156 }
157 }
158 }
159}
160
161/// Log key creation events to be sent to statsd.
162pub fn log_key_creation_event_stats<U>(
163 sec_level: SecurityLevel,
164 key_params: &[KeyParameter],
165 result: &Result<U>,
166) {
167 let (
168 key_creation_with_general_info,
169 key_creation_with_auth_info,
170 key_creation_with_purpose_and_modes_info,
171 ) = process_key_creation_event_stats(sec_level, key_params, result);
172
173 METRICS_STORE
174 .insert_atom(AtomID::KEY_CREATION_WITH_GENERAL_INFO, key_creation_with_general_info);
175 METRICS_STORE.insert_atom(AtomID::KEY_CREATION_WITH_AUTH_INFO, key_creation_with_auth_info);
176 METRICS_STORE.insert_atom(
177 AtomID::KEY_CREATION_WITH_PURPOSE_AND_MODES_INFO,
178 key_creation_with_purpose_and_modes_info,
179 );
180}
181
182// Process the statistics related to key creations and return the three atom objects related to key
183// creations: i) KeyCreationWithGeneralInfo ii) KeyCreationWithAuthInfo
184// iii) KeyCreationWithPurposeAndModesInfo
185fn process_key_creation_event_stats<U>(
186 sec_level: SecurityLevel,
187 key_params: &[KeyParameter],
188 result: &Result<U>,
189) -> (KeystoreAtomPayload, KeystoreAtomPayload, KeystoreAtomPayload) {
190 // In the default atom objects, fields represented by bitmaps and i32 fields
191 // will take 0, except error_code which defaults to 1 indicating NO_ERROR and key_size,
192 // and auth_time_out which defaults to -1.
193 // The boolean fields are set to false by default.
194 // Some keymint enums do have 0 as an enum variant value. In such cases, the corresponding
195 // enum variant value in atoms.proto is incremented by 1, in order to have 0 as the reserved
196 // value for unspecified fields.
197 let mut key_creation_with_general_info = KeyCreationWithGeneralInfo {
198 algorithm: MetricsAlgorithm::ALGORITHM_UNSPECIFIED,
199 key_size: -1,
200 ec_curve: MetricsEcCurve::EC_CURVE_UNSPECIFIED,
201 key_origin: MetricsKeyOrigin::ORIGIN_UNSPECIFIED,
202 error_code: 1,
203 // Default for bool is false (for attestation_requested field).
204 ..Default::default()
205 };
206
207 let mut key_creation_with_auth_info = KeyCreationWithAuthInfo {
Catherine Vlasov71817432025-01-15 16:30:13 +0000208 user_auth_type: MetricsHardwareAuthenticatorType::NO_AUTH_TYPE,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000209 log10_auth_key_timeout_seconds: -1,
210 security_level: MetricsSecurityLevel::SECURITY_LEVEL_UNSPECIFIED,
211 };
212
213 let mut key_creation_with_purpose_and_modes_info = KeyCreationWithPurposeAndModesInfo {
214 algorithm: MetricsAlgorithm::ALGORITHM_UNSPECIFIED,
215 // Default for i32 is 0 (for the remaining bitmap fields).
216 ..Default::default()
217 };
218
219 if let Err(ref e) = result {
Tri Vocd6fc7a2023-08-31 11:46:32 -0400220 key_creation_with_general_info.error_code = anyhow_error_to_serialized_error(e).0;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000221 }
222
223 key_creation_with_auth_info.security_level = process_security_level(sec_level);
224
225 for key_param in key_params.iter().map(KsKeyParamValue::from) {
226 match key_param {
227 KsKeyParamValue::Algorithm(a) => {
228 let algorithm = match a {
229 Algorithm::RSA => MetricsAlgorithm::RSA,
230 Algorithm::EC => MetricsAlgorithm::EC,
231 Algorithm::AES => MetricsAlgorithm::AES,
232 Algorithm::TRIPLE_DES => MetricsAlgorithm::TRIPLE_DES,
233 Algorithm::HMAC => MetricsAlgorithm::HMAC,
234 _ => MetricsAlgorithm::ALGORITHM_UNSPECIFIED,
235 };
236 key_creation_with_general_info.algorithm = algorithm;
237 key_creation_with_purpose_and_modes_info.algorithm = algorithm;
238 }
239 KsKeyParamValue::KeySize(s) => {
240 key_creation_with_general_info.key_size = s;
241 }
242 KsKeyParamValue::KeyOrigin(o) => {
243 key_creation_with_general_info.key_origin = match o {
244 KeyOrigin::GENERATED => MetricsKeyOrigin::GENERATED,
245 KeyOrigin::DERIVED => MetricsKeyOrigin::DERIVED,
246 KeyOrigin::IMPORTED => MetricsKeyOrigin::IMPORTED,
247 KeyOrigin::RESERVED => MetricsKeyOrigin::RESERVED,
248 KeyOrigin::SECURELY_IMPORTED => MetricsKeyOrigin::SECURELY_IMPORTED,
249 _ => MetricsKeyOrigin::ORIGIN_UNSPECIFIED,
250 }
251 }
252 KsKeyParamValue::HardwareAuthenticatorType(a) => {
253 key_creation_with_auth_info.user_auth_type = match a {
254 HardwareAuthenticatorType::NONE => MetricsHardwareAuthenticatorType::NONE,
255 HardwareAuthenticatorType::PASSWORD => {
256 MetricsHardwareAuthenticatorType::PASSWORD
257 }
258 HardwareAuthenticatorType::FINGERPRINT => {
259 MetricsHardwareAuthenticatorType::FINGERPRINT
260 }
Catherine Vlasov71817432025-01-15 16:30:13 +0000261 a if a.0
262 == HardwareAuthenticatorType::PASSWORD.0
263 | HardwareAuthenticatorType::FINGERPRINT.0 =>
264 {
265 MetricsHardwareAuthenticatorType::PASSWORD_OR_FINGERPRINT
266 }
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000267 HardwareAuthenticatorType::ANY => MetricsHardwareAuthenticatorType::ANY,
268 _ => MetricsHardwareAuthenticatorType::AUTH_TYPE_UNSPECIFIED,
269 }
270 }
271 KsKeyParamValue::AuthTimeout(t) => {
272 key_creation_with_auth_info.log10_auth_key_timeout_seconds =
273 f32::log10(t as f32) as i32;
274 }
275 KsKeyParamValue::PaddingMode(p) => {
276 compute_padding_mode_bitmap(
277 &mut key_creation_with_purpose_and_modes_info.padding_mode_bitmap,
278 p,
279 );
280 }
281 KsKeyParamValue::Digest(d) => {
282 // key_creation_with_purpose_and_modes_info.digest_bitmap =
283 compute_digest_bitmap(
284 &mut key_creation_with_purpose_and_modes_info.digest_bitmap,
285 d,
286 );
287 }
288 KsKeyParamValue::BlockMode(b) => {
289 compute_block_mode_bitmap(
290 &mut key_creation_with_purpose_and_modes_info.block_mode_bitmap,
291 b,
292 );
293 }
294 KsKeyParamValue::KeyPurpose(k) => {
295 compute_purpose_bitmap(
296 &mut key_creation_with_purpose_and_modes_info.purpose_bitmap,
297 k,
298 );
299 }
300 KsKeyParamValue::EcCurve(e) => {
301 key_creation_with_general_info.ec_curve = match e {
302 EcCurve::P_224 => MetricsEcCurve::P_224,
303 EcCurve::P_256 => MetricsEcCurve::P_256,
304 EcCurve::P_384 => MetricsEcCurve::P_384,
305 EcCurve::P_521 => MetricsEcCurve::P_521,
Seth Moore49d700d2021-12-13 20:03:33 +0000306 EcCurve::CURVE_25519 => MetricsEcCurve::CURVE_25519,
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000307 _ => MetricsEcCurve::EC_CURVE_UNSPECIFIED,
308 }
309 }
310 KsKeyParamValue::AttestationChallenge(_) => {
311 key_creation_with_general_info.attestation_requested = true;
312 }
313 _ => {}
314 }
315 }
316 if key_creation_with_general_info.algorithm == MetricsAlgorithm::EC {
317 // Do not record key sizes if Algorithm = EC, in order to reduce cardinality.
318 key_creation_with_general_info.key_size = -1;
319 }
320
321 (
322 KeystoreAtomPayload::KeyCreationWithGeneralInfo(key_creation_with_general_info),
323 KeystoreAtomPayload::KeyCreationWithAuthInfo(key_creation_with_auth_info),
324 KeystoreAtomPayload::KeyCreationWithPurposeAndModesInfo(
325 key_creation_with_purpose_and_modes_info,
326 ),
327 )
328}
329
330/// Log key operation events to be sent to statsd.
331pub fn log_key_operation_event_stats(
332 sec_level: SecurityLevel,
333 key_purpose: KeyPurpose,
334 op_params: &[KeyParameter],
335 op_outcome: &Outcome,
336 key_upgraded: bool,
337) {
338 let (key_operation_with_general_info, key_operation_with_purpose_and_modes_info) =
339 process_key_operation_event_stats(
340 sec_level,
341 key_purpose,
342 op_params,
343 op_outcome,
344 key_upgraded,
345 );
346 METRICS_STORE
347 .insert_atom(AtomID::KEY_OPERATION_WITH_GENERAL_INFO, key_operation_with_general_info);
348 METRICS_STORE.insert_atom(
349 AtomID::KEY_OPERATION_WITH_PURPOSE_AND_MODES_INFO,
350 key_operation_with_purpose_and_modes_info,
351 );
352}
353
354// Process the statistics related to key operations and return the two atom objects related to key
355// operations: i) KeyOperationWithGeneralInfo ii) KeyOperationWithPurposeAndModesInfo
356fn process_key_operation_event_stats(
357 sec_level: SecurityLevel,
358 key_purpose: KeyPurpose,
359 op_params: &[KeyParameter],
360 op_outcome: &Outcome,
361 key_upgraded: bool,
362) -> (KeystoreAtomPayload, KeystoreAtomPayload) {
363 let mut key_operation_with_general_info = KeyOperationWithGeneralInfo {
364 outcome: MetricsOutcome::OUTCOME_UNSPECIFIED,
365 error_code: 1,
366 security_level: MetricsSecurityLevel::SECURITY_LEVEL_UNSPECIFIED,
367 // Default for bool is false (for key_upgraded field).
368 ..Default::default()
369 };
370
371 let mut key_operation_with_purpose_and_modes_info = KeyOperationWithPurposeAndModesInfo {
372 purpose: MetricsPurpose::KEY_PURPOSE_UNSPECIFIED,
373 // Default for i32 is 0 (for the remaining bitmap fields).
374 ..Default::default()
375 };
376
377 key_operation_with_general_info.security_level = process_security_level(sec_level);
378
379 key_operation_with_general_info.key_upgraded = key_upgraded;
380
381 key_operation_with_purpose_and_modes_info.purpose = match key_purpose {
382 KeyPurpose::ENCRYPT => MetricsPurpose::ENCRYPT,
383 KeyPurpose::DECRYPT => MetricsPurpose::DECRYPT,
384 KeyPurpose::SIGN => MetricsPurpose::SIGN,
385 KeyPurpose::VERIFY => MetricsPurpose::VERIFY,
386 KeyPurpose::WRAP_KEY => MetricsPurpose::WRAP_KEY,
387 KeyPurpose::AGREE_KEY => MetricsPurpose::AGREE_KEY,
388 KeyPurpose::ATTEST_KEY => MetricsPurpose::ATTEST_KEY,
389 _ => MetricsPurpose::KEY_PURPOSE_UNSPECIFIED,
390 };
391
392 key_operation_with_general_info.outcome = match op_outcome {
393 Outcome::Unknown | Outcome::Dropped => MetricsOutcome::DROPPED,
394 Outcome::Success => MetricsOutcome::SUCCESS,
395 Outcome::Abort => MetricsOutcome::ABORT,
396 Outcome::Pruned => MetricsOutcome::PRUNED,
397 Outcome::ErrorCode(e) => {
398 key_operation_with_general_info.error_code = e.0;
399 MetricsOutcome::ERROR
400 }
401 };
402
403 for key_param in op_params.iter().map(KsKeyParamValue::from) {
404 match key_param {
405 KsKeyParamValue::PaddingMode(p) => {
406 compute_padding_mode_bitmap(
407 &mut key_operation_with_purpose_and_modes_info.padding_mode_bitmap,
408 p,
409 );
410 }
411 KsKeyParamValue::Digest(d) => {
412 compute_digest_bitmap(
413 &mut key_operation_with_purpose_and_modes_info.digest_bitmap,
414 d,
415 );
416 }
417 KsKeyParamValue::BlockMode(b) => {
418 compute_block_mode_bitmap(
419 &mut key_operation_with_purpose_and_modes_info.block_mode_bitmap,
420 b,
421 );
422 }
423 _ => {}
424 }
425 }
426
427 (
428 KeystoreAtomPayload::KeyOperationWithGeneralInfo(key_operation_with_general_info),
429 KeystoreAtomPayload::KeyOperationWithPurposeAndModesInfo(
430 key_operation_with_purpose_and_modes_info,
431 ),
432 )
433}
434
435fn process_security_level(sec_level: SecurityLevel) -> MetricsSecurityLevel {
436 match sec_level {
437 SecurityLevel::SOFTWARE => MetricsSecurityLevel::SECURITY_LEVEL_SOFTWARE,
438 SecurityLevel::TRUSTED_ENVIRONMENT => {
439 MetricsSecurityLevel::SECURITY_LEVEL_TRUSTED_ENVIRONMENT
440 }
441 SecurityLevel::STRONGBOX => MetricsSecurityLevel::SECURITY_LEVEL_STRONGBOX,
442 SecurityLevel::KEYSTORE => MetricsSecurityLevel::SECURITY_LEVEL_KEYSTORE,
443 _ => MetricsSecurityLevel::SECURITY_LEVEL_UNSPECIFIED,
444 }
445}
446
447fn compute_padding_mode_bitmap(padding_mode_bitmap: &mut i32, padding_mode: PaddingMode) {
448 match padding_mode {
449 PaddingMode::NONE => {
450 *padding_mode_bitmap |= 1 << PaddingModeBitPosition::NONE_BIT_POSITION as i32;
451 }
452 PaddingMode::RSA_OAEP => {
453 *padding_mode_bitmap |= 1 << PaddingModeBitPosition::RSA_OAEP_BIT_POS as i32;
454 }
455 PaddingMode::RSA_PSS => {
456 *padding_mode_bitmap |= 1 << PaddingModeBitPosition::RSA_PSS_BIT_POS as i32;
457 }
458 PaddingMode::RSA_PKCS1_1_5_ENCRYPT => {
459 *padding_mode_bitmap |=
460 1 << PaddingModeBitPosition::RSA_PKCS1_1_5_ENCRYPT_BIT_POS as i32;
461 }
462 PaddingMode::RSA_PKCS1_1_5_SIGN => {
463 *padding_mode_bitmap |= 1 << PaddingModeBitPosition::RSA_PKCS1_1_5_SIGN_BIT_POS as i32;
464 }
465 PaddingMode::PKCS7 => {
466 *padding_mode_bitmap |= 1 << PaddingModeBitPosition::PKCS7_BIT_POS as i32;
467 }
468 _ => {}
469 }
470}
471
472fn compute_digest_bitmap(digest_bitmap: &mut i32, digest: Digest) {
473 match digest {
474 Digest::NONE => {
475 *digest_bitmap |= 1 << DigestBitPosition::NONE_BIT_POSITION as i32;
476 }
477 Digest::MD5 => {
478 *digest_bitmap |= 1 << DigestBitPosition::MD5_BIT_POS as i32;
479 }
480 Digest::SHA1 => {
481 *digest_bitmap |= 1 << DigestBitPosition::SHA_1_BIT_POS as i32;
482 }
483 Digest::SHA_2_224 => {
484 *digest_bitmap |= 1 << DigestBitPosition::SHA_2_224_BIT_POS as i32;
485 }
486 Digest::SHA_2_256 => {
487 *digest_bitmap |= 1 << DigestBitPosition::SHA_2_256_BIT_POS as i32;
488 }
489 Digest::SHA_2_384 => {
490 *digest_bitmap |= 1 << DigestBitPosition::SHA_2_384_BIT_POS as i32;
491 }
492 Digest::SHA_2_512 => {
493 *digest_bitmap |= 1 << DigestBitPosition::SHA_2_512_BIT_POS as i32;
494 }
495 _ => {}
496 }
497}
498
499fn compute_block_mode_bitmap(block_mode_bitmap: &mut i32, block_mode: BlockMode) {
500 match block_mode {
501 BlockMode::ECB => {
502 *block_mode_bitmap |= 1 << BlockModeBitPosition::ECB_BIT_POS as i32;
503 }
504 BlockMode::CBC => {
505 *block_mode_bitmap |= 1 << BlockModeBitPosition::CBC_BIT_POS as i32;
506 }
507 BlockMode::CTR => {
508 *block_mode_bitmap |= 1 << BlockModeBitPosition::CTR_BIT_POS as i32;
509 }
510 BlockMode::GCM => {
511 *block_mode_bitmap |= 1 << BlockModeBitPosition::GCM_BIT_POS as i32;
512 }
513 _ => {}
514 }
515}
516
517fn compute_purpose_bitmap(purpose_bitmap: &mut i32, purpose: KeyPurpose) {
518 match purpose {
519 KeyPurpose::ENCRYPT => {
520 *purpose_bitmap |= 1 << KeyPurposeBitPosition::ENCRYPT_BIT_POS as i32;
521 }
522 KeyPurpose::DECRYPT => {
523 *purpose_bitmap |= 1 << KeyPurposeBitPosition::DECRYPT_BIT_POS as i32;
524 }
525 KeyPurpose::SIGN => {
526 *purpose_bitmap |= 1 << KeyPurposeBitPosition::SIGN_BIT_POS as i32;
527 }
528 KeyPurpose::VERIFY => {
529 *purpose_bitmap |= 1 << KeyPurposeBitPosition::VERIFY_BIT_POS as i32;
530 }
531 KeyPurpose::WRAP_KEY => {
532 *purpose_bitmap |= 1 << KeyPurposeBitPosition::WRAP_KEY_BIT_POS as i32;
533 }
534 KeyPurpose::AGREE_KEY => {
535 *purpose_bitmap |= 1 << KeyPurposeBitPosition::AGREE_KEY_BIT_POS as i32;
536 }
537 KeyPurpose::ATTEST_KEY => {
538 *purpose_bitmap |= 1 << KeyPurposeBitPosition::ATTEST_KEY_BIT_POS as i32;
539 }
540 _ => {}
541 }
542}
543
David Drysdaleda897432024-06-24 15:57:35 +0100544pub(crate) fn pull_storage_stats() -> Result<Vec<KeystoreAtom>> {
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000545 let mut atom_vec: Vec<KeystoreAtom> = Vec::new();
546 let mut append = |stat| {
547 match stat {
548 Ok(s) => atom_vec.push(KeystoreAtom {
549 payload: KeystoreAtomPayload::StorageStats(s),
550 ..Default::default()
551 }),
552 Err(error) => {
553 log::error!("pull_metrics_callback: Error getting storage stat: {}", error)
554 }
555 };
556 };
557 DB.with(|db| {
558 let mut db = db.borrow_mut();
559 append(db.get_storage_stat(MetricsStorage::DATABASE));
560 append(db.get_storage_stat(MetricsStorage::KEY_ENTRY));
561 append(db.get_storage_stat(MetricsStorage::KEY_ENTRY_ID_INDEX));
562 append(db.get_storage_stat(MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX));
563 append(db.get_storage_stat(MetricsStorage::BLOB_ENTRY));
564 append(db.get_storage_stat(MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX));
565 append(db.get_storage_stat(MetricsStorage::KEY_PARAMETER));
566 append(db.get_storage_stat(MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX));
567 append(db.get_storage_stat(MetricsStorage::KEY_METADATA));
568 append(db.get_storage_stat(MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX));
569 append(db.get_storage_stat(MetricsStorage::GRANT));
570 append(db.get_storage_stat(MetricsStorage::AUTH_TOKEN));
571 append(db.get_storage_stat(MetricsStorage::BLOB_METADATA));
572 append(db.get_storage_stat(MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX));
573 });
574 Ok(atom_vec)
575}
576
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000577/// Log error events related to Remote Key Provisioning (RKP).
Hasini Gunasingheadf66922022-05-10 08:49:53 +0000578pub fn log_rkp_error_stats(rkp_error: MetricsRkpError, sec_level: &SecurityLevel) {
Shaquille Johnsonbcab6012022-09-02 11:16:24 +0000579 let rkp_error_stats = KeystoreAtomPayload::RkpErrorStats(RkpErrorStats {
580 rkpError: rkp_error,
581 security_level: process_security_level(*sec_level),
582 });
Hasini Gunasinghe8af67ea2021-06-30 17:09:01 +0000583 METRICS_STORE.insert_atom(AtomID::RKP_ERROR_STATS, rkp_error_stats);
584}
585
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000586/// This function tries to read and update the system property: keystore.crash_count.
587/// If the property is absent, it sets the property with value 0. If the property is present, it
588/// increments the value. This helps tracking keystore crashes internally.
589pub fn update_keystore_crash_sysprop() {
Eric Biggers9f9ab182023-05-31 21:37:32 +0000590 let new_count = match read_keystore_crash_count() {
591 Ok(Some(count)) => count + 1,
592 // If the property is absent, then this is the first start up during the boot.
593 // Proceed to write the system property with value 0.
594 Ok(None) => 0,
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000595 Err(error) => {
Eric Biggers9f9ab182023-05-31 21:37:32 +0000596 log::warn!(
597 concat!(
598 "In update_keystore_crash_sysprop: ",
599 "Failed to read the existing system property due to: {:?}.",
600 "Therefore, keystore crashes will not be logged."
601 ),
602 error
603 );
604 return;
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000605 }
606 };
607
Joel Galenson7ead3a22021-07-29 15:27:34 -0700608 if let Err(e) =
609 rustutils::system_properties::write(KEYSTORE_CRASH_COUNT_PROPERTY, &new_count.to_string())
Joel Galensond83784a2021-07-21 11:35:25 -0700610 {
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000611 log::error!(
612 concat!(
613 "In update_keystore_crash_sysprop:: ",
614 "Failed to write the system property due to error: {:?}"
615 ),
616 e
617 );
618 }
619}
620
621/// Read the system property: keystore.crash_count.
Eric Biggers9f9ab182023-05-31 21:37:32 +0000622pub fn read_keystore_crash_count() -> Result<Option<i32>> {
623 match rustutils::system_properties::read("keystore.crash_count") {
624 Ok(Some(count)) => count.parse::<i32>().map(Some).map_err(std::convert::Into::into),
625 Ok(None) => Ok(None),
626 Err(e) => Err(e).context(ks_err!("Failed to read crash count property.")),
627 }
Hasini Gunasinghe365ce372021-07-02 23:13:11 +0000628}
629
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000630/// Enum defining the bit position for each padding mode. Since padding mode can be repeatable, it
631/// is represented using a bitmap.
632#[allow(non_camel_case_types)]
633#[repr(i32)]
634enum PaddingModeBitPosition {
635 ///Bit position in the PaddingMode bitmap for NONE.
636 NONE_BIT_POSITION = 0,
637 ///Bit position in the PaddingMode bitmap for RSA_OAEP.
638 RSA_OAEP_BIT_POS = 1,
639 ///Bit position in the PaddingMode bitmap for RSA_PSS.
640 RSA_PSS_BIT_POS = 2,
641 ///Bit position in the PaddingMode bitmap for RSA_PKCS1_1_5_ENCRYPT.
642 RSA_PKCS1_1_5_ENCRYPT_BIT_POS = 3,
643 ///Bit position in the PaddingMode bitmap for RSA_PKCS1_1_5_SIGN.
644 RSA_PKCS1_1_5_SIGN_BIT_POS = 4,
645 ///Bit position in the PaddingMode bitmap for RSA_PKCS7.
646 PKCS7_BIT_POS = 5,
647}
648
649/// Enum defining the bit position for each digest type. Since digest can be repeatable in
650/// key parameters, it is represented using a bitmap.
651#[allow(non_camel_case_types)]
652#[repr(i32)]
653enum DigestBitPosition {
654 ///Bit position in the Digest bitmap for NONE.
655 NONE_BIT_POSITION = 0,
656 ///Bit position in the Digest bitmap for MD5.
657 MD5_BIT_POS = 1,
658 ///Bit position in the Digest bitmap for SHA1.
659 SHA_1_BIT_POS = 2,
660 ///Bit position in the Digest bitmap for SHA_2_224.
661 SHA_2_224_BIT_POS = 3,
662 ///Bit position in the Digest bitmap for SHA_2_256.
663 SHA_2_256_BIT_POS = 4,
664 ///Bit position in the Digest bitmap for SHA_2_384.
665 SHA_2_384_BIT_POS = 5,
666 ///Bit position in the Digest bitmap for SHA_2_512.
667 SHA_2_512_BIT_POS = 6,
668}
669
670/// Enum defining the bit position for each block mode type. Since block mode can be repeatable in
671/// key parameters, it is represented using a bitmap.
672#[allow(non_camel_case_types)]
673#[repr(i32)]
674enum BlockModeBitPosition {
675 ///Bit position in the BlockMode bitmap for ECB.
676 ECB_BIT_POS = 1,
677 ///Bit position in the BlockMode bitmap for CBC.
678 CBC_BIT_POS = 2,
679 ///Bit position in the BlockMode bitmap for CTR.
680 CTR_BIT_POS = 3,
681 ///Bit position in the BlockMode bitmap for GCM.
682 GCM_BIT_POS = 4,
683}
684
685/// Enum defining the bit position for each key purpose. Since key purpose can be repeatable in
686/// key parameters, it is represented using a bitmap.
687#[allow(non_camel_case_types)]
688#[repr(i32)]
689enum KeyPurposeBitPosition {
690 ///Bit position in the KeyPurpose bitmap for Encrypt.
691 ENCRYPT_BIT_POS = 1,
692 ///Bit position in the KeyPurpose bitmap for Decrypt.
693 DECRYPT_BIT_POS = 2,
694 ///Bit position in the KeyPurpose bitmap for Sign.
695 SIGN_BIT_POS = 3,
696 ///Bit position in the KeyPurpose bitmap for Verify.
697 VERIFY_BIT_POS = 4,
698 ///Bit position in the KeyPurpose bitmap for Wrap Key.
699 WRAP_KEY_BIT_POS = 5,
700 ///Bit position in the KeyPurpose bitmap for Agree Key.
701 AGREE_KEY_BIT_POS = 6,
702 ///Bit position in the KeyPurpose bitmap for Attest Key.
703 ATTEST_KEY_BIT_POS = 7,
704}
David Drysdale49811e22023-05-22 18:51:30 +0100705
706/// The various metrics-related types are not defined in this crate, so the orphan
707/// trait rule means that `std::fmt::Debug` cannot be implemented for them.
708/// Instead, create our own local trait that generates a debug string for a type.
709trait Summary {
710 fn show(&self) -> String;
711}
712
713/// Implement the [`Summary`] trait for AIDL-derived pseudo-enums, mapping named enum values to
714/// specified short names, all padded with spaces to the specified width (to allow improved
715/// readability when printed in a group).
716macro_rules! impl_summary_enum {
717 { $enum:ident, $width:literal, $( $variant:ident => $short:literal ),+ $(,)? } => {
718 impl Summary for $enum{
719 fn show(&self) -> String {
720 match self.0 {
721 $(
722 x if x == Self::$variant.0 => format!(concat!("{:",
723 stringify!($width),
724 "}"),
725 $short),
726 )*
727 v => format!("Unknown({})", v),
728 }
729 }
730 }
731 }
732}
733
734impl_summary_enum!(AtomID, 14,
735 STORAGE_STATS => "STORAGE",
736 KEYSTORE2_ATOM_WITH_OVERFLOW => "OVERFLOW",
737 KEY_CREATION_WITH_GENERAL_INFO => "KEYGEN_GENERAL",
738 KEY_CREATION_WITH_AUTH_INFO => "KEYGEN_AUTH",
739 KEY_CREATION_WITH_PURPOSE_AND_MODES_INFO => "KEYGEN_MODES",
740 KEY_OPERATION_WITH_PURPOSE_AND_MODES_INFO => "KEYOP_MODES",
741 KEY_OPERATION_WITH_GENERAL_INFO => "KEYOP_GENERAL",
742 RKP_ERROR_STATS => "RKP_ERR",
743 CRASH_STATS => "CRASH",
744);
745
746impl_summary_enum!(MetricsStorage, 28,
747 STORAGE_UNSPECIFIED => "UNSPECIFIED",
748 KEY_ENTRY => "KEY_ENTRY",
749 KEY_ENTRY_ID_INDEX => "KEY_ENTRY_ID_IDX" ,
750 KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => "KEY_ENTRY_DOMAIN_NS_IDX" ,
751 BLOB_ENTRY => "BLOB_ENTRY",
752 BLOB_ENTRY_KEY_ENTRY_ID_INDEX => "BLOB_ENTRY_KEY_ENTRY_ID_IDX" ,
753 KEY_PARAMETER => "KEY_PARAMETER",
754 KEY_PARAMETER_KEY_ENTRY_ID_INDEX => "KEY_PARAM_KEY_ENTRY_ID_IDX" ,
755 KEY_METADATA => "KEY_METADATA",
756 KEY_METADATA_KEY_ENTRY_ID_INDEX => "KEY_META_KEY_ENTRY_ID_IDX" ,
757 GRANT => "GRANT",
758 AUTH_TOKEN => "AUTH_TOKEN",
759 BLOB_METADATA => "BLOB_METADATA",
760 BLOB_METADATA_BLOB_ENTRY_ID_INDEX => "BLOB_META_BLOB_ENTRY_ID_IDX" ,
761 METADATA => "METADATA",
762 DATABASE => "DATABASE",
763 LEGACY_STORAGE => "LEGACY_STORAGE",
764);
765
766impl_summary_enum!(MetricsAlgorithm, 4,
767 ALGORITHM_UNSPECIFIED => "NONE",
768 RSA => "RSA",
769 EC => "EC",
770 AES => "AES",
771 TRIPLE_DES => "DES",
772 HMAC => "HMAC",
773);
774
775impl_summary_enum!(MetricsEcCurve, 5,
776 EC_CURVE_UNSPECIFIED => "NONE",
777 P_224 => "P-224",
778 P_256 => "P-256",
779 P_384 => "P-384",
780 P_521 => "P-521",
781 CURVE_25519 => "25519",
782);
783
784impl_summary_enum!(MetricsKeyOrigin, 10,
785 ORIGIN_UNSPECIFIED => "UNSPEC",
786 GENERATED => "GENERATED",
787 DERIVED => "DERIVED",
788 IMPORTED => "IMPORTED",
789 RESERVED => "RESERVED",
790 SECURELY_IMPORTED => "SEC-IMPORT",
791);
792
793impl_summary_enum!(MetricsSecurityLevel, 9,
794 SECURITY_LEVEL_UNSPECIFIED => "UNSPEC",
795 SECURITY_LEVEL_SOFTWARE => "SOFTWARE",
796 SECURITY_LEVEL_TRUSTED_ENVIRONMENT => "TEE",
797 SECURITY_LEVEL_STRONGBOX => "STRONGBOX",
798 SECURITY_LEVEL_KEYSTORE => "KEYSTORE",
799);
800
Catherine Vlasov71817432025-01-15 16:30:13 +0000801impl_summary_enum!(MetricsHardwareAuthenticatorType, 8,
David Drysdale49811e22023-05-22 18:51:30 +0100802 AUTH_TYPE_UNSPECIFIED => "UNSPEC",
803 NONE => "NONE",
804 PASSWORD => "PASSWD",
805 FINGERPRINT => "FPRINT",
Catherine Vlasov71817432025-01-15 16:30:13 +0000806 PASSWORD_OR_FINGERPRINT => "PW_OR_FP",
David Drysdale49811e22023-05-22 18:51:30 +0100807 ANY => "ANY",
Catherine Vlasov71817432025-01-15 16:30:13 +0000808 NO_AUTH_TYPE => "NOAUTH",
David Drysdale49811e22023-05-22 18:51:30 +0100809);
810
811impl_summary_enum!(MetricsPurpose, 7,
812 KEY_PURPOSE_UNSPECIFIED => "UNSPEC",
813 ENCRYPT => "ENCRYPT",
814 DECRYPT => "DECRYPT",
815 SIGN => "SIGN",
816 VERIFY => "VERIFY",
817 WRAP_KEY => "WRAPKEY",
818 AGREE_KEY => "AGREEKY",
819 ATTEST_KEY => "ATTESTK",
820);
821
822impl_summary_enum!(MetricsOutcome, 7,
823 OUTCOME_UNSPECIFIED => "UNSPEC",
824 DROPPED => "DROPPED",
825 SUCCESS => "SUCCESS",
826 ABORT => "ABORT",
827 PRUNED => "PRUNED",
828 ERROR => "ERROR",
829);
830
831impl_summary_enum!(MetricsRkpError, 6,
832 RKP_ERROR_UNSPECIFIED => "UNSPEC",
833 OUT_OF_KEYS => "OOKEYS",
834 FALL_BACK_DURING_HYBRID => "FALLBK",
835);
836
837/// Convert an argument into a corresponding format clause. (This is needed because
838/// macro expansion text for repeated inputs needs to mention one of the repeated
839/// inputs.)
840macro_rules! format_clause {
841 { $ignored:ident } => { "{}" }
842}
843
844/// Generate code to print a string corresponding to a bitmask, where the given
845/// enum identifies which bits mean what. If additional bits (not included in
846/// the enum variants) are set, include the whole bitmask in the output so no
847/// information is lost.
848macro_rules! show_enum_bitmask {
849 { $v:expr, $enum:ident, $( $variant:ident => $short:literal ),+ $(,)? } => {
850 {
851 let v: i32 = $v;
852 let mut displayed_mask = 0i32;
853 $(
854 displayed_mask |= 1 << $enum::$variant as i32;
855 )*
856 let undisplayed_mask = !displayed_mask;
857 let undisplayed = v & undisplayed_mask;
858 let extra = if undisplayed == 0 {
859 "".to_string()
860 } else {
861 format!("(full:{v:#010x})")
862 };
863 format!(
864 concat!( $( format_clause!($variant), )* "{}"),
865 $(
866 if v & 1 << $enum::$variant as i32 != 0 { $short } else { "-" },
867 )*
868 extra
869 )
870 }
871 }
872}
873
874fn show_purpose(v: i32) -> String {
875 show_enum_bitmask!(v, KeyPurposeBitPosition,
876 ATTEST_KEY_BIT_POS => "A",
877 AGREE_KEY_BIT_POS => "G",
878 WRAP_KEY_BIT_POS => "W",
879 VERIFY_BIT_POS => "V",
880 SIGN_BIT_POS => "S",
881 DECRYPT_BIT_POS => "D",
882 ENCRYPT_BIT_POS => "E",
883 )
884}
885
886fn show_padding(v: i32) -> String {
887 show_enum_bitmask!(v, PaddingModeBitPosition,
888 PKCS7_BIT_POS => "7",
889 RSA_PKCS1_1_5_SIGN_BIT_POS => "S",
890 RSA_PKCS1_1_5_ENCRYPT_BIT_POS => "E",
891 RSA_PSS_BIT_POS => "P",
892 RSA_OAEP_BIT_POS => "O",
893 NONE_BIT_POSITION => "N",
894 )
895}
896
897fn show_digest(v: i32) -> String {
898 show_enum_bitmask!(v, DigestBitPosition,
899 SHA_2_512_BIT_POS => "5",
900 SHA_2_384_BIT_POS => "3",
901 SHA_2_256_BIT_POS => "2",
902 SHA_2_224_BIT_POS => "4",
903 SHA_1_BIT_POS => "1",
904 MD5_BIT_POS => "M",
905 NONE_BIT_POSITION => "N",
906 )
907}
908
909fn show_blockmode(v: i32) -> String {
910 show_enum_bitmask!(v, BlockModeBitPosition,
911 GCM_BIT_POS => "G",
912 CTR_BIT_POS => "T",
913 CBC_BIT_POS => "C",
914 ECB_BIT_POS => "E",
915 )
916}
917
918impl Summary for KeystoreAtomPayload {
919 fn show(&self) -> String {
920 match self {
921 KeystoreAtomPayload::StorageStats(v) => {
922 format!("{} sz={} unused={}", v.storage_type.show(), v.size, v.unused_size)
923 }
924 KeystoreAtomPayload::KeyCreationWithGeneralInfo(v) => {
925 format!(
926 "{} ksz={:>4} crv={} {} rc={:4} attest? {}",
927 v.algorithm.show(),
928 v.key_size,
929 v.ec_curve.show(),
930 v.key_origin.show(),
931 v.error_code,
932 if v.attestation_requested { "Y" } else { "N" }
933 )
934 }
935 KeystoreAtomPayload::KeyCreationWithAuthInfo(v) => {
936 format!(
937 "auth={} log(time)={:3} sec={}",
938 v.user_auth_type.show(),
939 v.log10_auth_key_timeout_seconds,
940 v.security_level.show()
941 )
942 }
943 KeystoreAtomPayload::KeyCreationWithPurposeAndModesInfo(v) => {
944 format!(
945 "{} purpose={} padding={} digest={} blockmode={}",
946 v.algorithm.show(),
947 show_purpose(v.purpose_bitmap),
948 show_padding(v.padding_mode_bitmap),
949 show_digest(v.digest_bitmap),
950 show_blockmode(v.block_mode_bitmap),
951 )
952 }
953 KeystoreAtomPayload::KeyOperationWithGeneralInfo(v) => {
954 format!(
955 "{} {:>8} upgraded? {} sec={}",
956 v.outcome.show(),
957 v.error_code,
958 if v.key_upgraded { "Y" } else { "N" },
959 v.security_level.show()
960 )
961 }
962 KeystoreAtomPayload::KeyOperationWithPurposeAndModesInfo(v) => {
963 format!(
964 "{} padding={} digest={} blockmode={}",
965 v.purpose.show(),
966 show_padding(v.padding_mode_bitmap),
967 show_digest(v.digest_bitmap),
968 show_blockmode(v.block_mode_bitmap)
969 )
970 }
971 KeystoreAtomPayload::RkpErrorStats(v) => {
972 format!("{} sec={}", v.rkpError.show(), v.security_level.show())
973 }
974 KeystoreAtomPayload::CrashStats(v) => {
975 format!("count={}", v.count_of_crash_events)
976 }
977 KeystoreAtomPayload::Keystore2AtomWithOverflow(v) => {
978 format!("atom={}", v.atom_id.show())
979 }
980 }
981 }
982}
983
984#[cfg(test)]
985mod tests {
986 use super::*;
987
988 #[test]
989 fn test_enum_show() {
990 let algo = MetricsAlgorithm::RSA;
991 assert_eq!("RSA ", algo.show());
992 let algo = MetricsAlgorithm(42);
993 assert_eq!("Unknown(42)", algo.show());
994 }
995
996 #[test]
997 fn test_enum_bitmask_show() {
998 let mut modes = 0i32;
999 compute_block_mode_bitmap(&mut modes, BlockMode::ECB);
1000 compute_block_mode_bitmap(&mut modes, BlockMode::CTR);
1001
1002 assert_eq!(show_blockmode(modes), "-T-E");
1003
1004 // Add some bits not covered by the enum of valid bit positions.
1005 modes |= 0xa0;
1006 assert_eq!(show_blockmode(modes), "-T-E(full:0x000000aa)");
1007 modes |= 0x300;
1008 assert_eq!(show_blockmode(modes), "-T-E(full:0x000003aa)");
1009 }
1010}