Add keystore API for metrics re-routing.
Keystore2 atoms need to be routed to statsd via a proxy.
The proxy needs to call this API in order to pull metrics from
keystore.
Bug: 188590587
Test: Statsd Testdrive script
Merged-In: I28f8675fe5467b0760418c4d2d87808e45657be1
Change-Id: I28f8675fe5467b0760418c4d2d87808e45657be1
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 9dc34d2..0069f95 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -35,6 +35,7 @@
"android.security.authorization-rust",
"android.security.compat-rust",
"android.security.maintenance-rust",
+ "android.security.metrics-rust",
"android.security.remoteprovisioning-rust",
"android.system.keystore2-V1-rust",
"libanyhow",
@@ -54,9 +55,6 @@
"liblog_rust",
"librand",
"librusqlite",
- "libstatslog_rust",
- "libstatslog_rust_header",
- "libstatspull_rust",
"libthiserror",
],
shared_libs: [
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index 5e4e22c..5416024 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -169,3 +169,25 @@
},
}
+aidl_interface {
+ name: "android.security.metrics",
+ srcs: [ "android/security/metrics/*.aidl" ],
+ imports: [
+ "android.system.keystore2-V1",
+ ],
+ unstable: true,
+ backend: {
+ java: {
+ platform_apis: true,
+ srcs_available: true,
+ },
+ rust: {
+ enabled: true,
+ },
+ ndk: {
+ enabled: true,
+ apps_enabled: false,
+ }
+ },
+}
+
diff --git a/keystore2/aidl/android/security/metrics/Algorithm.aidl b/keystore2/aidl/android/security/metrics/Algorithm.aidl
new file mode 100644
index 0000000..8e8d107
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/Algorithm.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * Algorithm enum as defined in stats/enums/system/security/keystore2/enums.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum Algorithm {
+ /** ALGORITHM is prepended because UNSPECIFIED exists in other enums as well. */
+ ALGORITHM_UNSPECIFIED = 0,
+
+ /** Asymmetric algorithms. */
+ RSA = 1,
+
+ /** 2 removed, do not reuse. */
+ EC = 3,
+
+ /** Block cipher algorithms. */
+ AES = 32,
+ TRIPLE_DES = 33,
+
+ /** MAC algorithms. */
+ HMAC = 128,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/AtomID.aidl b/keystore2/aidl/android/security/metrics/AtomID.aidl
new file mode 100644
index 0000000..dc3768a
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/AtomID.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * Atom IDs as defined in frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum AtomID {
+ STORAGE_STATS = 10103,
+ RKP_POOL_STATS = 10104,
+ KEY_CREATION_WITH_GENERAL_INFO = 10118,
+ KEY_CREATION_WITH_AUTH_INFO = 10119,
+ KEY_CREATION_WITH_PURPOSE_AND_MODES_INFO = 10120,
+ KEYSTORE2_ATOM_WITH_OVERFLOW = 10121,
+ KEY_OPERATION_WITH_PURPOSE_AND_MODES_INFO = 10122,
+ KEY_OPERATION_WITH_GENERAL_INFO = 10123,
+ RKP_ERROR_STATS = 10124,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/EcCurve.aidl b/keystore2/aidl/android/security/metrics/EcCurve.aidl
new file mode 100644
index 0000000..b190d83
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/EcCurve.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * EcCurve enum as defined in Keystore2KeyCreationWithGeneralInfo of
+ * frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum EcCurve {
+ /** Unspecified takes 0. Other values are incremented by 1 compared to the keymint spec. */
+ EC_CURVE_UNSPECIFIED = 0,
+ P_224 = 1,
+ P_256 = 2,
+ P_384 = 3,
+ P_521 = 4,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/HardwareAuthenticatorType.aidl b/keystore2/aidl/android/security/metrics/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..b13f6ea
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/HardwareAuthenticatorType.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * HardwareAuthenticatorType enum as defined in Keystore2KeyCreationWithAuthInfo of
+ * frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum HardwareAuthenticatorType {
+ /** Unspecified takes 0. Other values are incremented by 1 compared to keymint spec. */
+ AUTH_TYPE_UNSPECIFIED = 0,
+ NONE = 1,
+ PASSWORD = 2,
+ FINGERPRINT = 3,
+ ANY = 5,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/IKeystoreMetrics.aidl b/keystore2/aidl/android/security/metrics/IKeystoreMetrics.aidl
new file mode 100644
index 0000000..342cf01
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/IKeystoreMetrics.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.KeystoreAtom;
+import android.security.metrics.AtomID;
+
+/**
+ * IKeystoreMetrics interface exposes the method for system server to pull metrics from keystore.
+ * @hide
+ */
+interface IKeystoreMetrics {
+ /**
+ * Allows the metrics routing proxy to pull the metrics from keystore.
+ *
+ * @return an array of KeystoreAtom objects with the atomID. There can be multiple atom objects
+ * for the same atomID, encapsulating different combinations of values for the atom fields.
+ * If there is no atom object found for the atomID in the metrics store, an empty array is
+ * returned.
+ *
+ * Callers require 'PullMetrics' permission.
+ *
+ * @param atomID - ID of the atom to be pulled.
+ *
+ * Errors are reported as service specific errors.
+ */
+ KeystoreAtom[] pullMetrics(in AtomID atomID);
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeyCreationWithAuthInfo.aidl b/keystore2/aidl/android/security/metrics/KeyCreationWithAuthInfo.aidl
new file mode 100644
index 0000000..ff200bc
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeyCreationWithAuthInfo.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.HardwareAuthenticatorType;
+import android.security.metrics.SecurityLevel;
+
+/**
+ * Atom that encapsulates authentication related information in key creation events.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable KeyCreationWithAuthInfo {
+ HardwareAuthenticatorType user_auth_type;
+ /**
+ * Base 10 logarithm of time out in seconds.
+ * Logarithm is taken in order to reduce the cardinaltiy.
+ */
+ int log10_auth_key_timeout_seconds;
+ SecurityLevel security_level;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeyCreationWithGeneralInfo.aidl b/keystore2/aidl/android/security/metrics/KeyCreationWithGeneralInfo.aidl
new file mode 100644
index 0000000..74cd9ef
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeyCreationWithGeneralInfo.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.Algorithm;
+import android.security.metrics.EcCurve;
+import android.security.metrics.KeyOrigin;
+
+/**
+ * Atom that encapsulates a set of general information in key creation events.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable KeyCreationWithGeneralInfo {
+ Algorithm algorithm;
+ int key_size;
+ EcCurve ec_curve;
+ KeyOrigin key_origin;
+ int error_code;
+ boolean attestation_requested = false;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeyCreationWithPurposeAndModesInfo.aidl b/keystore2/aidl/android/security/metrics/KeyCreationWithPurposeAndModesInfo.aidl
new file mode 100644
index 0000000..dda61c4
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeyCreationWithPurposeAndModesInfo.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.Algorithm;
+
+/**
+ * Atom that encapsulates the repeated fields in key creation events.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable KeyCreationWithPurposeAndModesInfo {
+ Algorithm algorithm;
+ int purpose_bitmap;
+ int padding_mode_bitmap;
+ int digest_bitmap;
+ int block_mode_bitmap;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeyOperationWithGeneralInfo.aidl b/keystore2/aidl/android/security/metrics/KeyOperationWithGeneralInfo.aidl
new file mode 100644
index 0000000..d70aaf3
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeyOperationWithGeneralInfo.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.Outcome;
+import android.security.metrics.SecurityLevel;
+
+/**
+ * Atom that encapsulates a set of general information in key operation events.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable KeyOperationWithGeneralInfo {
+ Outcome outcome;
+ int error_code;
+ boolean key_upgraded;
+ SecurityLevel security_level;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeyOperationWithPurposeAndModesInfo.aidl b/keystore2/aidl/android/security/metrics/KeyOperationWithPurposeAndModesInfo.aidl
new file mode 100644
index 0000000..e3769e1
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeyOperationWithPurposeAndModesInfo.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.Purpose;
+
+/**
+ * Atom that encapsulates the purpose, padding mode, digest and block mode fields in key operations.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable KeyOperationWithPurposeAndModesInfo {
+ Purpose purpose;
+ int padding_mode_bitmap;
+ int digest_bitmap;
+ int block_mode_bitmap;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeyOrigin.aidl b/keystore2/aidl/android/security/metrics/KeyOrigin.aidl
new file mode 100644
index 0000000..b472bc3
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeyOrigin.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * KeyOrigin enum as defined in Keystore2KeyCreationWithGeneralInfo of
+ * frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum KeyOrigin {
+ /** Unspecified takes 0. Other values are incremented by 1 compared to keymint spec. */
+ ORIGIN_UNSPECIFIED = 0,
+
+ /** Generated in KeyMint. Should not exist outside the TEE. */
+ GENERATED = 1,
+
+ /** Derived inside KeyMint. Likely exists off-device. */
+ DERIVED = 2,
+
+ /** Imported into KeyMint. Existed as cleartext in Android. */
+ IMPORTED = 3,
+
+ /** Previously used for another purpose that is now obsolete. */
+ RESERVED = 4,
+
+ /** Securely imported into KeyMint. */
+ SECURELY_IMPORTED = 5,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/Keystore2AtomWithOverflow.aidl b/keystore2/aidl/android/security/metrics/Keystore2AtomWithOverflow.aidl
new file mode 100644
index 0000000..f2ac399
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/Keystore2AtomWithOverflow.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.AtomID;
+
+/**
+ * Logs the atom id of the atoms associated with key creation/operation events, that have reached
+ * the maximum storage limit allocated for different atom objects of that atom,
+ * in keystore in-memory store.
+ *
+ * Size of the storage bucket for each atom is limited considering their expected cardinaltity.
+ * This limit may exceed if the dimensions of the atoms take a large number of unexpected
+ * combinations. This atom is used to track such cases.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable Keystore2AtomWithOverflow {
+ AtomID atom_id;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/KeystoreAtom.aidl b/keystore2/aidl/android/security/metrics/KeystoreAtom.aidl
new file mode 100644
index 0000000..266267a
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeystoreAtom.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.KeystoreAtomPayload;
+
+/**
+ * Encapsulates a particular atom object of type KeystoreAtomPayload its count. Note that
+ * the field: count is only relevant for the atom types that are stored in the
+ * in-memory metrics store. E.g. count field is not relevant for the atom types such as StorageStats
+ * and RkpPoolStats that are not stored in the metrics store.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable KeystoreAtom {
+ KeystoreAtomPayload payload;
+ int count;
+}
diff --git a/keystore2/aidl/android/security/metrics/KeystoreAtomPayload.aidl b/keystore2/aidl/android/security/metrics/KeystoreAtomPayload.aidl
new file mode 100644
index 0000000..b8a3aba
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/KeystoreAtomPayload.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.KeyCreationWithGeneralInfo;
+import android.security.metrics.KeyCreationWithPurposeAndModesInfo;
+import android.security.metrics.KeyCreationWithAuthInfo;
+import android.security.metrics.KeyOperationWithGeneralInfo;
+import android.security.metrics.KeyOperationWithPurposeAndModesInfo;
+import android.security.metrics.StorageStats;
+import android.security.metrics.Keystore2AtomWithOverflow;
+import android.security.metrics.RkpErrorStats;
+import android.security.metrics.RkpPoolStats;
+
+/** @hide */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+union KeystoreAtomPayload {
+ StorageStats storageStats;
+ RkpPoolStats rkpPoolStats;
+ KeyCreationWithGeneralInfo keyCreationWithGeneralInfo;
+ KeyCreationWithAuthInfo keyCreationWithAuthInfo;
+ KeyCreationWithPurposeAndModesInfo keyCreationWithPurposeAndModesInfo;
+ Keystore2AtomWithOverflow keystore2AtomWithOverflow;
+ KeyOperationWithPurposeAndModesInfo keyOperationWithPurposeAndModesInfo;
+ KeyOperationWithGeneralInfo keyOperationWithGeneralInfo;
+ RkpErrorStats rkpErrorStats;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/Outcome.aidl b/keystore2/aidl/android/security/metrics/Outcome.aidl
new file mode 100644
index 0000000..006548b
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/Outcome.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * Outcome enum as defined in Keystore2KeyOperationWithGeneralInfo of
+ * frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum Outcome {
+ OUTCOME_UNSPECIFIED = 0,
+ DROPPED = 1,
+ SUCCESS = 2,
+ ABORT = 3,
+ PRUNED = 4,
+ ERROR = 5,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/PoolStatus.aidl b/keystore2/aidl/android/security/metrics/PoolStatus.aidl
new file mode 100644
index 0000000..3530163
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/PoolStatus.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * Status of the remotely provisioned keys, as defined in RkpPoolStats of
+ * frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum PoolStatus {
+ EXPIRING = 1,
+ UNASSIGNED = 2,
+ ATTESTED = 3,
+ TOTAL = 4,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/Purpose.aidl b/keystore2/aidl/android/security/metrics/Purpose.aidl
new file mode 100644
index 0000000..f003cea
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/Purpose.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * Purpose enum as defined in Keystore2KeyOperationWithPurposeAndModesInfo of
+ * frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum Purpose {
+ /** Unspecified takes 0. Other values are incremented by 1 compared to keymint spec. */
+ KEY_PURPOSE_UNSPECIFIED = 0,
+
+ /** Usable with RSA, 3DES and AES keys. */
+ ENCRYPT = 1,
+
+ /** Usable with RSA, 3DES and AES keys. */
+ DECRYPT = 2,
+
+ /** Usable with RSA, EC and HMAC keys. */
+ SIGN = 3,
+
+ /** Usable with RSA, EC and HMAC keys. */
+ VERIFY = 4,
+
+ /** 4 is reserved */
+
+ /** Usable with RSA keys. */
+ WRAP_KEY = 6,
+
+ /** Key Agreement, usable with EC keys. */
+ AGREE_KEY = 7,
+
+ /**
+ * Usable as an attestation signing key. Keys with this purpose must not have any other
+ * purpose.
+ */
+ ATTEST_KEY = 8,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/RkpError.aidl b/keystore2/aidl/android/security/metrics/RkpError.aidl
new file mode 100644
index 0000000..c33703d
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/RkpError.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * KeyOrigin enum as defined in RkpErrorStats of frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum RkpError {
+ RKP_ERROR_UNSPECIFIED = 0,
+
+ /** The key pool is out of keys. */
+ OUT_OF_KEYS = 1,
+
+ /** Falling back to factory provisioned keys during hybrid mode. */
+ FALL_BACK_DURING_HYBRID = 2,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/RkpErrorStats.aidl b/keystore2/aidl/android/security/metrics/RkpErrorStats.aidl
new file mode 100644
index 0000000..616d129
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/RkpErrorStats.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.RkpError;
+/**
+ * Atom that encapsulates error information in remote key provisioning events.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable RkpErrorStats {
+ RkpError rkpError;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl b/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl
new file mode 100644
index 0000000..b233842
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/RkpPoolStats.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.PoolStatus;
+
+/**
+ * Count of keys in the key pool related to Remote Key Provisioning (RKP).
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable RkpPoolStats {
+ PoolStatus pool_status;
+ int count_of_keys;
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/SecurityLevel.aidl b/keystore2/aidl/android/security/metrics/SecurityLevel.aidl
new file mode 100644
index 0000000..f627be2
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/SecurityLevel.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * SecurityLevel enum as defined in stats/enums/system/security/keystore2/enums.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum SecurityLevel {
+ /** Unspecified takes 0. Other values are incremented by 1 compared to keymint spec. */
+ SECURITY_LEVEL_UNSPECIFIED = 0,
+ SECURITY_LEVEL_SOFTWARE = 1,
+ SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 2,
+ SECURITY_LEVEL_STRONGBOX = 3,
+ SECURITY_LEVEL_KEYSTORE = 4,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/Storage.aidl b/keystore2/aidl/android/security/metrics/Storage.aidl
new file mode 100644
index 0000000..1ba6e1f
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/Storage.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+/**
+ * Storage enum as defined in Keystore2StorageStats of frameworks/proto_logging/stats/atoms.proto.
+ * @hide
+ */
+@Backing(type="int")
+enum Storage {
+ STORAGE_UNSPECIFIED = 0,
+ KEY_ENTRY = 1,
+ KEY_ENTRY_ID_INDEX = 2,
+ KEY_ENTRY_DOMAIN_NAMESPACE_INDEX = 3,
+ BLOB_ENTRY = 4,
+ BLOB_ENTRY_KEY_ENTRY_ID_INDEX = 5,
+ KEY_PARAMETER = 6,
+ KEY_PARAMETER_KEY_ENTRY_ID_INDEX = 7,
+ KEY_METADATA = 8,
+ KEY_METADATA_KEY_ENTRY_ID_INDEX = 9,
+ GRANT = 10,
+ AUTH_TOKEN = 11,
+ BLOB_METADATA = 12,
+ BLOB_METADATA_BLOB_ENTRY_ID_INDEX =13,
+ METADATA = 14,
+ DATABASE = 15,
+ LEGACY_STORAGE = 16,
+}
\ No newline at end of file
diff --git a/keystore2/aidl/android/security/metrics/StorageStats.aidl b/keystore2/aidl/android/security/metrics/StorageStats.aidl
new file mode 100644
index 0000000..6822e86
--- /dev/null
+++ b/keystore2/aidl/android/security/metrics/StorageStats.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.security.metrics;
+
+import android.security.metrics.Storage;
+
+/**
+ * Atom that encapsulates a set of general information in key creation events.
+ * @hide
+ */
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable StorageStats {
+ Storage storage_type;
+ int size;
+ int unused_size;
+}
\ No newline at end of file
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 36c722a..fa54623 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -69,8 +69,9 @@
use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
AttestationPoolStatus::AttestationPoolStatus,
};
-use statslog_rust::keystore2_storage_stats::{
- Keystore2StorageStats, StorageType as StatsdStorageType,
+use android_security_metrics::aidl::android::security::metrics::{
+ StorageStats::StorageStats,
+ Storage::Storage as MetricsStorage,
};
use keystore2_crypto::ZVec;
@@ -1021,23 +1022,23 @@
fn do_table_size_query(
&mut self,
- storage_type: StatsdStorageType,
+ storage_type: MetricsStorage,
query: &str,
params: &[&str],
- ) -> Result<Keystore2StorageStats> {
+ ) -> Result<StorageStats> {
let (total, unused) = self.with_transaction(TransactionBehavior::Deferred, |tx| {
tx.query_row(query, params_from_iter(params), |row| Ok((row.get(0)?, row.get(1)?)))
.with_context(|| {
- format!("get_storage_stat: Error size of storage type {}", storage_type as i32)
+ format!("get_storage_stat: Error size of storage type {}", storage_type.0)
})
.no_gc()
})?;
- Ok(Keystore2StorageStats { storage_type, size: total, unused_size: unused })
+ Ok(StorageStats { storage_type, size: total, unused_size: unused })
}
- fn get_total_size(&mut self) -> Result<Keystore2StorageStats> {
+ fn get_total_size(&mut self) -> Result<StorageStats> {
self.do_table_size_query(
- StatsdStorageType::Database,
+ MetricsStorage::DATABASE,
"SELECT page_count * page_size, freelist_count * page_size
FROM pragma_page_count('persistent'),
pragma_page_size('persistent'),
@@ -1048,10 +1049,10 @@
fn get_table_size(
&mut self,
- storage_type: StatsdStorageType,
+ storage_type: MetricsStorage,
schema: &str,
table: &str,
- ) -> Result<Keystore2StorageStats> {
+ ) -> Result<StorageStats> {
self.do_table_size_query(
storage_type,
"SELECT pgsize,unused FROM dbstat(?1)
@@ -1063,63 +1064,57 @@
/// Fetches a storage statisitics atom for a given storage type. For storage
/// types that map to a table, information about the table's storage is
/// returned. Requests for storage types that are not DB tables return None.
- pub fn get_storage_stat(
- &mut self,
- storage_type: StatsdStorageType,
- ) -> Result<Keystore2StorageStats> {
+ pub fn get_storage_stat(&mut self, storage_type: MetricsStorage) -> Result<StorageStats> {
let _wp = wd::watch_millis("KeystoreDB::get_storage_stat", 500);
match storage_type {
- StatsdStorageType::Database => self.get_total_size(),
- StatsdStorageType::KeyEntry => {
+ MetricsStorage::DATABASE => self.get_total_size(),
+ MetricsStorage::KEY_ENTRY => {
self.get_table_size(storage_type, "persistent", "keyentry")
}
- StatsdStorageType::KeyEntryIdIndex => {
+ MetricsStorage::KEY_ENTRY_ID_INDEX => {
self.get_table_size(storage_type, "persistent", "keyentry_id_index")
}
- StatsdStorageType::KeyEntryDomainNamespaceIndex => {
+ MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX => {
self.get_table_size(storage_type, "persistent", "keyentry_domain_namespace_index")
}
- StatsdStorageType::BlobEntry => {
+ MetricsStorage::BLOB_ENTRY => {
self.get_table_size(storage_type, "persistent", "blobentry")
}
- StatsdStorageType::BlobEntryKeyEntryIdIndex => {
+ MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX => {
self.get_table_size(storage_type, "persistent", "blobentry_keyentryid_index")
}
- StatsdStorageType::KeyParameter => {
+ MetricsStorage::KEY_PARAMETER => {
self.get_table_size(storage_type, "persistent", "keyparameter")
}
- StatsdStorageType::KeyParameterKeyEntryIdIndex => {
+ MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX => {
self.get_table_size(storage_type, "persistent", "keyparameter_keyentryid_index")
}
- StatsdStorageType::KeyMetadata => {
+ MetricsStorage::KEY_METADATA => {
self.get_table_size(storage_type, "persistent", "keymetadata")
}
- StatsdStorageType::KeyMetadataKeyEntryIdIndex => {
+ MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX => {
self.get_table_size(storage_type, "persistent", "keymetadata_keyentryid_index")
}
- StatsdStorageType::Grant => self.get_table_size(storage_type, "persistent", "grant"),
- StatsdStorageType::AuthToken => {
+ MetricsStorage::GRANT => self.get_table_size(storage_type, "persistent", "grant"),
+ MetricsStorage::AUTH_TOKEN => {
// Since the table is actually a BTreeMap now, unused_size is not meaningfully
// reportable
// Size provided is only an approximation
- Ok(Keystore2StorageStats {
+ Ok(StorageStats {
storage_type,
size: (self.perboot.auth_tokens_len() * std::mem::size_of::<AuthTokenEntry>())
- as i64,
+ as i32,
unused_size: 0,
})
}
- StatsdStorageType::BlobMetadata => {
+ MetricsStorage::BLOB_METADATA => {
self.get_table_size(storage_type, "persistent", "blobmetadata")
}
- StatsdStorageType::BlobMetadataBlobEntryIdIndex => {
+ MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX => {
self.get_table_size(storage_type, "persistent", "blobmetadata_blobentryid_index")
}
- _ => Err(anyhow::Error::msg(format!(
- "Unsupported storage type: {}",
- storage_type as i32
- ))),
+ _ => Err(anyhow::Error::msg(format!("Unsupported storage type: {}", storage_type.0))),
}
}
@@ -5497,21 +5492,21 @@
Ok(())
}
- fn get_valid_statsd_storage_types() -> Vec<StatsdStorageType> {
+ fn get_valid_statsd_storage_types() -> Vec<MetricsStorage> {
vec![
- StatsdStorageType::KeyEntry,
- StatsdStorageType::KeyEntryIdIndex,
- StatsdStorageType::KeyEntryDomainNamespaceIndex,
- StatsdStorageType::BlobEntry,
- StatsdStorageType::BlobEntryKeyEntryIdIndex,
- StatsdStorageType::KeyParameter,
- StatsdStorageType::KeyParameterKeyEntryIdIndex,
- StatsdStorageType::KeyMetadata,
- StatsdStorageType::KeyMetadataKeyEntryIdIndex,
- StatsdStorageType::Grant,
- StatsdStorageType::AuthToken,
- StatsdStorageType::BlobMetadata,
- StatsdStorageType::BlobMetadataBlobEntryIdIndex,
+ MetricsStorage::KEY_ENTRY,
+ MetricsStorage::KEY_ENTRY_ID_INDEX,
+ MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
+ MetricsStorage::BLOB_ENTRY,
+ MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
+ MetricsStorage::KEY_PARAMETER,
+ MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX,
+ MetricsStorage::KEY_METADATA,
+ MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX,
+ MetricsStorage::GRANT,
+ MetricsStorage::AUTH_TOKEN,
+ MetricsStorage::BLOB_METADATA,
+ MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
]
}
@@ -5519,7 +5514,7 @@
/// that are supported by the DB. Check for reasonable values.
#[test]
fn test_query_all_valid_table_sizes() -> Result<()> {
- const PAGE_SIZE: i64 = 4096;
+ const PAGE_SIZE: i32 = 4096;
let mut db = new_test_db()?;
@@ -5527,7 +5522,7 @@
let stat = db.get_storage_stat(t)?;
// AuthToken can be less than a page since it's in a btree, not sqlite
// TODO(b/187474736) stop using if-let here
- if let StatsdStorageType::AuthToken = t {
+ if let MetricsStorage::AUTH_TOKEN = t {
} else {
assert!(stat.size >= PAGE_SIZE);
}
@@ -5537,35 +5532,35 @@
Ok(())
}
- fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, Keystore2StorageStats> {
+ fn get_storage_stats_map(db: &mut KeystoreDB) -> BTreeMap<i32, StorageStats> {
get_valid_statsd_storage_types()
.into_iter()
- .map(|t| (t as i32, db.get_storage_stat(t).unwrap()))
+ .map(|t| (t.0, db.get_storage_stat(t).unwrap()))
.collect()
}
fn assert_storage_increased(
db: &mut KeystoreDB,
- increased_storage_types: Vec<StatsdStorageType>,
- baseline: &mut BTreeMap<i32, Keystore2StorageStats>,
+ increased_storage_types: Vec<MetricsStorage>,
+ baseline: &mut BTreeMap<i32, StorageStats>,
) {
for storage in increased_storage_types {
// Verify the expected storage increased.
let new = db.get_storage_stat(storage).unwrap();
- let storage = storage as i32;
- let old = &baseline[&storage];
- assert!(new.size >= old.size, "{}: {} >= {}", storage, new.size, old.size);
+ let storage = storage;
+ let old = &baseline[&storage.0];
+ assert!(new.size >= old.size, "{}: {} >= {}", storage.0, new.size, old.size);
assert!(
new.unused_size <= old.unused_size,
"{}: {} <= {}",
- storage,
+ storage.0,
new.unused_size,
old.unused_size
);
// Update the baseline with the new value so that it succeeds in the
// later comparison.
- baseline.insert(storage, new);
+ baseline.insert(storage.0, new);
}
// Get an updated map of the storage and verify there were no unexpected changes.
@@ -5573,7 +5568,7 @@
assert_eq!(updated_stats.len(), baseline.len());
for &k in baseline.keys() {
- let stringify = |map: &BTreeMap<i32, Keystore2StorageStats>| -> String {
+ let stringify = |map: &BTreeMap<i32, StorageStats>| -> String {
let mut s = String::new();
for &k in map.keys() {
writeln!(&mut s, " {}: {}, {}", &k, map[&k].size, map[&k].unused_size)
@@ -5601,9 +5596,9 @@
assert_storage_increased(
&mut db,
vec![
- StatsdStorageType::KeyEntry,
- StatsdStorageType::KeyEntryIdIndex,
- StatsdStorageType::KeyEntryDomainNamespaceIndex,
+ MetricsStorage::KEY_ENTRY,
+ MetricsStorage::KEY_ENTRY_ID_INDEX,
+ MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX,
],
&mut working_stats,
);
@@ -5614,10 +5609,10 @@
assert_storage_increased(
&mut db,
vec![
- StatsdStorageType::BlobEntry,
- StatsdStorageType::BlobEntryKeyEntryIdIndex,
- StatsdStorageType::BlobMetadata,
- StatsdStorageType::BlobMetadataBlobEntryIdIndex,
+ MetricsStorage::BLOB_ENTRY,
+ MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX,
+ MetricsStorage::BLOB_METADATA,
+ MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX,
],
&mut working_stats,
);
@@ -5626,7 +5621,7 @@
db.insert_keyparameter(&key_id, ¶ms)?;
assert_storage_increased(
&mut db,
- vec![StatsdStorageType::KeyParameter, StatsdStorageType::KeyParameterKeyEntryIdIndex],
+ vec![MetricsStorage::KEY_PARAMETER, MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX],
&mut working_stats,
);
@@ -5635,7 +5630,7 @@
db.insert_key_metadata(&key_id, &metadata)?;
assert_storage_increased(
&mut db,
- vec![StatsdStorageType::KeyMetadata, StatsdStorageType::KeyMetadataKeyEntryIdIndex],
+ vec![MetricsStorage::KEY_METADATA, MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX],
&mut working_stats,
);
@@ -5643,7 +5638,7 @@
for stat in working_stats.values() {
sum += stat.size;
}
- let total = db.get_storage_stat(StatsdStorageType::Database)?.size;
+ let total = db.get_storage_stat(MetricsStorage::DATABASE)?.size;
assert!(sum <= total, "Expected sum <= total. sum: {}, total: {}", sum, total);
Ok(())
@@ -5661,7 +5656,7 @@
timestamp: Timestamp { milliSeconds: 10 },
mac: b"mac".to_vec(),
});
- assert_storage_increased(&mut db, vec![StatsdStorageType::AuthToken], &mut working_stats);
+ assert_storage_increased(&mut db, vec![MetricsStorage::AUTH_TOKEN], &mut working_stats);
Ok(())
}
@@ -5685,7 +5680,7 @@
|_, _| Ok(()),
)?;
- assert_storage_increased(&mut db, vec![StatsdStorageType::Grant], &mut working_stats);
+ assert_storage_increased(&mut db, vec![MetricsStorage::GRANT], &mut working_stats);
Ok(())
}
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index a6a25b2..2c7d4a0 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -17,7 +17,7 @@
use keystore2::entropy;
use keystore2::globals::ENFORCEMENTS;
use keystore2::maintenance::Maintenance;
-use keystore2::metrics;
+use keystore2::metrics::Metrics;
use keystore2::remote_provisioning::RemoteProvisioningService;
use keystore2::service::KeystoreService;
use keystore2::{apc::ApcManager, shared_secret_negotiation};
@@ -29,6 +29,7 @@
static KS2_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
static APC_SERVICE_NAME: &str = "android.security.apc";
static AUTHORIZATION_SERVICE_NAME: &str = "android.security.authorization";
+static METRICS_SERVICE_NAME: &str = "android.security.metrics";
static REMOTE_PROVISIONING_SERVICE_NAME: &str = "android.security.remoteprovisioning";
static USER_MANAGER_SERVICE_NAME: &str = "android.security.maintenance";
static LEGACY_KEYSTORE_SERVICE_NAME: &str = "android.security.legacykeystore";
@@ -109,6 +110,13 @@
},
);
+ let metrics_service = Metrics::new_native_binder().unwrap_or_else(|e| {
+ panic!("Failed to create service {} because of {:?}.", METRICS_SERVICE_NAME, e);
+ });
+ binder::add_service(METRICS_SERVICE_NAME, metrics_service.as_binder()).unwrap_or_else(|e| {
+ panic!("Failed to register service {} because of {:?}.", METRICS_SERVICE_NAME, e);
+ });
+
// Devices with KS2 and KM 1.0 may not have any IRemotelyProvisionedComponent HALs at all. Do
// not panic if new_native_binder returns failure because it could not find the TEE HAL.
if let Ok(remote_provisioning_service) = RemoteProvisioningService::new_native_binder() {
@@ -133,8 +141,6 @@
},
);
- metrics::register_pull_metrics_callbacks();
-
info!("Successfully registered Keystore 2.0 service.");
info!("Joining thread pool now.");
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 51316d7..8b629b1 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -32,6 +32,7 @@
pub mod legacy_migrator;
pub mod maintenance;
pub mod metrics;
+pub mod metrics_store;
pub mod operation;
pub mod permission;
pub mod raw_device;
diff --git a/keystore2/src/metrics.rs b/keystore2/src/metrics.rs
index 10a465c..42295b7 100644
--- a/keystore2/src/metrics.rs
+++ b/keystore2/src/metrics.rs
@@ -12,533 +12,45 @@
// 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,
+//! This module implements the IKeystoreMetrics AIDL interface, which exposes the API method for the
+//! proxy in the system server to pull the aggregated metrics in keystore.
+use crate::error::map_or_log_err;
+use crate::metrics_store::METRICS_STORE;
+use crate::permission::KeystorePerm;
+use crate::utils::{check_keystore_permission, watchdog as wd};
+use android_security_metrics::aidl::android::security::metrics::{
+ AtomID::AtomID,
+ IKeystoreMetrics::{BnKeystoreMetrics, IKeystoreMetrics},
+ KeystoreAtom::KeystoreAtom,
};
-use anyhow::{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};
+use android_security_metrics::binder::{BinderFeatures, Interface, Result as BinderResult, Strong};
+use anyhow::{Context, Result};
-// Waits and returns Ok if boot is completed.
-fn wait_for_boot_completed() -> Result<()> {
- let watcher = PropertyWatcher::new("sys.boot_completed");
- match watcher {
- Ok(mut watcher) => {
- loop {
- let wait_result = watcher.wait();
- match wait_result {
- Ok(_) => {
- let value_result =
- watcher.read(|_name, value| Ok(value.trim().to_string()));
- match value_result {
- Ok(value) => {
- if value == "1" {
- break;
- }
- }
- Err(e) => {
- log::error!(
- "In wait_for_boot_completed: Failed while reading property. {}",
- e
- );
- return Err(anyhow!("Error in waiting for boot completion."));
- }
- }
- }
- Err(e) => {
- log::error!("In wait_for_boot_completed: Failed while waiting. {}", e);
- return Err(anyhow!("Error in waiting for boot completion."));
- }
- }
- }
- Ok(())
- }
- Err(e) => {
- log::error!("In wait_for_boot_completed: Failed to create PropertyWatcher. {}", e);
- Err(anyhow!("Error in waiting for boot completion."))
- }
+/// This struct is defined to implement IKeystoreMetrics AIDL interface.
+pub struct Metrics;
+
+impl Metrics {
+ /// Create a new instance of Keystore Metrics service.
+ pub fn new_native_binder() -> Result<Strong<dyn IKeystoreMetrics>> {
+ Ok(BnKeystoreMetrics::new_binder(
+ Self,
+ BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
+ ))
+ }
+
+ fn pull_metrics(&self, atom_id: AtomID) -> Result<Vec<KeystoreAtom>> {
+ // Check permission. Function should return if this failed. Therefore having '?' at the end
+ // is very important.
+ check_keystore_permission(KeystorePerm::pull_metrics()).context("In pull_metrics.")?;
+ METRICS_STORE.get_atoms(atom_id)
}
}
-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,
+impl Interface for Metrics {}
+
+impl IKeystoreMetrics for Metrics {
+ fn pullMetrics(&self, atom_id: AtomID) -> BinderResult<Vec<KeystoreAtom>> {
+ let _wp = wd::watch_millis("IKeystoreMetrics::pullMetrics", 500);
+ map_or_log_err(self.pull_metrics(atom_id), Ok)
}
}
-
-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 |_| {
- if let Ok(()) = wait_for_boot_completed() {
- if let Err(e) = key_creation_event_stats.stats_write() {
- 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 |_| {
- if let Ok(()) = wait_for_boot_completed() {
- if let Err(e) = key_operation_event_stats.stats_write() {
- 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() {
- // 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.
- LOGS_HANDLER.queue_lo(move |_| {
- if let Ok(()) = wait_for_boot_completed() {
- set_pull_atom_callback(Atoms::Keystore2StorageStats, None, pull_metrics_callback);
- log::info!("Pull metrics callbacks successfully registered.")
- }
- });
-}
-
-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,
-}
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
new file mode 100644
index 0000000..e3de035
--- /dev/null
+++ b/keystore2/src/metrics_store.rs
@@ -0,0 +1,611 @@
+// 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 is the metrics store module of keystore. It does the following tasks:
+//! 1. Processes the data about keystore events asynchronously, and
+//! stores them in an in-memory store.
+//! 2. Returns the collected metrics when requested by the statsd proxy.
+
+use crate::error::get_error_code;
+use crate::globals::DB;
+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 android_security_metrics::aidl::android::security::metrics::{
+ Algorithm::Algorithm as MetricsAlgorithm, AtomID::AtomID, EcCurve::EcCurve as MetricsEcCurve,
+ HardwareAuthenticatorType::HardwareAuthenticatorType as MetricsHardwareAuthenticatorType,
+ KeyCreationWithAuthInfo::KeyCreationWithAuthInfo,
+ KeyCreationWithGeneralInfo::KeyCreationWithGeneralInfo,
+ KeyCreationWithPurposeAndModesInfo::KeyCreationWithPurposeAndModesInfo,
+ KeyOperationWithGeneralInfo::KeyOperationWithGeneralInfo,
+ KeyOperationWithPurposeAndModesInfo::KeyOperationWithPurposeAndModesInfo,
+ KeyOrigin::KeyOrigin as MetricsKeyOrigin, Keystore2AtomWithOverflow::Keystore2AtomWithOverflow,
+ KeystoreAtom::KeystoreAtom, KeystoreAtomPayload::KeystoreAtomPayload,
+ Outcome::Outcome as MetricsOutcome, Purpose::Purpose as MetricsPurpose,
+ SecurityLevel::SecurityLevel as MetricsSecurityLevel, Storage::Storage as MetricsStorage,
+};
+use anyhow::Result;
+use lazy_static::lazy_static;
+use std::collections::HashMap;
+use std::sync::Mutex;
+
+lazy_static! {
+ /// Singleton for MetricsStore.
+ pub static ref METRICS_STORE: MetricsStore = Default::default();
+}
+
+/// MetricsStore stores the <atom object, count> as <key, value> in the inner hash map,
+/// indexed by the atom id, in the outer hash map.
+/// There can be different atom objects with the same atom id based on the values assigned to the
+/// fields of the atom objects. When an atom object with a particular combination of field values is
+/// inserted, we first check if that atom object is in the inner hash map. If one exists, count
+/// is inceremented. Otherwise, the atom object is inserted with count = 1. Note that count field
+/// of the atom object itself is set to 0 while the object is stored in the hash map. When the atom
+/// objects are queried by the atom id, the corresponding atom objects are retrieved, cloned, and
+/// the count field of the cloned objects is set to the corresponding value field in the inner hash
+/// map before the query result is returned.
+#[derive(Default)]
+pub struct MetricsStore {
+ metrics_store: Mutex<HashMap<AtomID, HashMap<KeystoreAtomPayload, i32>>>,
+}
+
+impl MetricsStore {
+ /// There are some atoms whose maximum cardinality exceeds the cardinality limits tolerated
+ /// by statsd. Statsd tolerates cardinality between 200-300. Therefore, the in-memory storage
+ /// limit for a single atom is set to 250. If the number of atom objects created for a
+ /// particular atom exceeds this limit, an overflow atom object is created to track the ID of
+ /// such atoms.
+ const SINGLE_ATOM_STORE_MAX_SIZE: usize = 250;
+
+ /// Return a vector of atom objects with the given atom ID, if one exists in the metrics_store.
+ /// If any atom object does not exist in the metrics_store for the given atom ID, return an
+ /// empty vector.
+ pub fn get_atoms(&self, atom_id: AtomID) -> Result<Vec<KeystoreAtom>> {
+ // StorageStats is an original pulled atom (i.e. not a pushed atom converted to a
+ // pulledd atom). Therefore, it is handled separately.
+ if AtomID::STORAGE_STATS == atom_id {
+ return pull_storage_stats();
+ }
+
+ // TODO (b/184301651): process and return RKP pool stats.
+
+ // It is safe to call unwrap here since the lock can not be poisoned based on its usage
+ // in this module and the lock is not acquired in the same thread before.
+ let metrics_store_guard = self.metrics_store.lock().unwrap();
+ metrics_store_guard.get(&atom_id).map_or(Ok(Vec::<KeystoreAtom>::new()), |atom_count_map| {
+ Ok(atom_count_map
+ .iter()
+ .map(|(atom, count)| KeystoreAtom { payload: atom.clone(), count: *count })
+ .collect())
+ })
+ }
+
+ /// Insert an atom object to the metrics_store indexed by the atom ID.
+ fn insert_atom(&self, atom_id: AtomID, atom: KeystoreAtomPayload) {
+ // It is ok to unwrap here since the mutex cannot be poisoned according to the way it is
+ // used in this module. And the lock is not acquired by this thread before.
+ let mut metrics_store_guard = self.metrics_store.lock().unwrap();
+ let atom_count_map = metrics_store_guard.entry(atom_id).or_insert_with(HashMap::new);
+ if atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
+ let atom_count = atom_count_map.entry(atom).or_insert(0);
+ *atom_count += 1;
+ } else {
+ // Insert an overflow atom
+ let overflow_atom_count_map = metrics_store_guard
+ .entry(AtomID::KEYSTORE2_ATOM_WITH_OVERFLOW)
+ .or_insert_with(HashMap::new);
+
+ if overflow_atom_count_map.len() < MetricsStore::SINGLE_ATOM_STORE_MAX_SIZE {
+ let overflow_atom = Keystore2AtomWithOverflow { atom_id };
+ let atom_count = overflow_atom_count_map
+ .entry(KeystoreAtomPayload::Keystore2AtomWithOverflow(overflow_atom))
+ .or_insert(0);
+ *atom_count += 1;
+ } else {
+ // This is a rare case, if at all.
+ log::error!("In insert_atom: Maximum storage limit reached for overflow atom.")
+ }
+ }
+ }
+}
+
+/// Log key creation events to be sent to statsd.
+pub fn log_key_creation_event_stats<U>(
+ sec_level: SecurityLevel,
+ key_params: &[KeyParameter],
+ result: &Result<U>,
+) {
+ let (
+ key_creation_with_general_info,
+ key_creation_with_auth_info,
+ key_creation_with_purpose_and_modes_info,
+ ) = process_key_creation_event_stats(sec_level, key_params, result);
+
+ METRICS_STORE
+ .insert_atom(AtomID::KEY_CREATION_WITH_GENERAL_INFO, key_creation_with_general_info);
+ METRICS_STORE.insert_atom(AtomID::KEY_CREATION_WITH_AUTH_INFO, key_creation_with_auth_info);
+ METRICS_STORE.insert_atom(
+ AtomID::KEY_CREATION_WITH_PURPOSE_AND_MODES_INFO,
+ key_creation_with_purpose_and_modes_info,
+ );
+}
+
+// Process the statistics related to key creations and return the three atom objects related to key
+// creations: i) KeyCreationWithGeneralInfo ii) KeyCreationWithAuthInfo
+// iii) KeyCreationWithPurposeAndModesInfo
+fn process_key_creation_event_stats<U>(
+ sec_level: SecurityLevel,
+ key_params: &[KeyParameter],
+ result: &Result<U>,
+) -> (KeystoreAtomPayload, KeystoreAtomPayload, KeystoreAtomPayload) {
+ // In the default atom objects, 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 defaults 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.
+ let mut key_creation_with_general_info = KeyCreationWithGeneralInfo {
+ algorithm: MetricsAlgorithm::ALGORITHM_UNSPECIFIED,
+ key_size: -1,
+ ec_curve: MetricsEcCurve::EC_CURVE_UNSPECIFIED,
+ key_origin: MetricsKeyOrigin::ORIGIN_UNSPECIFIED,
+ error_code: 1,
+ // Default for bool is false (for attestation_requested field).
+ ..Default::default()
+ };
+
+ let mut key_creation_with_auth_info = KeyCreationWithAuthInfo {
+ user_auth_type: MetricsHardwareAuthenticatorType::AUTH_TYPE_UNSPECIFIED,
+ log10_auth_key_timeout_seconds: -1,
+ security_level: MetricsSecurityLevel::SECURITY_LEVEL_UNSPECIFIED,
+ };
+
+ let mut key_creation_with_purpose_and_modes_info = KeyCreationWithPurposeAndModesInfo {
+ algorithm: MetricsAlgorithm::ALGORITHM_UNSPECIFIED,
+ // Default for i32 is 0 (for the remaining bitmap fields).
+ ..Default::default()
+ };
+
+ if let Err(ref e) = result {
+ key_creation_with_general_info.error_code = get_error_code(e);
+ }
+
+ key_creation_with_auth_info.security_level = process_security_level(sec_level);
+
+ for key_param in key_params.iter().map(KsKeyParamValue::from) {
+ match key_param {
+ KsKeyParamValue::Algorithm(a) => {
+ let algorithm = match a {
+ Algorithm::RSA => MetricsAlgorithm::RSA,
+ Algorithm::EC => MetricsAlgorithm::EC,
+ Algorithm::AES => MetricsAlgorithm::AES,
+ Algorithm::TRIPLE_DES => MetricsAlgorithm::TRIPLE_DES,
+ Algorithm::HMAC => MetricsAlgorithm::HMAC,
+ _ => MetricsAlgorithm::ALGORITHM_UNSPECIFIED,
+ };
+ key_creation_with_general_info.algorithm = algorithm;
+ key_creation_with_purpose_and_modes_info.algorithm = algorithm;
+ }
+ KsKeyParamValue::KeySize(s) => {
+ key_creation_with_general_info.key_size = s;
+ }
+ KsKeyParamValue::KeyOrigin(o) => {
+ key_creation_with_general_info.key_origin = match o {
+ KeyOrigin::GENERATED => MetricsKeyOrigin::GENERATED,
+ KeyOrigin::DERIVED => MetricsKeyOrigin::DERIVED,
+ KeyOrigin::IMPORTED => MetricsKeyOrigin::IMPORTED,
+ KeyOrigin::RESERVED => MetricsKeyOrigin::RESERVED,
+ KeyOrigin::SECURELY_IMPORTED => MetricsKeyOrigin::SECURELY_IMPORTED,
+ _ => MetricsKeyOrigin::ORIGIN_UNSPECIFIED,
+ }
+ }
+ KsKeyParamValue::HardwareAuthenticatorType(a) => {
+ key_creation_with_auth_info.user_auth_type = match a {
+ HardwareAuthenticatorType::NONE => MetricsHardwareAuthenticatorType::NONE,
+ HardwareAuthenticatorType::PASSWORD => {
+ MetricsHardwareAuthenticatorType::PASSWORD
+ }
+ HardwareAuthenticatorType::FINGERPRINT => {
+ MetricsHardwareAuthenticatorType::FINGERPRINT
+ }
+ HardwareAuthenticatorType::ANY => MetricsHardwareAuthenticatorType::ANY,
+ _ => MetricsHardwareAuthenticatorType::AUTH_TYPE_UNSPECIFIED,
+ }
+ }
+ KsKeyParamValue::AuthTimeout(t) => {
+ key_creation_with_auth_info.log10_auth_key_timeout_seconds =
+ f32::log10(t as f32) as i32;
+ }
+ KsKeyParamValue::PaddingMode(p) => {
+ compute_padding_mode_bitmap(
+ &mut key_creation_with_purpose_and_modes_info.padding_mode_bitmap,
+ p,
+ );
+ }
+ KsKeyParamValue::Digest(d) => {
+ // key_creation_with_purpose_and_modes_info.digest_bitmap =
+ compute_digest_bitmap(
+ &mut key_creation_with_purpose_and_modes_info.digest_bitmap,
+ d,
+ );
+ }
+ KsKeyParamValue::BlockMode(b) => {
+ compute_block_mode_bitmap(
+ &mut key_creation_with_purpose_and_modes_info.block_mode_bitmap,
+ b,
+ );
+ }
+ KsKeyParamValue::KeyPurpose(k) => {
+ compute_purpose_bitmap(
+ &mut key_creation_with_purpose_and_modes_info.purpose_bitmap,
+ k,
+ );
+ }
+ KsKeyParamValue::EcCurve(e) => {
+ key_creation_with_general_info.ec_curve = match e {
+ EcCurve::P_224 => MetricsEcCurve::P_224,
+ EcCurve::P_256 => MetricsEcCurve::P_256,
+ EcCurve::P_384 => MetricsEcCurve::P_384,
+ EcCurve::P_521 => MetricsEcCurve::P_521,
+ _ => MetricsEcCurve::EC_CURVE_UNSPECIFIED,
+ }
+ }
+ KsKeyParamValue::AttestationChallenge(_) => {
+ key_creation_with_general_info.attestation_requested = true;
+ }
+ _ => {}
+ }
+ }
+ if key_creation_with_general_info.algorithm == MetricsAlgorithm::EC {
+ // Do not record key sizes if Algorithm = EC, in order to reduce cardinality.
+ key_creation_with_general_info.key_size = -1;
+ }
+
+ (
+ KeystoreAtomPayload::KeyCreationWithGeneralInfo(key_creation_with_general_info),
+ KeystoreAtomPayload::KeyCreationWithAuthInfo(key_creation_with_auth_info),
+ KeystoreAtomPayload::KeyCreationWithPurposeAndModesInfo(
+ key_creation_with_purpose_and_modes_info,
+ ),
+ )
+}
+
+/// Log key operation events to be sent to statsd.
+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_with_general_info, key_operation_with_purpose_and_modes_info) =
+ process_key_operation_event_stats(
+ sec_level,
+ key_purpose,
+ op_params,
+ op_outcome,
+ key_upgraded,
+ );
+ METRICS_STORE
+ .insert_atom(AtomID::KEY_OPERATION_WITH_GENERAL_INFO, key_operation_with_general_info);
+ METRICS_STORE.insert_atom(
+ AtomID::KEY_OPERATION_WITH_PURPOSE_AND_MODES_INFO,
+ key_operation_with_purpose_and_modes_info,
+ );
+}
+
+// Process the statistics related to key operations and return the two atom objects related to key
+// operations: i) KeyOperationWithGeneralInfo ii) KeyOperationWithPurposeAndModesInfo
+fn process_key_operation_event_stats(
+ sec_level: SecurityLevel,
+ key_purpose: KeyPurpose,
+ op_params: &[KeyParameter],
+ op_outcome: &Outcome,
+ key_upgraded: bool,
+) -> (KeystoreAtomPayload, KeystoreAtomPayload) {
+ let mut key_operation_with_general_info = KeyOperationWithGeneralInfo {
+ outcome: MetricsOutcome::OUTCOME_UNSPECIFIED,
+ error_code: 1,
+ security_level: MetricsSecurityLevel::SECURITY_LEVEL_UNSPECIFIED,
+ // Default for bool is false (for key_upgraded field).
+ ..Default::default()
+ };
+
+ let mut key_operation_with_purpose_and_modes_info = KeyOperationWithPurposeAndModesInfo {
+ purpose: MetricsPurpose::KEY_PURPOSE_UNSPECIFIED,
+ // Default for i32 is 0 (for the remaining bitmap fields).
+ ..Default::default()
+ };
+
+ key_operation_with_general_info.security_level = process_security_level(sec_level);
+
+ key_operation_with_general_info.key_upgraded = key_upgraded;
+
+ key_operation_with_purpose_and_modes_info.purpose = match key_purpose {
+ KeyPurpose::ENCRYPT => MetricsPurpose::ENCRYPT,
+ KeyPurpose::DECRYPT => MetricsPurpose::DECRYPT,
+ KeyPurpose::SIGN => MetricsPurpose::SIGN,
+ KeyPurpose::VERIFY => MetricsPurpose::VERIFY,
+ KeyPurpose::WRAP_KEY => MetricsPurpose::WRAP_KEY,
+ KeyPurpose::AGREE_KEY => MetricsPurpose::AGREE_KEY,
+ KeyPurpose::ATTEST_KEY => MetricsPurpose::ATTEST_KEY,
+ _ => MetricsPurpose::KEY_PURPOSE_UNSPECIFIED,
+ };
+
+ key_operation_with_general_info.outcome = match op_outcome {
+ Outcome::Unknown | Outcome::Dropped => MetricsOutcome::DROPPED,
+ Outcome::Success => MetricsOutcome::SUCCESS,
+ Outcome::Abort => MetricsOutcome::ABORT,
+ Outcome::Pruned => MetricsOutcome::PRUNED,
+ Outcome::ErrorCode(e) => {
+ key_operation_with_general_info.error_code = e.0;
+ MetricsOutcome::ERROR
+ }
+ };
+
+ for key_param in op_params.iter().map(KsKeyParamValue::from) {
+ match key_param {
+ KsKeyParamValue::PaddingMode(p) => {
+ compute_padding_mode_bitmap(
+ &mut key_operation_with_purpose_and_modes_info.padding_mode_bitmap,
+ p,
+ );
+ }
+ KsKeyParamValue::Digest(d) => {
+ compute_digest_bitmap(
+ &mut key_operation_with_purpose_and_modes_info.digest_bitmap,
+ d,
+ );
+ }
+ KsKeyParamValue::BlockMode(b) => {
+ compute_block_mode_bitmap(
+ &mut key_operation_with_purpose_and_modes_info.block_mode_bitmap,
+ b,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ (
+ KeystoreAtomPayload::KeyOperationWithGeneralInfo(key_operation_with_general_info),
+ KeystoreAtomPayload::KeyOperationWithPurposeAndModesInfo(
+ key_operation_with_purpose_and_modes_info,
+ ),
+ )
+}
+
+fn process_security_level(sec_level: SecurityLevel) -> MetricsSecurityLevel {
+ match sec_level {
+ SecurityLevel::SOFTWARE => MetricsSecurityLevel::SECURITY_LEVEL_SOFTWARE,
+ SecurityLevel::TRUSTED_ENVIRONMENT => {
+ MetricsSecurityLevel::SECURITY_LEVEL_TRUSTED_ENVIRONMENT
+ }
+ SecurityLevel::STRONGBOX => MetricsSecurityLevel::SECURITY_LEVEL_STRONGBOX,
+ SecurityLevel::KEYSTORE => MetricsSecurityLevel::SECURITY_LEVEL_KEYSTORE,
+ _ => MetricsSecurityLevel::SECURITY_LEVEL_UNSPECIFIED,
+ }
+}
+
+fn compute_padding_mode_bitmap(padding_mode_bitmap: &mut i32, padding_mode: PaddingMode) {
+ match padding_mode {
+ PaddingMode::NONE => {
+ *padding_mode_bitmap |= 1 << PaddingModeBitPosition::NONE_BIT_POSITION as i32;
+ }
+ PaddingMode::RSA_OAEP => {
+ *padding_mode_bitmap |= 1 << PaddingModeBitPosition::RSA_OAEP_BIT_POS as i32;
+ }
+ PaddingMode::RSA_PSS => {
+ *padding_mode_bitmap |= 1 << PaddingModeBitPosition::RSA_PSS_BIT_POS as i32;
+ }
+ PaddingMode::RSA_PKCS1_1_5_ENCRYPT => {
+ *padding_mode_bitmap |=
+ 1 << PaddingModeBitPosition::RSA_PKCS1_1_5_ENCRYPT_BIT_POS as i32;
+ }
+ PaddingMode::RSA_PKCS1_1_5_SIGN => {
+ *padding_mode_bitmap |= 1 << PaddingModeBitPosition::RSA_PKCS1_1_5_SIGN_BIT_POS as i32;
+ }
+ PaddingMode::PKCS7 => {
+ *padding_mode_bitmap |= 1 << PaddingModeBitPosition::PKCS7_BIT_POS as i32;
+ }
+ _ => {}
+ }
+}
+
+fn compute_digest_bitmap(digest_bitmap: &mut i32, digest: Digest) {
+ match digest {
+ Digest::NONE => {
+ *digest_bitmap |= 1 << DigestBitPosition::NONE_BIT_POSITION as i32;
+ }
+ Digest::MD5 => {
+ *digest_bitmap |= 1 << DigestBitPosition::MD5_BIT_POS as i32;
+ }
+ Digest::SHA1 => {
+ *digest_bitmap |= 1 << DigestBitPosition::SHA_1_BIT_POS as i32;
+ }
+ Digest::SHA_2_224 => {
+ *digest_bitmap |= 1 << DigestBitPosition::SHA_2_224_BIT_POS as i32;
+ }
+ Digest::SHA_2_256 => {
+ *digest_bitmap |= 1 << DigestBitPosition::SHA_2_256_BIT_POS as i32;
+ }
+ Digest::SHA_2_384 => {
+ *digest_bitmap |= 1 << DigestBitPosition::SHA_2_384_BIT_POS as i32;
+ }
+ Digest::SHA_2_512 => {
+ *digest_bitmap |= 1 << DigestBitPosition::SHA_2_512_BIT_POS as i32;
+ }
+ _ => {}
+ }
+}
+
+fn compute_block_mode_bitmap(block_mode_bitmap: &mut i32, block_mode: BlockMode) {
+ match block_mode {
+ BlockMode::ECB => {
+ *block_mode_bitmap |= 1 << BlockModeBitPosition::ECB_BIT_POS as i32;
+ }
+ BlockMode::CBC => {
+ *block_mode_bitmap |= 1 << BlockModeBitPosition::CBC_BIT_POS as i32;
+ }
+ BlockMode::CTR => {
+ *block_mode_bitmap |= 1 << BlockModeBitPosition::CTR_BIT_POS as i32;
+ }
+ BlockMode::GCM => {
+ *block_mode_bitmap |= 1 << BlockModeBitPosition::GCM_BIT_POS as i32;
+ }
+ _ => {}
+ }
+}
+
+fn compute_purpose_bitmap(purpose_bitmap: &mut i32, purpose: KeyPurpose) {
+ match purpose {
+ KeyPurpose::ENCRYPT => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::ENCRYPT_BIT_POS as i32;
+ }
+ KeyPurpose::DECRYPT => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::DECRYPT_BIT_POS as i32;
+ }
+ KeyPurpose::SIGN => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::SIGN_BIT_POS as i32;
+ }
+ KeyPurpose::VERIFY => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::VERIFY_BIT_POS as i32;
+ }
+ KeyPurpose::WRAP_KEY => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::WRAP_KEY_BIT_POS as i32;
+ }
+ KeyPurpose::AGREE_KEY => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::AGREE_KEY_BIT_POS as i32;
+ }
+ KeyPurpose::ATTEST_KEY => {
+ *purpose_bitmap |= 1 << KeyPurposeBitPosition::ATTEST_KEY_BIT_POS as i32;
+ }
+ _ => {}
+ }
+}
+
+fn pull_storage_stats() -> Result<Vec<KeystoreAtom>> {
+ let mut atom_vec: Vec<KeystoreAtom> = Vec::new();
+ let mut append = |stat| {
+ match stat {
+ Ok(s) => atom_vec.push(KeystoreAtom {
+ payload: KeystoreAtomPayload::StorageStats(s),
+ ..Default::default()
+ }),
+ 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(MetricsStorage::DATABASE));
+ append(db.get_storage_stat(MetricsStorage::KEY_ENTRY));
+ append(db.get_storage_stat(MetricsStorage::KEY_ENTRY_ID_INDEX));
+ append(db.get_storage_stat(MetricsStorage::KEY_ENTRY_DOMAIN_NAMESPACE_INDEX));
+ append(db.get_storage_stat(MetricsStorage::BLOB_ENTRY));
+ append(db.get_storage_stat(MetricsStorage::BLOB_ENTRY_KEY_ENTRY_ID_INDEX));
+ append(db.get_storage_stat(MetricsStorage::KEY_PARAMETER));
+ append(db.get_storage_stat(MetricsStorage::KEY_PARAMETER_KEY_ENTRY_ID_INDEX));
+ append(db.get_storage_stat(MetricsStorage::KEY_METADATA));
+ append(db.get_storage_stat(MetricsStorage::KEY_METADATA_KEY_ENTRY_ID_INDEX));
+ append(db.get_storage_stat(MetricsStorage::GRANT));
+ append(db.get_storage_stat(MetricsStorage::AUTH_TOKEN));
+ append(db.get_storage_stat(MetricsStorage::BLOB_METADATA));
+ append(db.get_storage_stat(MetricsStorage::BLOB_METADATA_BLOB_ENTRY_ID_INDEX));
+ });
+ Ok(atom_vec)
+}
+
+/// 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)]
+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)]
+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,
+}
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 1d595b3..7e08f4e 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -127,7 +127,7 @@
use crate::enforcements::AuthInfo;
use crate::error::{map_err_with, map_km_error, map_or_log_err, Error, ErrorCode, ResponseCode};
-use crate::metrics::log_key_operation_event_stats;
+use crate::metrics_store::log_key_operation_event_stats;
use crate::utils::watchdog as wd;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
IKeyMintOperation::IKeyMintOperation, KeyParameter::KeyParameter, KeyPurpose::KeyPurpose,
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index e7999bc..8343a29 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -315,6 +315,8 @@
EarlyBootEnded = 0x800, selinux name: early_boot_ended;
/// Checked when IKeystoreMaintenance::onDeviceOffBody is called.
ReportOffBody = 0x1000, selinux name: report_off_body;
+ /// Checked when IkeystoreMetrics::pullMetris is called.
+ PullMetrics = 0x2000, selinux name: pull_metrics;
}
);
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 2fddc18..b66c778 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -23,7 +23,7 @@
use crate::globals::{DB, ENFORCEMENTS, LEGACY_MIGRATOR, SUPER_KEY};
use crate::key_parameter::KeyParameter as KsKeyParam;
use crate::key_parameter::KeyParameterValue as KsKeyParamValue;
-use crate::metrics::log_key_creation_event_stats;
+use crate::metrics_store::log_key_creation_event_stats;
use crate::remote_provisioning::RemProvState;
use crate::super_key::{KeyBlob, SuperKeyManager};
use crate::utils::{